Delphi's TNetHTTPClient descendant supporting http2 - delphi

I am trying to communicate with Google Cloud Speech via gRPC from a Delphi 10.3.1 Windows client application. For this, the communication needs to be using http2 as protocol, and data needs to be transmitted 2-ways async.
Delphi includes TNetHTTPClient, which is used by TNetHTTPRequest for http communication. Using the debugger, I found that TWinHTTPClient in System.Net.HttpClient.Win.pas is used internally for the communication.
To add http2 support, I inserted 2 lines in TWinHTTPClient.DoExecuteRequest in System.Net.HttpClient.Win.pas, at line 1360:
LOptionValue := 1;//WINHTTP_PROTOCOL_FLAG_HTTP2;
WinHttpSetOption(LRequest.FWRequest, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, #LOptionValue, sizeof(LOptionValue));
After adding the above code, the component is using http2, which I verified by calling Google Cloud Speech Sync Request endpoint via gRPC successfully.
However, my approach has two major disadvantages:
It needs Delphi Source Code modification.
It does not support async bidirectional transport of data, for which I think an event a la OnDataReceived that may be triggered without the connection being closed is necessary.
I tried to find a point where I could replace TNetHTTPClient by a modified component TMyNetHTTPClient, but I did not succeed.
So, the question is: how to create a TNetHTTPClient replacement, based on TWinHTTPClient, that supports http2 and implements OnDataReceived event without closing the connection?

It's not based on TNetHTTPClient, but grijjy have open-sourced an HTTP2 Delphi client for Windows and Linux.
You can find it here - https://github.com/grijjy/DelphiScalableClientSockets

A bit late, sorry :)
I don't know how to implement the async bidirectional transport of data. I do know how TWinHTTPClient is constructed. Unfortunately, as you found out, since TWinHTTPClient is hidden in the unit's implementation, you cannot extend it.
You could copy that unit, make the necessary modifications, and use the modified class instead. It's not ideal at all to copy it, since it's a unit of over 2000 lines, but unfortunately there is no way around that.
But how to construct the modified TWinHttpClient, since normally you wouldn't construct a TWinHttpClient directly at all? That's a bit tricky, especially if you want to use other classes (like TNetHttpClient), that construct their own HttpClient internally.
TWinHTTPClient registers itself as a handler for HTTP and HTTPS. The unit itself does that by invoking TUrlSchemas.RegisterURLClientScheme.
You could unregister the TWinHttpClient class, and register your own like so:
TURLSchemes.UnRegisterURLClientScheme('HTTP');
TURLSchemes.UnRegisterURLClientScheme('HTTPS');
TURLSchemes.RegisterURLClientScheme(TYourWinHttpClient, 'HTTP');
TURLSchemes.RegisterURLClientScheme(TYourWinHttpClient, 'HTTPS');
After that, you can call THttpClient.Create, which is actually not a constructor but a class function that will invoke TURLSchemes to get an instance of the registered class.
That is, it finds the class, and calls the CreateInstance class function of that class. CreateInstance is a virtual factory method of TUrlClient, the ultimate base class. Your class should override that method to create and return an instance of itself.
It's a freaky construction. THttpClient is not just the base class for the various platform-specific descendants, but it's also a factory for them.
I happened to bump into this logic (and this question), when I was trying to create a THttpClient descendant for unit-testing purposes and ran into some surprise behavior. I'm not yet sure if it's genius or madness, or both :D
TUrlClient, THttpClient and TWinHttpClient are RTL classes, meant to be instantiated from code.
TNetHTTPClient is a TComponent that you can place on a TForm or TDataModule to configure design time. At runtime, when making requests, it uses THttpClient internally. It should use your modified version if you register it.

Related

Reusing ADO objects across multiple CoInitializeEx/CoUninitialize cycles

Currently I'm writing a REST server using a framework of a well-known Delphi component developing company. This framework provides the ability to simply write a class whose methods are named like the REST API endpoints.
The REST server fetches data from a MS SQL Server, I use dbGo components for that (what is ADO behind the scenes). There is also available an ORM framework of the same company mentioned above, but I don't want to use it for reasons.
Some of the REST calls work on a bunch of databases at once. In order to increase performance I implemented a connection pool, holding objects that encapsulate TADOConnection instances. When a REST call gets executed, it queries the connection pool if there is already an existing connection for the database(s) used by the call. If not, the required ADO database connection objects are created and handed over to the connection pool in order to be used again for subsequent connections to the same database(s).
I've noticed that the class with the methods named like the REST API endpoints gets instantiated by the framework for every single REST call. When the call is done the instance is freed. Because object instantiation and method calls are executed in the context of the REST server's thread (not in the main thread), I need to call CoInitializeEx in the constructor of the class and CoUninitialize in its destructor to be able to use dbGo's TADOxxx classes. Please note: There is no way to hook the server's thread creation or termination (I know, these would be the correct places to call CoInitializeEx and CoUninitialize, respectively).
The above concluded means that I store TADOConnection objects (encapsulating an ADO ActiveX class) during a certain cycle of CoInitializeEx/CoUninitialize and reuse them in a later cycle, i.e. COM has been uninitialized and gets initialized again between two usages of the same TADOConnection object.
Now my question is: Could that lead to any problems in a production scenario (for example crashes, memory or handle leaks or similar unwanted things) if multiple clients access the REST server? I'm quite unexperienced in dealing with COM and ActiveX respectively, so I need some help.

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.

