简体   繁体   English

使用 Indy + SSL + 代理发布

[英]POST with Indy + SSL + Proxy

I'm trying to do a POST request through proxy using https.我正在尝试使用 https 通过代理发出 POST 请求。 Code looks like:代码如下:

  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);

Proxy server is Squid.代理服务器是 Squid。

Code generates error "Socket Error # 10054 Connection reset by peer."代码生成错误“Socket Error # 10054 Connection reset by peer。”

Now, the interesting part comes:现在,有趣的部分来了:

  1. If not using proxy at all (ie not setting FHttp.ProxyParams settings) - everything is OK.如果根本不使用代理(即不设置 FHttp.ProxyParams 设置) - 一切正常。
  2. If not setting any POST parameters (ie empty FParams), but still using proxy - everything is OK.如果没有设置任何 POST 参数(即空 FParams),但仍在使用代理- 一切正常。
  3. The most strange one: If I'm debugging the Indy code step by step (TIdCustomHTTP.DoRequest method) - everything is OK with above example (proxy settings + parameters).最奇怪的一个:如果我正在逐步调试 Indy 代码(TIdCustomHTTP.DoRequest 方法) - 上面的示例一切正常(代理设置 + 参数)。

POST parameters are not sent properly for some reason? POST 参数由于某种原因没有正确发送?

And why step 3 is happening?为什么会发生第 3 步?

Indy is up to date, just pulled from repository Indy 是最新的,刚刚从存储库中提取

UPDATE更新

After intercepting TIdHTTP calls (thanks Remy ) there is a little bit more clarity.拦截 TIdHTTP 调用(感谢Remy )后,清晰度会更高一些。 ( failing log , working log ). 失败日志工作日志)。

Short version: when doing debug, Indy does 3 CONNECT + POST + DISCONNECT requests (because there are redirection on the service I believe) and it works.简短版本:在进行调试时,Indy 会执行 3 个 CONNECT + POST + DISCONNECT 请求(因为我相信服务上有重定向)并且它可以工作。

When running test without debug - CONNECT + DISCONNECT + POST - and it fails obviously (ie POST is executed without CONNECT in front).在没有调试的情况下运行测试时 - CONNECT + DISCONNECT + POST - 它显然失败了(即在前面没有 CONNECT 的情况下执行 POST)。 See attached log files for details.有关详细信息,请参阅附加的日志文件。

You have found some logic bugs in TIdHTTP that need to be fixed.您在TIdHTTP中发现了一些需要修复的逻辑错误。 I have opened a new ticket for that:我为此开了一张新票:

#315: Bugs in TIdHTTP proxy handling #315:TIdHTTP 代理处理中的错误


Here is what I see happening in your "failing" scenario:这是我在您的“失败”场景中看到的情况:

TIdHTTP connects to the proxy, sends a CONNECT request that successfully connects to my.service.com:443 , then sends a POST request (using HTTP 1.0 rather than HTTP 1.1 a ). TIdHTTP连接代理,发送CONNECT请求成功连接到my.service.com:443 ,然后发送POST请求(使用 HTTP 1.0 而不是Z293C9EA246FF9985DC6F62A1650)

a) to send a POST request with HTTP 1.1, you have to set the TIdHTTP.ProtocolVersion property to pv1_1 , AND enable the hoKeepOrigProtocol flag in the TIdHTTP.HTTPOptions property. a) 要使用 HTTP 1.1 发送POST请求,您必须将TIdHTTP.ProtocolVersion属性设置为pv1_1 ,并在TIdHTTP.HTTPOptions属性中启用hoKeepOrigProtocol标志。 Otherwise, TIdHTTP.Post() forces the ProtocolVersion to pv1_0 .否则, TIdHTTP.Post()ProtocolVersion强制为pv1_0

The HTTP server replies with a 302 Found response redirecting to a different URL, including a Keep-Alive header indicating the server will close the connection if a new request is not sent in the next 5 seconds. HTTP 服务器回复302 Found响应重定向到不同的 URL,包括Keep-Alive header,如果在下一个请求中未发送新连接,则表明服务器将关闭。

