POST с Indy + SSL + Proxy - PullRequest
       45

POST с Indy + SSL + Proxy

1 голос
/ 10 июля 2020

Я пытаюсь выполнить POST-запрос через прокси с использованием https. Код выглядит так:

  FHttp := TIdHttp.Create(nil);

  FHttp.ProxyParams.ProxyServer := Host;
  FHttp.ProxyParams.ProxyPort := Port;
  FHttp.ProxyParams.ProxyUsername := User;
  FHttp.ProxyParams.ProxyPassword := Password;

  FHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  FHandler.SSLOptions.Method := sslvTLSv1_2;
  FHandler.PassThrough := true;
  FHttp.IOHandler := FHandler;
  FHttp.HandleRedirects := true;
  FHttp.Request.ContentType := 'application/x-www-form-urlencoded';
  FHttp.Request.Connection := 'keep-alive';
  FHttp.Request.ProxyConnection := 'keep-alive';
...

  FParams.Add('username=user');
  FParams.Add('password=pwd');
  FHttp.Post('https://my.service/login', FParams);

Прокси-сервер - Squid.

Код генерирует ошибку «Ошибка сокета # 10054 Сброс соединения одноранговым узлом».

Теперь самое интересное. :

  1. Если вообще не использовать прокси (т.е. не устанавливать параметры FHttp.ProxyParams) - все в порядке.
  2. Если не заданы какие-либо параметры POST (т.е. пустые FParams), но все же через прокси - все в порядке.
  3. Самый странный: если я отлаживаю код Indy пошагово (метод TIdCustomHTTP.DoRequest) - все в порядке с примером выше (прокси настройки + параметры).

Параметры POST не отправляются должным образом по какой-то причине?

И почему происходит шаг 3?

Indy обновлен, просто вытащен из репозитория

ОБНОВЛЕНИЕ

После перехвата вызовов TIdHTTP (спасибо Remy ) ясности немного больше. ( журнал сбоев , рабочий журнал ).

Краткая версия: при отладке Indy выполняет 3 запроса CONNECT + POST + DISCONNECT (поскольку в службе есть перенаправление Я верю), и это работает.

При запуске теста без отладки - CONNECT + DISCONNECT + POST - и он явно терпит неудачу (т.е. POST выполняется без CONNECT впереди). Подробнее см. Прикрепленные файлы журнала.

1 Ответ

2 голосов
/ 14 июля 2020

Вы обнаружили несколько c ошибок в TIdHTTP, которые необходимо исправить. Я открыл для этого новую заявку:

# 315: Ошибки в обработке прокси TIdHTTP

Вот что я вижу в вашем «неудачном» сценарии:

TIdHTTP подключается к прокси, отправляет запрос CONNECT, который успешно подключается к my.service.com:443, а затем отправляет POST запрос (с использованием HTTP 1.0, а не HTTP 1.1 a ).

a) для отправки запроса POST с HTTP 1.1 необходимо установить для свойства TIdHTTP.ProtocolVersion значение pv1_1, И включите флаг hoKeepOrigProtocol в свойстве TIdHTTP.HTTPOptions. В противном случае TIdHTTP.Post() принудительно устанавливает ProtocolVersion на pv1_0.

HTTP-сервер отвечает перенаправлением ответа 302 Found на другой URL-адрес, включая заголовок Keep-Alive, указывающий, что сервер будет закройте соединение, если новый запрос не будет отправлен в течение следующих 5 секунд.

Когда TIdHTTP завершит обработку ответа POST, он знает, что он собирается повторно отправить тот же запрос новому URL. На следующей итерации l oop он видит, что целевой сервер тот же, а прокси-сервер все еще подключен, поэтому соединение не закрывается, а код, который отправил бы новый запрос CONNECT, пропускается.

Непосредственно перед отправкой запроса POST проверяется свойство Response.KeepAlive, чтобы узнать, закрывать ли соединение сокета в любом случае. Получатель свойства KeepAlive видит, что свойство ProtocolVersion равно pv1_0 и что в ответе нет заголовка Proxy-Connection: keep-alive (даже если есть заголовок Connection: keep-alive), поэтому он возвращает False, а затем сокет соединение закрыто.

TIdHTTP затем снова подключается к прокси, но не отправляет новый запрос CONNECT до отправки запроса POST. Прокси-сервер не знает, что делать с POST, поэтому он не выполняет запрос с ответом 400 Bad Request.

Вот что я вижу в вашем «рабочем» сценарии:

Все то же, что и выше, до момента, когда обрабатывается 1-й запрос POST. Затем возникает задержка примерно в 16 секунд (вероятно, поскольку вы выполняете код) - больше, чем позволяет задержка в 5 секунд Keep-Alive, поэтому HTTP-сервер закрывает свое соединение с прокси-сервером, который затем закрывает свое соединение с * 1059. *.

К тому времени, когда TIdHTTP готов отправить 2-й запрос POST, он знает, что был отключен от прокси, поэтому он повторно подключается к прокси, отправляет новый CONNECT запрос, а затем отправляет запрос POST.

Пока я не смогу исправить ошибки должным образом, попробуйте следующее:

  • включите флаг hoKeepOrigProtocol в свойстве TIdHTTP.HTTPOptions, чтобы разрешить TIdHTTP.Post() использовать HTTP 1.1. Это само по себе может решить проблему с ненужным закрытием соединения перед отправкой 2-го POST запроса на перенаправленный URL.

  • , если это не решит проблему, попробуйте отредактировать IdHTTP.pas самостоятельно и перекомпилируйте Indy, чтобы обновить метод TIdCustomHTTP.ConnectToHost(), чтобы принудительно использовать Disconnect(), если свойство Response.KeepAlive имеет значение False ДО , для локальной LUseConnectVerb переменной установлено значение not Connected в случае где ARequest.UseProxy - это ctSSLProxyctProxy тоже). Таким образом, второй запрос POST отключится от прокси и повторно подключится с новым запросом CONNECT.

...