LINUX.ORG.RU

emacs http-client изменить User-Agent

 ,


0

1

Всем привет! Подскажите как изменить User-Agent в загаловках запроса, вобщем делаю так:

...
(defun http-request (url handler)
  (let ((url-request-method "GET")
	(url-request-extra-headers '(("Content-Type" . "text/xml")
				     ("User-Agent" . "Bot312"))))
    (url-retrieve url 'callback-response '(handler))))


(http-request "http://example.com/?hello=world" 'handler)
...

Получаю:

GET /?hello=world HTTP/1.1
MIME-Version: 1.0
Connection: close
Extension: Security/Digest Security/SSL
Host: example.com
Accept-encoding: gzip
Accept: */*
User-Agent: URL/Emacs
Content-Type: text/xml
User-Agent: Bot312

Как видно заголовок дублируется



Последнее исправление: cetjs2 (всего исправлений: 1)
Ответ на: комментарий от Zubok

А как правильно использовать эту опцию? Видимо нужно с 'paranoid :), но я все попробовал безрезультатно, может нужно с глобальным связыванием не через лет указывать?

domik_v_derevne
() автор топика
Ответ на: комментарий от domik_v_derevne

Через let не получилось, наверное, потому что сам зарос выполнялся асинхронно, поэтому установка не действовала.

Function: url-retrieve url callback &optional cbargs silent 
no-cookies

    This function retrieves url asynchronously, calling the 
                                ^^^^^^^^^^^^^^
function callback when the object has been completely retrieved. 
The return value is the buffer into which the data will be 
inserted, or nil if the process has already completed. 

Есть url-retrieve-synchronously, но она может по тем или иным причина не подойти.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от domik_v_derevne

Ясно, Понятно!

Хотя, может быть, и нет. Ведь url-request-extra-headers добавились. Надо будет попробовать, но попозже.

Zubok ★★★★★
()
Ответ на: комментарий от domik_v_derevne

но я все попробовал безрезультатно, может нужно с глобальным связыванием не через лет указывать?

У меня получилось через let. Проверь синтаксис. Я убрал extra-headers для чистоты эксперимента и попробовал два запроса:

(let ((url-request-method "GET")
      (url-privacy-level '(agent)))
  (url-retrieve ...))

и

(let ((url-request-method "GET"))
  (url-retrieve ...))

В первом случае агент не шлется, а во втором уходит URL/Emacs.

Zubok ★★★★★
()
Ответ на: комментарий от Bad_ptr

Да вроде не нужно, так как вся цепочка построения запросов с использованием этих переменных выполняется в url-retrieve. То есть динамический биндинг должен работать.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

До этого в let у меня еще была прописана строчка url-proxy-services для отладки запросов там у меня висел burp, но потом убрал эту строчку и стал слушать через tcpdump

(defun http-request (url handler)
  (let ((url-request-method "GET")
	(url-privacy-level '(agent)))
    (url-retrieve url 'callback-response '(handler))))

(http-request "http://example.com/?hello=world" 'handler)
Ответ:
GET /?hello=world HTTP/1.1
MIME-Version: 1.0
Connection: keep-alive
Extension: Security/Digest Security/SSL
Host: example.com
From: votypka@machine
Accept-encoding: gzip
Accept: */*
User-Agent: URL/Emacs
Агент шлется по дефолту, хотя при setq, работает :)

domik_v_derevne
() автор топика
Ответ на: комментарий от domik_v_derevne

