How can i connect to a server through a http proxy server in delphi?
What about SOCKS5 proxy?
Google doesn't have any suggestion!
If you're using Indy (highly recommended), then try using a TIdConnectThroughHttpProxy object from the IdConnectThroughHttpProxy unit. It's a descendant of TIdIOHandler, so connect an instance of that class to your client object's IOHandler property. To connect through a Socks server instead, use TIdSocksInfo, in IdSocks.
If you're set on doing it manually, without the aid of a protocol library like Indy, then connect your TTcpClient object to the proxy server's address instead of the real destination, and then send your commands there. The proxy server knows where to send the request either because you issue a CONNECT command to it, or because you specify a full URL (instead of just the path portion) in the GET request. (The HTTP spec demonstrates the latter.) The response you'll get should be forwarded from the destination server, unless the proxy server has an error itself.
I think you can do it using Indy. You may find information in the Indy in Depth ebook.
Hope this helps.
Related
I'm thinking of writing a Proxy Server. When I specify and activate the port using the TIdHTTPProxyServer component, the proxy server works properly. It's okay so far, but I can't password it and I can't open an IPv6 proxy. It's just an IPv4 proxy. I couldn't find much documentation on this.
I can't password it
TIdHTTPProxyServer does not currently implement any authentication of its own.
HTTP authentication between the client and target server is handled transparently between the two of them, TIdHTTPProxyServer is not involved in that process.
If you want to password-protect the proxy itself, you will have to manually handle authentication in the proxy's OnHTTPBeforeCommand event. Check the client's request headers (in the event's AContext.Headers property) for a Proxy-Authorization header, and if it is not present, or its credentials fail, then manually send the client (via the AContext.Connection property) an HTTP 407 response containing an appropriate Proxy-Authenticate header, and then raise an exception (or disconnect the AContext.Connection) to stop processing the current proxy request.
I can't open an IPv6 proxy. It's just an IPv4 proxy.
TIdHTTPProxyServer can handle both IPv4 and IPv6, but it will require some manual setup.
Whichever IP version Indy is compiled for by default is specified in the global ID_DEFAULT_IP_VERSION constant in Indy's IdGlobal unit (it is set to IPv4, unless Indy is compiled with IdIPv6 defined in IdCompilerDefines.inc).
Listening IP/port pairs can be configured in the proxy's Bindings collection. You can specify an IPVersion for each binding. The IPVersion is set to ID_DEFAULT_IP_VERSION by default.
If you don't specify any Bindings entries, the proxy's DefaultPort property is used instead. The proxy will then open either 1 or 2 listening ports, depending on platform and OS capabilities. If 1 port is opened, it will use ID_DEFAULT_IP_VERSION. If 2 ports are opened, 1 will be IPv4 and 1 will be IPv6.
So, if you want control over the setup of the listening IP/ports, don't leave the Bindings empty.
Once a client has connected to a listening port, the TIdHTTPProxyServerContext.OutboundClient object that is used to connect to the next HTTP server will use ID_DEFAULT_IP_VERSION by default. You can override this in the proxy's OnHTTPBeforeCommand event, by casting the event's AContext.OutboundClient property to TIdTCPClient and then setting its IPVersion property.
Previously the URL I needed to check was http and I used TidTCPClient to emulate the http protocol to determine the file at the web server existed. Now they have switched to https and I don't know how to do it.
Can I use TIdHTTP with the TIdSSLIOHandlerSocketOpenSSL hander, and then some Indy function to only determine the resource exists? I have OpenSSL installed.
Your existing TIdTCPClient code should continue to work if you simply assign a TIdSSLIOHandlerSocketOpenSSL to the client's IOHandler, change the client's Port to 443, and set the IOHandler's PassThrough to False. HTTPS is just HTTP over an SSL/TLS connection, it doesn't change HTTP itself.
But to answer your question, yes, you can switch to TIdHTTP if you want to. You can use the HTTP HEAD command (the TIdHTTP.Head() method) to check if a URL is valid without having to download a full resource.
Our Delphi application is trying to connect to our website via IdFTP on a client machine using a proxy server, and I always get a 'read timed out' message. I don't know how to fix it.
My code:
IdFTP1.Host :=Website_address;
IdFTP1.Username :=Website_user;
IdFTP1.Password :=Website_password;
IdFTP1.TransferType:=ftBinary;
IdFTP1.ProxySettings.ProxyType:=fpcmNone;
IdFTP1.ProxySettings.Host :=Proxy_server;
IdFTP1.ProxySettings.Port :=Proxy_port;
IdFTP1.ProxySettings.Username :=Proxy_username;
IdFTP1.ProxySettings.Password :=Proxy_password;
IdFTP1.Connect;
...which returns a 'read timed out' exception.
Having looked on the web for possible solutions, I have tried various combinations of the following with no joy (although there might be a combination that might work, I just don't really know what I'm doing):
IdFTP1.IOHandler :=TIdSSLIOHandlerSocketOpenSSL.Create
(IdFTP1);
IdFTP1.UseTLS :=utUseExplicitTLS;
IdFTP1.NATKeepAlive.UseKeepAlive:=True;
IdFTP1.NATKeepAlive.IdleTimeMS :=100000;
IdFTP1.DataPortProtection :=ftpdpsPrivate;
The frustrating thing is I can't test it on my machine, I have to compile a new version of the application, copy it to their machine, and then see if it works.
There is nothing complex about the installation on the client side as far as I can tell. They have given me the proxy host address, and the proxy username and password are blank.
Other bits of the application connect to the same website via HTTP and the proxy server, and this works perfectly. So my logic is that it can't be firewalls or anything like that.
IdHTTP1.HandleRedirects :=True;
IdHTTP1.ProxyParams.BasicAuthentication:=True;
IdHTTP1.ProxyParams.ProxyServer :=Proxy_server;
IdHTTP1.ProxyParams.ProxyPort :=Proxy_port;
IdHTTP1.ProxyParams.ProxyUsername :=Proxy_username;
IdHTTP1.ProxyParams.ProxyPassword :=Proxy_password;
I am using Delphi XE8.
They have created a virtual server for our testing, it runs Windows 7 64 bit.
Update
Remy, is this the right idea? One problem I am having is the TIdConnectThroughHttpProxy component, what must be in the uses clause for this? Delphi is not recognizing it.
var
TempIO : TIdIOHandlerStack;
TempProxy : TIdConnectThroughHttpProxy;
......
TempIO :=TIdIOHandlerStack.Create;
TempProxy :=TIdConnectThroughHttpProxy.Create;
TempProxy.Host :=Proxy_host;
TempIO.TransparentProxy:=TempProxy;
IdFTP1.IOHandler :=TempIO;
IdFTP1.Connect;
Update 2
A point of clarity: the HTTP request that is successfully reaching the web server through the proxy server goes to a different web address than the FTP request. In other words, they both go through the same proxy server, but the destination addresses are different. Just in case this is of use.
I have now tried using Fiddler to find the problem, not sure if this is a great idea? My understanding is is that Fiddler acts as a proxy server, so I thought I would see if I encountered the same problem. Sure enough, can't connect.
To be clear about my steps:
Run Fiddler, and check the box that says 'Capture FTP requests'.
Update my IdHTTP component:
IdHTTP1.ProxyParams.ProxyServer:='127.0.0.1';
IdHTTP1.ProxyParams.ProxyPort :=Fiddler port;
Update my IdFTP component:
IdFTP1.ProxySettings.Host:='127.0.0.1';
IdFTP1.ProxySettings.Port:=Fiddler port;
So now I have removed the client setup completely, I am mirroring the problem from my local machine using Fiddler as far as I can tell. If I don't use Fiddler, everything works great. If I use Fiddler as described above, then the HTTP request works correctly, but the FTP request can't connect.
Any ideas as to what I can do to try and solve this? I'm sure it is something really stupid that I'm doing wrong.
IdFTP1.ProxySettings.ProxyType:=fpcmNone
This tells TIdFTP not to communicate with an FTP-aware proxy. If you want to use the TIdFTP.ProxySettings properties, you need to set the ProxyType so TIdFTP.Connect() will connect to the ProxySettings.Host and TIdFTP.Login() will know what kind of commands it needs to send to login to the proxy and request a connection to the next host.
Note that TIdFTP.ProxySettings only works with FTP proxies. If you need to connect to a different type of proxy, before you call TIdFTP.Connect() you will have to assign a TIdIOHandler-derived component to the TIdFTP.IOHandler property, and then assign a TIdCustomTransparentProxy-derived component to the TIdIOHandler.TransparentProxy property. To connect to an HTTP proxy (which it sounds like you need, since that is what TIdHTTP.ProxyParams works with), use TIdConnectThroughHttpProxy. To connect to a SOCKS proxy, use TIdSocksInfo.
I am not good with delphi yet, but based on some examples I have managed to create simple http server with no more than 10 users.
There are 2 main problems I don't know how to solve yet.
proper way to authenticate, manage users - sessions
main problem, connection must be secure, so SSL encryption is needed, how to implement it?
Any example I found in relation with idhttpserver and openssl, was not quite complete or with older version of Indy.
I am currently working with Delphi XE2 with Indy 10 components.
proper way to authenticate, manage users - sessions
TIdHTTPServer manages HTTP sessions for you if you set the TIdHTTPServer.SessionState property is true (it is false by default). TIdHTTPServer uses cookies for session management, so your clients need to have cookies enabled.
Authentication has to be performed manually, but how you do that depends on whether your clients are using HTTP-based or HTML-based authentication.
For HTTP authentication, there are ARequestInfo.UserName and ARequestInfo.Password properties available. If not valid, send an appropriate 401 response back to the client (if you set the AResponseInfo.AuthRealm property to a non-blank string, TIdHTTPServer will send a 401 response for you). By default, TIdHTTPServer only supports BASIC authentication. If you want to support other authentication schemes, you will have to use the TIdHTTPServer.OnParseAuthentication event, and send the 401 reply manually so you can send back appropriate WWW-Authenticate headers. Either way, if the client is validated, you can use HTTP sessions to keep the client logged in between requests. The AResponseInfo.Session and AResponseInfo.Session properties point at the current session. If TIdHTTPServer.AutoStartSession is true (it is false by default), TIdHTTPServer creates new sessions automatically. Otherwise, you can call TIdHTTPServer.CreateSession() yourself when needed. TIdHTTPSession has a Content property that you can store session-specific data in. Or you can derive a new class from TIdHTTPSession and then use the TIdHTTPServer.OnCreateSession event to create instances of that class.
For HTML authentication, you have two choices, depending on how you configure your HTML:
if your HTML <form> tag does not have an enctype attribute, or it is set to application/x-www-webform-urlencoded, TIdHTTPServer will store the raw webform data in the ARequestInfo.FormParams property, and if TIdHTTPServer.ParseParams is true (which it is by default), the data will also be parsed into the ARequestInfo.Params property for you.
if your HTML <form> tag has an enctype attribute set to multipart/form-data, you will have to parse the content of the ARequestInfo.PostStream manually, as TIdHTTPServer does not yet parse that data for you (examples have been posted many times before on many different forums on how to parse that data manually using Indy's TIdMessageDecoderMIME class). By default, ARequestInfo.PostStream points at a TMemoryStream object. You can use the TIdHTTPServer.OnCreatePostStream event to create an instance of a different TStream-derived class, if desired.
main problem, connection must be secure, so SSL encryption is needed, how to implement it?
Before activating the server:
assign a TIdServerIOHandlerSSLBase-derived component, such as TIdServerIOHandlerSSLOpenSSL, to the TIdHTTPServer.IOHandler property and configure it as needed (certificate, peer validation, SSL version(s), etc). In the case of OpenSSL, you will have to deploy the 2 OpenSSL library binaries libeay32.dll and ssleay32.dll (or non-Windows platform equivalents) with your app if they are not already pre-installed on the target OS, or if you want to ensure your app uses a specific version of OpenSSL. At this time, OpenSSL is the only encryption that Indy supports natively, but there are third-party solutions available that are compatible with Indy, such as EldoS SecureBlackbox.
fill in the TIdHTTPServer.Binding property with a binding for your desired HTTPS port (443 is the default HTTPS port). Typically you should create 2 bindings, one for HTTP port 80 and one for HTTPS port 443. Inside your OnCommand... handlers, if you receive a request that requires SSL/TLS encryption, you can check the port that the request was made on (AContext.Binding.Port) and if not HTTPS then redirect (AResponseInfo.Redirect()) the client to retry the request on the HTTPS port.
assign a handler to the TIdHTTPServer.OnQuerySSLPort event and have it set its VUseSSL parameter to True when its APort parameter matches your HTTPS port. UPDATE starting with SVN rev 5461, an OnQuerySSLPort handler is no longer needed if your only HTTPS port is 443.
I'm trying to get the post data from TIdHTTPProxyServer, using OnHTTPBeforeCommand or OnHTTPDocument events but all is useless.
How can I do that?
BTW, I'm using Indy 10, but other solutions (with synapse, for example) will be cool.
Thanks in advance.
POST data is not available in the OnHTTPBeforeCommand event, as it has not been read from the socket yet. Only the HTTP headers are available in that event.
POST data is available in the OnHTTPDocument event, but only under the following conditions:
the POST request uses a non-zero Content-Length header (as TIdHTTPProxyServer does not yet support the Transfer-Encoding header to handle compressed/chunked HTTP messages).
the TIdHTTPProxyServerContext.TransferMode property is tmFullDocument when the OnHTTPBeforeCommand event exits. By default, the TransferMode is set to the same value as the TIdHTTPProxyServer.DefaultTransferMode property, which is tmFullDocument by default.
the client sends the POST request directly to TIdHTTPProxyServer, specifying a full URL as the target. If the client instead sends a CONNECT request directly to TIdHTTPProxyServer to establish a tunnel to the target server and then sends the POST request through the tunnel to the target server (for instance, when establishing SSL sessions for HTTPS requests), TIdHTTPProxyServer does not expose access to that data. It is a straight pass-through from one socket to another.