You are not logged in.
Since Windows XP SP2 and Windows Server 2003, the Operating System provides a kernel stack to handle HTTP requests. This http.sys driver is in fact a full featured HTTP server, running in kernel mode. It is part of the networking subsystem of the Windows operating system, as a core component.
The SynCrtSock unit can now implement a HTTP server based on this component. Of course, our SQLite3 framework now can use it. If it's not available, it will use our pure Delphi optimized HTTP server, using I/O completion ports and a Thread Pool.
What's good about https.sys?
Kernel-mode request queuing
Requests cause less overhead in context switching, because the kernel forwards requests directly to the correct worker process. If no worker process is available to accept a request, the kernel-mode request queue holds the request until a worker process picks it up.
Enhanced stability
When a worker process fails, service is not interrupted; the failure is undetectable by the user because the kernel queues the requests while the WWW service starts a new worker process for that application pool.
Faster process
Requests are processed faster because they are routed directly from the kernel to the appropriate user-mode worker process instead of being routed between two user-mode processes, i.e. the good old WinSock library and the worker process.
Who does it work with our framework?
The HTTP Server API is first initialized. The HttpApi.dll library (which is the wrapper around http.sys) is loaded dynamically: so if you are running in an old system (Windows XP SP1 for instance), you could still be able to use the server.
We then register some URL matching the RESTful model. In short, the TSQLModel.Root property is used, just as usual.
You can register several TSQLRestServer instances, each with its own TSQLModel.Root, if you need it.
If any of the two first point fails (e.g. if http.sys is not available, or if it was not possible to register the URLs), our framework will fall back into using our THttpServer class, which is a plain Delphi multi-threaded server.
Inside http.sys all the magic is made... it will listen to any incoming connection request, then handle the headers, then check against any matching URL.
Our THttpApiServer class will then receive the request, and pass it to the TSQLRestServer instance matching the incoming URL request.
All JSON content will be processed, and a response will be retrieved from the internal cache, or computed using the SQLite3 database engine.
The JSON content will be compressed using our very optimized SynLZ algorithm (much faster than Zip/Deflate), if the client is a Delphi application knowing about SynLZ - for an AJAX client, it won't be compressed by default (even if you can enable the deflate algorithm - which may slow down the server).
Then the response will be marked as to be sent back to the Client...
And http.sys will handle all the communication by itself.
When UAC strikes back again...
This works fine under XP. Performances are very good, and stability is there.
But... here comes the UAC nightmare again.
Security settings have changed since XP. Now only application running with Administrator rights can register URLs to http.sys. That is, no real application.
So the default registration step will always fail, under Vista and Seven.
So we managed to create a workaround for this.
Our SynCrtSock unit provides a dedicated method to authorize a particular URL prefix to be registered by any user.
Therefore, a program can be easily created and called once with administrator rights to make http.sys work with our framework.
This could be for instance part of your Setup program.
Here is a sample program which can be launched to allow our TestSQL3.dpr to work as expected:
program TestSQL3Register;
uses
SynCrtSock,
SysUtils;
{$R VistaAdm.res} // force elevation to Administrator under Vista/Seven
begin
THttpApiServer.AddUrlAuthorize('root','888',false,'+',delete));
end.
All this is to be officially release with our upcoming 1.13 version of the framework.
But you have all the source code freely available from our Source Code repository.
Offline
There was a problem in our implementation of body retrieval.
It's now fixed by http://synopse.info/fossil/info/6e50daabb4
And I've also enhanced error handling in THttpApiServer.Execute.
See http://synopse.info/fossil/info/eee15165fa
Sounds quite stable now.
Offline
I've uploaded a demo program for this THttpApiServer class.
It's able to serve some hard drive content, using a virtual directory layout.
Directory list is created in Delphi code.
File downloads are handled by http.sys at kernel-level mode.
Offline
How much faster is this kernel mode? Do you have any numbers? (response time, throughput, etc)
Offline
It depends on the system it runs on.
Run locally, I found out the kernel mode to be faster than our tuned THttpServer class, using a thread pool:
2.5. Client server access:
- TSQLite3HttpServer: 2 assertions passed
using THttpApiServer
- TSQLite3HttpClient: 3 assertions passed
- Http client keep alive: 3,008 assertions passed
first in 315.81ms, done in 429.42ms i.e. 2328/s, aver. 429us, 10.8 MB/s
- Http client multi connect: 3,008 assertions passed
first in 204.11ms, done in 423.57ms i.e. 2360/s, aver. 423us, 11.0 MB/s
- Http client keep alive delphi: 3,008 assertions passed
first in 558.29ms, done in 458.62ms i.e. 2180/s, aver. 458us, 10.1 MB/s
- Http client multi connect delphi: 3,008 assertions passed
first in 225.19ms, done in 456.12ms i.e. 2192/s, aver. 456us, 10.2 MB/s
- Named pipe access: 3,010 assertions passed
first in 325.61ms, done in 154.22ms i.e. 6483/s, aver. 154us, 30.3 MB/s
- Local window messages: 3,009 assertions passed
first in 252.94ms, done in 87.61ms i.e. 11413/s, aver. 87us, 53.3 MB/s
- Direct in process access: 3,008 assertions passed
first in 204.82ms, done in 70.54ms i.e. 17175/s, aver. 70us, 66.2 MB/s
Total failed: 0 / 21,064 - Client server access PASSED
The "delphi" versions are the one using our Thread-pool based server.
Not a big speed increase (10% more queries), but we can rely on the kernel.sys architecture to scale better and to be more reliable on all circumstances than our own pure Delphi implementation (which is already faster than Indy's).
Those have been run on an old Pentium IV under Windows XP, with slow Norton antivirus running, and LOCALY.
So don't take those number in absolute, just as relative comparison between http.sys kernel-mode server and our pure delphi tuned implementation.
For instance, on a Core i7 laptop, direct process access if more than 27000 requests/s (this is the speed of our RESTful authentication and URI + JSON parsing and caching layer, without Client-Server access).
The speed bottleneck here is not our Framework, but the TCP/IP layer.
It's very interesting, IMHO, that multi-connection and kept-alive connections both achieve more or less the same speed.
If we need a conclusion, I would state than on a real server, on a real network, serving real JSON data, the http.sys server will scale always better.
Offline
I played around with the httpAPI server a little bit. Is it meant to be a blocking single client server?
I noticed no other client is processed if a really big response (as example a 2 GB file) is send...
Last edited by MarcHal (2011-06-28 14:39:11)
Offline
The HttpAPI server is natively multi-thread, AFAIK.
Each response queue has its own thread, so it's able to run on multi-thread.
Otherwise, there should be not use for such a HTTP server.
What did you code to have this behaviour?
If you were using our framework, there is some kind of "giant lock" in the current implementation. We will improve this for mORMot. But our ORM was meant to deal with some "small" kind of JSON data. I definitively need some more info about what you did.
Offline
I simply used the Sample 09 - HttpApi web server, selected a 4 GB file to download (takes even local 2 minutes) and tried to open the page in another browser tab and nothing came up until the download was done.
After a little bit of of debugging it showed that
procedure THttpApiServer.Execute;
[...]
Http.SendHttpResponse(fReqQueue,Req^.RequestId,0,Resp^,nil,bytesSent);
finally
FileClose(FileHandle);
end;
[...]
the server does wait for Http.SendHttpResponse to finish.
Maybe there should also be a thread pool for client requests like in the delphi httpserver...
Offline
I''m not so sure.
Thinking about all those casted pchars in the Resp structure and the filehandle itself. I have some doubts all this gets duplicated in the http.sys so that there are no memory allocation problems and free floating filehandles...
Offline
Thinking about all those casted pchars in the Resp structure and the filehandle itself. I have some doubts all this gets duplicated in the http.sys so that there are no memory allocation problems and free floating filehandles...
There is no problem of freeing a file handle in another place. It's perfectly thread safe.
You can check with the reference code available in http://msdn.microsoft.com/en-us/library … S.85).aspx
About the thread pool, there is already one, implemented via fClones[] TObjectList.
All threads share an unique fReqQueue, and Http.ReceiveHttpRequest() function retrieve a pending request from the queue on purpose.
Did you try with multiple browser instances? Perhaps the connection is shared on the client side, so it won't create several threads on server side.
Offline
I even tried different computers (downloading from a laptop, browsing from my IPad). Same effect.
And the PC the "server sample" is running on has more than enough power to handle this with ease.
Offline
BTW:
http://msdn.microsoft.com/en-us/library … 85%29.aspx
pOverlapped [in]
For asynchronous calls, set pOverlapped to point to an OVERLAPPED structure; for synchronous calls, set to NULL.
A synchronous call blocks until all response data specified in the pHttpResponse parameter is sent, whereas an asynchronous call immediately returns ERROR_IO_PENDING and the calling application then uses GetOverlappedResult or I/O completion ports to determine when the operation is completed.
As far as I see the server uses the synchronous call...
Offline
As far as I see the server uses the synchronous call...
And that is as expected: each thread blocks until it receives a request to handle from the pool.
Overlapping is about blocking or not blocking the current thread, not all other threads accessing to the resource, AFAIK.
Offline
I see, I might have been misslead by the Sample. you need to create clones to make it work.
Sorry about this.
Last edited by MarcHal (2011-06-29 08:50:08)
Offline
Have you got any plans to implement http logging like this doc describes http://msdn.microsoft.com/en-us/library … 85%29.aspx?
Offline
Have you got any plans to implement http logging like this doc describes http://msdn.microsoft.com/en-us/library … 85%29.aspx?
I did not notice this feature.
To be honest, I rely on our TSynLog class for logging.
In fact; there is already plenty of logging in TSQLRestServer.URI method:
- High resolution timing of each request handling;
- Authorization logging (with user name and SessionID);
- HTTP method and URI, with integer result for both correct requests and errors.
But this is from the application point of view.
In order to use external tools to review HTTP requests log (e.g. for security purposes), it may be indeed useful to enable W3C type server side logging.
If you have any implementation, I would include it.
I may take a look at it, also.
Offline
I haven't got any experience translating api headers but may try this as a learning exercise. I've noticed the JEDI project do some tutorials.
Still haven't properly looked at TSynLog so will do that first.
Offline
I need understand when I need use AddUrlAuthorize.
If I use Windows XP I don't need of it, but what I need to do in these case:
1) use my application as standalone application on Windows Vista/7;
2) use my application as client/server, in this case I need know what to do on client and on server computer?
Offline
1) use my application as standalone application on Windows Vista/7;
Of course, AddUrlAuthorize is not necessary if you do not use the HTTP server.
2) use my application as client/server, in this case I need know what to do on client and on server computer?
On client: ensure that the used port will pass through the Windows firewall.
On server: run AddUrlAuthorize on the given port+URI. On server, no need to configure the Windows firewall: the http.sys component is already registered to the firewall.
Offline
Offline