Хм, интересно. Я тут еще разик повнимательнее попробовал и обнаружил, что если шлем запрос через https (например, https://www.whatismybrowser.com/what-is-my-user-agent), то '(agent) в let срабатывает и сервер не может определить user agent. Без '(agent) определят URL/Emacs. То есть как и должно быть. Если же переходим на http, то '(agent) в let не срабатывает. Действительно так. Также не работает выключение user agent через lexical-let.

Далее я пробую с url-retrieve-syncronously и http. А вот тут-то через (let...) все прекрасно работает. Значит, скорее всего, мое первое предположение было верно. Думаю, надо в исходный код заглянуть. Все-таки я считаю, что глобально url-privacy-level щелкать не комильфо. Или надо возвращать в прежнее значение после запроса, потому что эта переменная так и останется навсегда в выставленном значении, пока кто-то другой ее не поменяет. В общем, гляну исходный код.

Zubok ★★★★★
()
Ответ на: комментарий от domik_v_derevne

В общем, разобрался. Да, проблема в асинхронности. Когда выполняется асинхронный запрос, то функция url-retrieve вызывает функцию url-http, где при помощи стандартной set-process-sentinel привязывает функцию url-http-async-sentinel, которая вызывается, когда процесс, привязанный к временному буферу, где формируется запрос, изменяет свое состояние, и эта функция, получается, вызывается уже не из url-http. Таким образом, процесс формирования заголовка выполняется уже не url-retrieve, а в функции, которая привязана к процессу, и эта функция находится вне зоны действия let, которая влияет только на то, что вызывается напрямую из url-retrieve.

В синхронном случае все происходит в одной функции.

Вообще, мне кажется, что заголовки надо заранее готовить, а потом уже запускать процесс. Тогда бы все работало.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Благодарю за развернутый расклад, все-же я немного запутался

функция находится вне зоны действия let, которая влияет только на то, что вызывается напрямую из url-retrieve

Почему тогда у тебя при let связывании (url-privacy-level '(agent)) работает как нужно, т.е. не отправляет дефолтный агент, а у меня отправляет?

domik_v_derevne
() автор топика
Ответ на: комментарий от Zubok

У меня еще вот такой код нормально сработал:

(defun http-request (url handler)
  (let* ((url-request-method "GET")
	 (url-privacy-level 'paranoid))
    (url-retrieve url 'callback-response '(handler))))

(http-request "http://example.com/?hello=world" 'handler)
Заголовки:
GET /?hello=world HTTP/1.1
MIME-Version: 1.0
Connection: keep-alive
Extension: Security/Digest Security/SSL
Host: example.com
From: votypka@machine
Accept-encoding: gzip
Accept: */*

domik_v_derevne
() автор топика
Ответ на: комментарий от domik_v_derevne

Почему тогда у тебя при let связывании (url-privacy-level '(agent)) работает как нужно

Сработало тогда только https, на самом деле. Я плохо поставил эксперимент. А через http не сработало.

У меня еще вот такой код нормально сработал:

У меня такой код не сработал на http и сработал на https. Я попробовал и example.com, и другие адреса. У меня версия здесь - гонки. В одном случае будет работать, а в другом не будет. Причем еще интересные эффекты возникают, если несколько одинаковых запросов друг за другом сделать: иногда срабатывает '(agent) и 'paranoid. Кусок исходного кода намекает на это:

	(let ((status (process-status connection)))
	  (cond
	   ((eq status 'connect)
	    ;; Asynchronous connection
	    (set-process-sentinel connection 'url-http-async-sentinel))
	   ((eq status 'failed)
	    ;; Asynchronous connection failed
	    (error "Could not create connection to %s:%d" host port))
	   (t
	    (set-process-sentinel connection 'url-http-end-of-document-sentinel)
	    (process-send-string connection (url-http-create-request)))))))

Как видно, в зависимости от статуса connection (статусы можно посмотреть в C-h f process-status) формирование заголовков (функция url-http-create-request) происходит либо в url-http-async-sentinel в случае статуса 'connect, которая вызывается не из url-retrieve, либо же формирование заголовков здесь же (самый последний вариант cond в коде, когда, например, status уже 'open).

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 2)
Ответ на: комментарий от Zubok

Понятно.
Вобщем решил всетаки использовать url-retrieve-synchronously вместо url-retrieve, в принципе моя программа не нуждается в асинхронных запросах, я просто подумал что здесь использование оных является хорошим стилем, ну типа как в node.js.
Еще раз Спасибо за поддержку, мистер Кредо )

domik_v_derevne
() автор топика
Ответ на: комментарий от domik_v_derevne

Да нет, ничего плохого в асинхронном стиле нет. Emacs однотредный пока, поэтому если у тебя запрос-ответ занимает много времени, то Emacs висит в ожидании ответа, а если запросы короткие, то ничего страшного.

Хорошо, что вскрылось такое поведение. Надо будет подумать. Может, патч заслать. Вроде патч простой. Запишу себе в TODO, гляну позже.

Zubok ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.