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.
Related
Just a simple question:
what is the difference between a request and a command in protocols like HTML or SMTP?
Can it be that requests await a response?
Or that one is from the client side and the other from the server side?
Thanks in advance!
Similar to http, smtp requests can contain multiple commands e.g. the TLS command to enabled encryption
E.g. HELO, BYE
Ftp is similar to Smtp, where a single connection (request) exchanges multiple commands (PASV... EXIT) before the connection is closed.
The main difference is the request response for http can usually be visualized as 1 request to 1 response however when you look at how the TLS encryption is applied over http you then see similar commands being exchanged between client and server before the final response is returned to the client.
In short http separates the noise of the commands by encompassing them into the header portions of the request and response.
An example of http commands without encryption would be chucked transfer encoding where the server send a part of the response after the headers in chunks which must be put back together at the client side.
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 am trying my hand in server applications using Indy Internet tools.
My client sends Post data (XML) in Unicode format.
Can I convey my preference to client (HTTP Client). I prefer Text. In general can a HTTP server send its preferences to its Clients?
Thanks for any hint or help.
The problem with this is the fact, that with only one POST the server has no way to respond, until the client has already sent the data.
The solution is to make two calls: One where the client asks for the server preferences and another to send the data. The OPTIONS HTTP method can be used for this scenario.
You can handle both requests on the same URL: If the clients makes an OPTIONS request the server responds with the configuration data. (via response headers) Then the client can make a POST request on the same URL and the server handles the data appropriately.
For further information see HTTP methods and HTTP headers, especially the Accept header.
I need to program a stateless server to execute remote methods. The client uses REST with a JSON parameter to pass the method name and its parameters. After servicing the result the session is closed. I have to use Indy10, TCP/IP as protocol, and therefore look at using IdHTTPServer.
Large result sets are chunked by Indy10 and sent to the client in parts.
My problem now is:
The methods on the server provide progress information if they take longer to produce the results. These are short messages. How can I write back to the client?
So far I have used writeflush on the server, but the client waited for the request to end before handing back the full resultset, including the progress information. What can I do to display/process such progress information on the client and yet keep the connection open to receive further data on the same request?
On the client side instead of the regular HTTP client component TIdHTTP you can instead use Indy class TIdTCPClientCustom in unit IdTCPClient to send the request and process the response.
This class gives total control over the processing of the server responses. I used the TIdTelnet class as a starting point to implement a client for a message broker messaging protocol, and found it stable and reliable for both text and binary data.
In the receiving thread, the incoming data can be read up to delimiters and parsed into chunks (for the progress information) and immediately processed.
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.