1

I'm using TIdHTTP in my class to handle web APIs (TWebAPI). Since it might happen that this class is used in a TIdHTTPServer.OnCommandGet event handler, I need to make sure that TWebAPIis thread safe.

Do I need to wrap a PUT/GET/POST inside a TMultiReadExclusiveWriteSynchronizer?

EDIT: Code-Sample

TWebAPI

TWebAPI=class(TObject)
 FSocket:TidHTTP;
end;

procedure TWebAPI.Send;
Var
 Response:TSTringStream;
begin
 FSocket.Get(fURL,Response);
end;

Main Program

TMain=class(TForm)
 Server:TidHTTPServer;
 WebAPI:TWebAPI;
end;

procedure TMain.ServerCommandGet(....)
begin
 WebAPI.Send;
end;

So my WebAPI would be used in different threads on each command the server gets. SHould I use the CriticalSection in TMain, or implement it in TWebAPI like this?

TWebAPI=class(TObject)
 FSocket:TidHTTP;
 FLock:TCriticalSection;
end;

procedure TWebAPI.Send;
Var
 Response:TSTringStream;
begin
 FLock.Aquire;
 try
   FSocket.Get(fURL,Response);
 finally
   FLock.Release;
 end;
end;
Wolfgang Bures
  • 509
  • 4
  • 12
  • 2
    It depends on how you use it. You did not show any code. Like most other classes, if you share a `TIdHTTP` object across thread boundaries, then yes, you need to sync access to it. Otherwise, no, you do not. Please provide a [mcve] that you are concerned about, and someone can tell you if it is threadsafe or not. – Remy Lebeau Jan 08 '21 at 10:06
  • @RemyLebeau, code added :-) – Wolfgang Bures Jan 08 '21 at 19:26
  • 1
    You are sharing a single `TIdHTTP` across multiple threasd, so yes, you would need to lock access to it on each HTTP operation you want to perform. Is there a reason why you are using a single `TIdHTTP` in this manner, and not letting each `TIdTCPServer` thread use its own local `TIdHTTP` instead? – Remy Lebeau Jan 08 '21 at 19:45
  • Yes, TwebAPI uses OAuth and I don't want to do it every time. – Wolfgang Bures Jan 08 '21 at 20:15
  • 3
    You don't need to reuse a single `TIdHTTP` just to reuse credentials across multiple HTTP requests. Use 1 `TIdHTTP` to grab the credentials one time and save them, and then you can assign the saved credentials to other `TIdHTTP` objects as needed. So, I'm still in the mindset that each server thread should be using its own local `TIdHTTP`, and you sync only the OAuth login between them. – Remy Lebeau Jan 08 '21 at 20:17
  • I'll look into that, thx! – Wolfgang Bures Jan 08 '21 at 20:44
  • Would I also recreate the (SSL)IOHandler every time new, or use a shared one? – Wolfgang Bures Jan 08 '21 at 22:12
  • 1
    You can't share an `(SSL)IOHandler` between multiple clients *simultaneously*, since it represents a single TCP connection. But, if you have multiple requests going to the same server, it might make sense to share an `(SSL)IOHandler` as long as the requests are not performed *simultaneously*. For instance, you could create a small pool of `(SSL)IOHandler` objects, and then pull one out of the pool when you need to make a request, and put it back in the pool when finished. Of course, you could do the same thing with `TIdHTTP` objects, too. – Remy Lebeau Jan 08 '21 at 22:21

1 Answers1

2

A single TIdHTTP could be protected by a TCriticalSection or TMonitor. There is no R/W involved, so don't use TMultiReadExclusiveWriteSynchronizer - just a mutex/lock. But if you use a single TIdHTTP you will need a mutex/lock, so all HTTP calls will be serialized, which may be not a good idea on a multi-threaded server.

I would maintain one connection per thread, or write a connection pool. Perhaps just a given TIdHTTP each time may not be too bad. At least it will be safe and there will be room for improvement later on. Reopening a TCP/HTTP connection is quick in practice.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • I'm currently only using `TMREWS`for everything. Is it "just" performance that gets lost when using it all the time, or are there any other cavets? – Wolfgang Bures Jan 08 '21 at 19:28
  • 4
    You *can* use `TMREWSync`, but you would have to use only its write lock for adequate protection, which kind of defeats the purpose of using `TMREWSync` in the first place. A `TCriticalSection` or `TMonitor`, or even a Win32 Slim R/W Lock, would be more efficient. – Remy Lebeau Jan 08 '21 at 19:47