What's the appropriate place to call CoInitialize/CoUninitialize across DLL's?

I'm implementing a DLL containing a shared ADO Connection by using the ConnectionObject property of TADOConnection and passing it across DLL boundaries into other instances of TADOConnection. I need to make sure COM is initialized, so I need to call CoInitialize / CoUninitialize. Currently it's in the context of a VCL main thread, but could be elsewhere in another thread, which of course requires its own instance of COM. I'm not currently implementing multi-threading.
Where is the appropriate place to call these; inside the DLL (during loading/unloading), outside the DLL (calling process), or both? Considering it's only one thread, shouldn't it be only one time outside the DLL in the original process?
I'm assuming the original calling thread should be solely responsible for this, since COM runs in the context of a thread. Of course calling them on both sides shouldn't hurt any, however it would also create multiple COM instances.
Long story short... Is it "safe to be safe" in this case? Or is it important to only keep one COM instance?
You should not be doing this in the DLL. Make it part of the contract between the DLL and the host that the host is responsible for initializing COM.
The DLL cannot be expected to initialize COM because the host may already have done so. And use a different threading model. Once COM has been initialized then future attempts to initialize will fail if they attempt to change the threading mode.
So, don't initialize COM in your DLL. Require the host to do so.

Why are onOpen and onClose Streams (not Futures) in dart:html WebSockets?

A dart:html.WebSocket opens once and closes once. So I'd expect that the onOpen and onClose properties would be Futures, but in reality they are Streams.
Of course, I can use stream.onClose.first to get a Future. But the done property on the dart:io version of WebSocket is a Future as expected, so I'm wondering if I'm missing something.
Why use Streams and not Futures in dart:html?
In a word: transparency. The purpose of the dart:html package is to provide access to the DOM of the page, and so it mirrors the underlying DOM constructs as closely as possible. This is in contrast with dart:io where the goal is to provide a convenient server-side API rather than exposing some underlying layer.
Sure, as a consumer of the API you would expect open and close to be fired only once, whereas message would be fired multiple times, but at the root of things, open, close, message, and error are all just events. And in dart:html, DOM events are modeled as streams.
And actually, a WebSocket could very well fire multiple open events (or close events). The following is definitely a contrived example, but consider this snippet of javascript:
var socket = new WebSocket('ws://mysite.com');
socket.dispatchEvent(new Event('open'));
socket.dispatchEvent(new Event('open'));
socket.dispatchEvent(new Event('open'));
How would a Dart WebSocket object behave in a situation like this, if onOpen were a Future rather than a Stream? Of course I highly, highly doubt this would ever surface out there in the "real world". But the DOM allows for it, and dart:html should not be making judgment calls trying to determine which situations are likely and which are not. If it's possible according to the spec, dart:html should reflect that. Its role is simply to pass through the behavior - as transparently as possible - and let the consumer of the API decide what cases they need to handle and which they can ignore.

LoadLibrary, a way to instantiate a class from external dll?

I have written a dll in d-7. It functions correctly. It gets loaded when an application starts and unloaded when it exists.
Now, that dll must also work on the server side of that application, being loaded from the COM+ surrogate (dllhost.exe) as the server is based on com+ technology.
The problem is that one process may have only one handle for loaded library. I cannot have separate handles on each LoadLibrary call.
In com+, one dllhost.exe can serve many clients, which means that if I load an external library it gives the same instance for each clients calls.
So:
1) Is it possible to somehow workaround this problem?
2) Or Is it possible to directly create instance of the class which resides in this dll for each client call?
3) Or How to make a dll thread-safe by instantiating an internal class for each call.
Thanks for suggestions in advance!
Since a DLL uses the local memory of the thread/process that calls it, I'm not sure you're really going to have a "problem". You do not want to have the DLL maintain some global information because that will only lead to threading nightmares.
If you have a function within the DLL return an object reference (effectively a handle) you can also guarantee that each instance gets its own information to play with and not stomp on other processes or threads. Define the function to return your TWhatever object, have the DLL create it ( TWhatever.Create() ) and return it to the calling process. It would then be up to the calling process to free the object. If you need COM+ compatibility then it should be possible to use an interface reference (IWhatever) and return that from your function.
If each thread deals with its own object instance (or interface reference) then you could have the DLL serve as many threads and processes as you wish.
Your question is confusing to me so I'm not sure if I answered it correctly. :p

Resources