Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Writing data directly to socket from TIdHttp to TIdHttpServer
#2
(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: I want to keep track of user status on client machines and update the service on the server side with this status. For example, if the user is logged in/out of our system, Busy with a task or not and if the PC is locked.

OK, so why not simply have the HTTP client send its updated status to the HTTP server using a standard HTTP POST or PUT command?

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: Now, I want to write directly from TIdHttp client to an TIdHttpServer

Why? That would likely cause you to end up violating the HTTP protocol. Besides, pushes are typically sent from the server to the client, not the other way around.

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: but http servers in indy does not implement the OnExecute event handler like TCP servers do.

Because HTTP uses a command/response model, so TIdHTTPServer exposes events to handle commands sent by clients.

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: We can add a TCP server inside the dll resource itself but I don't want to have 2 connections from the same client just for the sake keeping track of user status. 

HTTP is a stateless protocol, there is no guarantee that multiple commands from the same client will be able to reuse connections, even with HTTP keep-alives enabled. So, you have to be prepared to handle multiple connections, even from the same client.

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: If I put a TCP server in the dll resource, is there a way to redirect the http connection from the client made with the http server (host app) to the TCP server inside the dll?

No.

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: If I didn't use the TCP server inside the dll. Can expose the "OnExecute" event handler from TIdHttpServer?

Technically, yes, but doing so won't help you.

TIdHTTPServer derives from TIdCustomTCPServer, and the TIdCustomTCPServer.OnExecute event is protected. You would have to derive a new class from TIdHTTPServer to gain access to the event.

But even so, the event won't fire at runtime, because TIdHTTPServer overrides the virtual TIdCustomTCPServer.DoExecute() method to do all of its HTTP work, thus bypassing the OnExecute event.

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: I want to be able to use TIdHttp.WriteRFC from the client side and read that on the server side.

First, TIdHTTP does not have a WriteRFC() method. Did you mean the WriteRFCStrings() method?

Second, using WriteRFCString() would absolutely violate the HTTP protocol. WriteRFCStrings() does not send data in a format that HTTP allows. You can't just send random arbitrary data at a connection and expect the receiver to handle it. HTTP is a protocol, it has structure and rules to it.

If you want to send custom data to an HTTP server, use the ASource input parameter of the TIdHTTP.Post() or TIdHTTP.Put() method.

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: I don't want to use POST/PUT http requests for updating users status

Then why are you using the HTTP protocol at all?

(04-27-2022, 01:59 PM)Ahmed Sayed Wrote: I want this to use the minimum amount of data possible when send status pings to the push server.

Then use TIdTCPClient + TIdTCPServer instead of TIdHTTP + TIdHTTPServer. Invent your own protocol on top of TCP directly to suit your needs. You are approaching your issue all wrong.

(04-27-2022, 04:43 PM)rlebeau Wrote: OK, so why not simply have the HTTP client send its updated status to the HTTP server using a standard HTTP POST or PUT command?

That being said, there is one way you MIGHT be able to accomplish what you want using TIdHTTPServer, but you will not be able to accomplish it using TIdHTTP due to current design limitations in it, so you will have to use TIdTCPClient instead and implement the HTTP protocol manually on the client side.

Have the client send an HTTP 1.1 POST or PUT command, specifying Expect: 100-continue and Transfer-Encoding: chunked request headers. Do not send any body data yet to finish the request, just send the headers (TIdHTTP does not support this last part at this time).

When the server receives the request, it will detect the Expect header and send back an intermediate HTTP 1.1 100 Continue response, then wait for the remaining request body to arrive.

Have your client read that response, then start sending status updates to the socket connection as needed, in the 'chunked' format described in RFC 2616 Section 3.6.1 and RFC 7230 Section 4.1 (TIdHTTP does not currently support this, either). When there are no more updates to be sent, send a chunk with a size of 0, followed by empty trailer headers. Disconnect from the server if needed.

TIdHTTPServer will create a TIdHTTPResponseInfo.PostStream object and then enter a loop reading chunks, until it receives a chunk with a data size of 0, or the client disconnects. Each chunk will be written to the PostStream. However, by default, TIdHTTPServer will create a TMemoryStream for the PostStream, so you will have to use the TIdHTTPServer.OnCreatePostStream event to provide your own TStream instead. You can derive from TStream and override its virtual TStream.Write() method, or use Indy's TIdEventStream class with an OnWrite event handler assigned, to parse your status update chunks as needed.

After the last chunk has been received, TIdHTTPServer will fire the appropriate OnCommand... event for the original request. Simply do nothing, just exit.

With all of that said, this is a bit of an abuse of the HTTP protocol, but it will likely work for your particular use-case.

Reply


Messages In This Thread
RE: Writing data directly to socket from TIdHttp to TIdHttpServer - by rlebeau - 04-27-2022, 04:43 PM

Forum Jump:


Users browsing this thread: 1 Guest(s)