When TIdHTTP is done processing the POST response, it knows it is going to re-send the same request to a new URL.TIdHTTP完成对POST响应的处理后,它知道它将向新的 URL 重新发送相同的请求。 On the next loop iteration, it sees that the target server is the same, and the proxy is still connected, and so the connection is not closed, and the code that would have sent a new CONNECT request is skipped.在下一次循环迭代中,它看到目标服务器是相同的,并且代理仍然连接,因此连接没有关闭,并且会发送新的CONNECT请求的代码被跳过。

Just before the POST request is sent, the Response.KeepAlive property is checked to know whether or not to close the socket connection anyway.就在发送POST请求之前,会检查Response.KeepAlive属性以确定是否要关闭套接字连接。 The KeepAlive property getter sees the ProtocolVersion property is pv1_0 and that there is no Proxy-Connection: keep-alive header present in the response (even though there is a Connection: keep-alive header), so it returns False, and then the socket connection is closed. KeepAlive属性 getter 看到ProtocolVersion属性是pv1_0并且没有Proxy-Connection: keep-alive header 出现在响应中(即使有一个Connection: keep-alive标头),所以它返回 False,然后是套接字连接关闭。

TIdHTTP then re-connects to the proxy again, but does not send a new CONNECT request before sending the POST request. TIdHTTP然后再次重新连接到代理,但在发送POST请求之前不会发送新的CONNECT请求。 The proxy does not know what to do with the POST , so it fails the request with a 400 Bad Request response.代理不知道如何处理POST ,因此它以400 Bad Request响应使请求失败。


Here is what I see happening in your "working" scenario:这是我在您的“工作”场景中看到的情况:

Everything is the same as above, up to the point where the 1st POST request is processed.一切都与上面相同,直到处理第一个POST请求。 Then there is a delay of roughly 16 seconds (likely since you are stepping through code) - more than the 5-second Keep-Alive delay allows - so the HTTP server closes its connection with the proxy, which then closes its connection to TIdHTTP .然后会有大约 16 秒的延迟(可能是因为您正在单步执行代码) - 超过 5 秒的Keep-Alive延迟允许 - 所以 HTTP 服务器关闭与代理的连接,然后关闭与TIdHTTP的连接。

By the time TIdHTTP is ready to send the 2nd POST request, it knows it has been disconnected from the proxy, so it re-connects to the proxy, sends a new CONNECT request, and then sends the POST request.TIdHTTP准备发送第二个POST请求时,它知道它已经与代理断开连接,所以它重新连接到代理,发送一个新的CONNECT请求,然后发送POST请求。


Until I can fix the bugs properly, try the following:在我可以正确修复错误之前,请尝试以下操作:

  • enable the hoKeepOrigProtocol flag in the TIdHTTP.HTTPOptions property to allow TIdHTTP.Post() to use HTTP 1.1.TIdHTTP.HTTPOptions属性中启用hoKeepOrigProtocol标志以允许TIdHTTP.Post()使用 HTTP 1.1。 That in itself may fix the issue with the connection being closed unnecessarily before sending the 2nd POST request to the redirected URL.这本身可能会解决在将第二个POST请求发送到重定向的 URL 之前不必要地关闭连接的问题。

  • if that doesn't solve the issue, try editing IdHTTP.pas yourself and recompile Indy, to update the TIdCustomHTTP.ConnectToHost() method to force a Disconnect() if the Response.KeepAlive property is False BEFORE the local LUseConnectVerb variable is set to not Connected in the case where ARequest.UseProxy is ctSSLProxy (and ctProxy , too).如果这不能解决问题,请尝试自己编辑IdHTTP.pas并重新编译 Indy,以更新TIdCustomHTTP.ConnectToHost()方法以在本地LUseConnectVerb变量设置为之前Response.KeepAlive属性为 False 时强制Disconnect()ARequest.UseProxyctSSLProxy (和ctProxy也是)的情况下not Connected That way, the 2nd POST request will disconnect from the proxy and re-connect with a new CONNECT request.这样,第二个POST请求将与代理断开连接,并使用新的CONNECT请求重新连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM