Delphi 7 indy web server display AResponseInfo.PostStream - delphi

I have some clients that post xml / soap containers. I would like to build a tiny standalone indy web server app, that accepts any request and displays the content of the PostStream in a memo field. Unfortunately I don't know how to decode the PostStream. I get an exception using this code:
ARequestInfo.PostStream.Seek(0, soFromBeginning);
Memo1.Lines.LoadFromStream(ARequestInfo.PostStream);
I am using Delphi7 Enterprise

Not every request type uses the PostStream property, so you have to check if the PostStream is not nil before you attempt to use it.
Also, TIdHTTPServer is a multi-threaded component. Its events are triggered in worker threads, and it is not safe to access UI components from outside of the main thread, so you need to synchronize with the main thread when accessing the TMemo.
Update: If you need to always have a PostStream available, in older versions of Indy you can use the OnCreatePostStream event to create your own TStream object to use as the PostStream. In those versions, TIdHTTPServer manages PostStream objects that it creates, and sometimes frees them before giving them to you, but user-defined PostStream objects are not freed until after the request is finished being processed by you. However, in recent Indy 10 releases, there is a new OnDoneWithPostStream event that helps control when a PostStream gets freed for any given request, regardless of whether it is created by TIdHTTPServer or by you (in which case, you don't need to use the OnCreatePostStream event to extend the PostStream's lifetime). In all versions, an unfreed PostStream is always freed when the TIdHTTPRequestInfo object is freed.

Related

How to start Indy TCP Server with parameters?

I am building a TCP Server using Indy 10 (from Delphi 2009). In OnExecute event I need to acces some data from the main thread. It is possible to pass that data to the server thread when I start it ? The server is started with IdTCPServer1.Active:=True; so I don't see how I can pass some parameters.
It is not possible to pass extra parameters to TIdTCPServer. Your server event handlers will have to retrieve the data from the main thread when needed.
To keep track of per-connection data across events, you can use the TIdContext.Data property, or derive a custom class from TIdServerContext and assign it to the TIdTCPServer.ContextClass property. For instance, your OnConnect event handler can retrieve the latest data from the main thread using TIdSync or TThread.Synchronize(), and then cache it in the context for OnExecute to use.

How to access/use Indy server/client 's OnReceive and OnSend event ?

I use c++ builder XE8, and I am a beginner. I want to use OnReceive and OnSend event of Indy server and client to make it work in non-blocking mode. I have read that Indy server/client works in blocking mode, and to make it work i have to use a separate thread. I also found example but those were in delphi not c++. Can I do this using Intercept/IOHandler, or I have to use separate thread ? Please give a short example code.
I want to use OnReceive and OnSend event of Indy server and client to make it work in non-blocking mode.
Indy uses blocking sockets exclusively. You cannot use them in a non-blocking mode. There are no OnReceive and OnSend events, like there are in the VCL's TClientSocket and TServerSocket components.
I have read that Indy server/client works in blocking mode, and to make it work i have to use a separate thread.
That is true.
Indy servers are multi-threaded. TIdTCPServer has OnConnect, OnDisconnect, and OnExecute events that are triggered in the context of worker threads, one for each connected client. TIdUDPServer has an OnUDPRead event that is triggered in the context of worker threads, one foor each listening port. You need to do your socket I/O in these events. Typically, you would simply perform whatever read/write operations you need and let Indy block the calling thread as needed.
Indy clients are mostly single-threaded, they run in the context of whatever thread they are used in (TIdCmdTCPServer and TIdTelnet being the exception to that rule). So you usually have to create your own thread to manage the socket I/O if you want non-blocking behavior.
Please read the documentation for more details:
Introduction to Indy
I also found example but those were in delphi not c++.
And? The components are the same in both languages. So either translate the code from Pascal to C++, or just use the code as-is (did you know that you can use Delphi code in C++Builder projects? You can).
Can I do this using Intercept/IOHandler
No. An Intercept is meant for manipulating data as it passes to/from the connection (to apply encryption, compression, etc). The IOHandler performs the actual I/O operations, but it has nothing to do with threading.
or I have to use separate thread ?
Yes.
Please give a short example code.
There are plenty of examples readily available if you search around. StackOverflow is not the place to ask for them.

Best pratice ro handle Indy TCP Server execute in Delphi Xe3

When receiving data from a indy TCPServers execute method i generally handle it by reading the data by doing the following:
AContext.Connection.IOHandler.ReadLn;
and then process the data in the execute method. Most of the data that comes through are small JSon strings.
In the future i will need to handle larger data chunks and was wondering what the best pratice is to do so?
Is it a good idea to add the incoming data to a TidContext class and process it using some worker thread? Any thoughts or code samples would be appreciated. I use Indy 10 and Delphi XE3
The OnExecute event is already triggered in a worker thread, so it doesn't matter how long it takes to receive the data. As long at the data only has 1 (CR)LF at the end of it, ReadLn() will not care how long the string actually is (subject to the IOHandler's MaxLineAction and MaxLineLength properties, which you can tweak if needed). However, if the data has more than 1 (CR)LF in it, then you will have to either:
transmit the string length before transmitting the actual string, then use ReadLongInt() and ReadString() instead of ReadLn() in the receiving code.
terminate the string with a different delimiter than (CR)LF at the end, and then pass that delimiter to ReadLn() so it knows when to stop reading.
If the server has to receive incoming requests at a guaranteed rate, without blocking the consumers by slow request processing, saving the big data chunks to a datastore (file, database) for later processing could be a solution.
This would make the HTTP server thread available for the next request as soon as possible.
It also allows to do the data processing by multiple worker servers, with load balancing.

Delphi Service to Listen to TCP or UDP

Reading this question:
Delphi Windows Service Design, I saw that most designer use this code below in the OnExecute of the TService or in the TThread method, in order to keep service alive.
while not Terminated do
begin
// do something
end;
But what if I need (and I do) to create a service to respond (using Indy) to messages sent by the main application in order to send back some authentication data, what do I do with this code, ignore it or put some Sleep() in it?
Indy's TIdTCPServer and TIdUDPServer components are multi-threaded, so you don't really need to use the TService.OnExecute event at all. You could just activate them in the TService.OnStart event and deactivate them in the TService.OnStop event, and then assign handlers to the TIdTCPServer.OnExecute and TIdUDPServer.OnUDPRead events as needed. Both events are already looped for you, so you don't need a while not Terminated loop in them. Just read/process one request as needed, then exit, and wait for the next event to repeat. Let the server handle any exceptions that are raised. And keep in mind that TIdUDPServer has a ThreadedEvent property that is False by default, so you should set it to True inside a service.

Is it possible to call TidSMTP.Connect once and then from threads call TidSMTP.Send?

I am writing an app that sends e-mail messages using Indy.
Every message is sent by a thread.
Currently I am connecting to TidSMTP inside the thread, so for sending 10 mails, I need 10 threads and I connect 10 times.
Is it safe (which are the drawbacks?) of having a single TidSMTP (outside of the thread), call Connect once and then call TidSMTP.Send inside the thread?
Will TidSMTP manage thing correctly?
Note: the idea is to avoid to connect every time (if possible), in case of many emails to be sent it could be an advantage. (does it makes sense to get worried for this, or calling Connect in every thread is pefectly ok?).
Why don't you use only 1 thead in which you have a TIdSMTP and a TList in which you store TIdMessage's and after each send you free the TIdMessage from the list, in this case you avoid overhead and keep it simple.
What if you want to send 200 e-mails, well if you start 200 threads then your application will use over 200 Mb only for those 200 threads not to mention that there can be problems starting that many threads in your application.
Bottom line add a TList in which you temporarily store prepared TIdMessages and inside the thread a while loop that will check if the list has any messages to send, if it has then grab, send and remove from list.
Technically, you can call Connect() in one thread and then call Send() in other threads. However, you would have to serialize access to Send(), otherwise the sending threads can overlap each other and corrupt the SMTP communication. Dorin's suggestion to move all of the SMTP traffic to a single thread with a queue is the best choice. However, the queue itself needs to be accessed in a thread-safe manner, so using a plain TList or TQueue by itself it not good enough. Either use TThreadList (or Indy's own TIdThreadSafeList) instead of TList, or wrap the TQueue with a separate TCriticalSection.

Resources