You are not logged in.
Any chance of a web-based, google-searchable HTML documentation?
PDF for technical docs is quite on the impractical side, especially with so many pages, and it's a bit sad to have all that information stay basically unreachable for everyday use. ![]()
But the providers (especially on iOS) add some serious limitation (like 256 bytes maximum length) or security requirements (like explicit SLL certificates).
Yes, they should really only be used to pass commands, rather than data.
For instance for a mail app, you wouldn't pass the new mails, but a command like "check new mails", and the app would then fetch the mails through regular means.
I guess it helps to consider platform notifications as being barely improved remote keypress events ![]()
But mostly the whole point is that on mobile devices, either the application is active and it's okay to poll like a madman, or it's not active, and you can use neither websockets nor long polling. Desktops and laptops are a different story of course.
Another advantage of polling when the app is active is that you can report connection lag to the user, which is quite important for a chat app, multi-player game or trading views!
With long poll or websockets, you can't tell connection lag apart from a lack of updates... unless you "ping" frequently, but then you're no better than polling.
As a conclusion, I would recommend the following, for any project:
Use WebSocket for client notifications only (with a fallback mechanism to long-polling - there are plenty of libraries around);
Use RESTful / JSON for all other data, using a CDN or proxies for cache, to make it scale.
Cloudflare recently began adding websocket support
http://blog.cloudflare.com/cloudflare-n … websockets
though obviously there is no caching ![]()
I'm not sure long-polling is a very good alternative to websockets: it will still incur the same scaling issues as websockets (since it has to bypass the CDN), it has associated risks of timeout throughout the wire (can miss some notifications, especially on mobile connections, and you don't have receipts).
The security advantage is over WSS is marginal at best: websockets data goes in well delimited messages that are just as inspectable (or not) as the random binary or malformed data you can pass over http.
That said, for instant notifications the best solution are probably the platform's push notifications, which are centralized on a single service and can thus happen even when an application is not active. Long polling and websockets both require the application to be active.
However for data not specific to a client, such as chat, news, trading data, etc. in my experience good old brute-force high-frequency polling can work very well. It's *very* CDN friendly, if you set 1 second caching f.i., you can serve a million of clients with 1 refresh per second while the main server will get just dozens of requests per second, which is easily manageable.
@Eric & @Chapa
Logic-less templates have other advantages, like 100% uncoupling logic and presentation (whereas PHP, Razor or DWS do not).
They allow coupling, but don't dictate it. DWS has server-side compilation and strong-typing, so it's not like PHP where you can never now exactly what access what and how or when.
A downside of logic-less data-driven templates is that they're runtime-evaluated, with no strong typing, so they require more effort to maintain to maintain, and are error-prone (a weakness shared by untyped languages like PHP).
AJAX requests represent only a small portion of web pages - and Mustache was designed for real web site (used by Twitter or by Google, in its parent ctemplate).
I disagree, the XML portion of AJAX is pretty much dead, but the asynchronous, javascript-driven aspects have become ubiquitous.
Pretty much all of google and twitter webpages are JavaScript applications, which load not just the data asynchronously, but the presentation and the code itself, and arguably google "webpages" are architectured like traditional fat clients, with dynamic libraries, data access drivers, UI drivers & APIs, etc. they just happen to run in a web browser.
If you look at trends for gmail, charts, maps, google+, analytics, adsense, drive etc. they're all ever more heavy on the client-side logic, and they're all relying on javascript-driven asynchronous loading (many even have loading progress bar or pacifiers, which I don't consider a progress btw)
While mustache and logic-less templates was interesting as a reaction to PHP (and JSP), I'm not convinced it still is very relevant: you can built simple stuff easily with mustache, but you can't build modern web UIs with it, not without throwing a lot of JS or going through extra hoops. Popular template engines these days seem to all have logic.
Very nice results!
However, I heartily disagree on you benchmarking conclusions for several reasons ![]()
Perhaps it's my scientific training, but I believe that focused experiments & measurements always yield interesting fundamental insight.
And case in point, your benchmark is synthetic and focused, where Mandelbrot measures tight loops and simple floating point operators, your benchmarks measure loops, buffer writes and string lookups.
Also, Mustache js isn't really optimized for speed, but for size (hence all the Regular Expressions), and there are faster, Mustache-compatible JS libraries (like Handlebars f.i, which is said to be 2x faster than Mustache, but that in special cases can be 100 times faster).
The reason why optimizing for size makes sense, is that in a "real world" high-performance application, you shouldn't be processing the templates on the server-side in the first-place, that's why I think your benchmark is no more "real-world" than Mandelbrot. Though it likely provides more insight on your coding skills than on the Delphi compiler's own strength I'm afraid
Logic-less templates real strength comes in client-side processing, where they have numerous advantages:
- processing power linearly goes up with the number of clients, and thus is never an issue as long as it's fast enough for the slowest client
- server-side CPU requirements are limited to data-extraction & JSON generation
- templates are static, and thus can be cached on the client (zero bandwidth after 1st load) or served by geo-located CDN (practically unlimited bandwidth)
- server bandwidth requirements are reduced to just serving the data
- since the templates are logic-less, you don't leak any business know-how to client-side execution
- fundamentally different rendering of the same data from the same server is possible, without touching anything on the server, and with no risk of a faulty template/rendering affecting server performance
So where a server-side Mustache will result in ever-increasing load, especially bandwidth load which you're likely to run out well before you run out of CPU on a web-based application, especially if want to serve the whole world, a client-side Mustache will only be limited by the data extraction & bandwidth rates, ie. the speed at which you can extract, generate & send the data.
And when the data itself can be cached & shared (even for short durations), there is practically no limit to scale-ability.
Case in point, my current DWS WebServer experimentation involves serving datasets up to the megabyte range, with usage spikes of hundreds of simultaneous clients, the megabyte of data getting rendered to several megabytes of HTML (once you factor scaffolding & class tags for convenient CSS presentation + IDs for JS interactivity, html quickly balloons up). All this from a mere 10Mbit/s server, which if you do the maths, just wouldn't have the bandwidth (nor the latency, nor the CPU) to handle the load on its own.
The client-side tech is not Mustache, but the fundamentals of client-side rendering & geo-located caching are the same (in my case, it's Cloudflare that's takes the brunt of the load). During a time one link got popular, it averaged a week at 30000 pageviews per day, that's plenty of gigabytes of data, and even more gigabytes of rendered html if it had been done server-side, and way more than the server could have handled on its own.
Great, thanks!
Currently TSQLDataBase.DBOpen uses sqlite3.open, it could be nice to use open_v2 instead and the extra flags it supports.
Basically 'open' should be replaced by 'open_v2', an extra parameter with the flags added (default value SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE), and the following constants added:
SQLITE_OPEN_READONLY = $00000001; // Ok for sqlite3_open_v2()
SQLITE_OPEN_READWRITE = $00000002; // Ok for sqlite3_open_v2()
SQLITE_OPEN_CREATE = $00000004; // Ok for sqlite3_open_v2()
SQLITE_OPEN_DELETEONCLOSE = $00000008; // VFS only
SQLITE_OPEN_EXCLUSIVE = $00000010; // VFS only
SQLITE_OPEN_AUTOPROXY = $00000020; // VFS only
SQLITE_OPEN_URI = $00000040; // Ok for sqlite3_open_v2()
SQLITE_OPEN_MEMORY = $00000080; // Ok for sqlite3_open_v2()
SQLITE_OPEN_MAIN_DB = $00000100; // VFS only
SQLITE_OPEN_TEMP_DB = $00000200; // VFS only
SQLITE_OPEN_TRANSIENT_DB = $00000400; // VFS only
SQLITE_OPEN_MAIN_JOURNAL = $00000800; // VFS only
SQLITE_OPEN_TEMP_JOURNAL = $00001000; // VFS only
SQLITE_OPEN_SUBJOURNAL = $00002000; // VFS only
SQLITE_OPEN_MASTER_JOURNAL = $00004000; // VFS only
SQLITE_OPEN_NOMUTEX = $00008000; // Ok for sqlite3_open_v2()
SQLITE_OPEN_FULLMUTEX = $00010000; // Ok for sqlite3_open_v2()
SQLITE_OPEN_SHAREDCACHE = $00020000; // Ok for sqlite3_open_v2()
SQLITE_OPEN_PRIVATECACHE = $00040000; // Ok for sqlite3_open_v2()
SQLITE_OPEN_WAL = $00080000; // VFS onlyThanks!
In case of errors, SynZip has a Check function, which displays errors with
MessageError(IntToStr(aCode),'SynZip');However that can be called from the HTTP worker threads (among others), which may be running in a service, so there may be no one to see the error. It should probably be something like
raise Exception.CreateFmt('SynZip %d', [aCode]);So that an exception is appropriately triggered, and the code calling SynZip can react appropriately.
Even for interactive debugging it can get problematic if you have a few hundred of such errors fired from a tight loop, it'll overwhelm your screen with as many error dialogs, which just can make Windows crawl before you get a chance to terminate the app (happened to me)
Thanks! A bit out of budget as it's for experimenting (don't know if you caught my Mandel experiment why it was online).
GPU is fast, but servers with GPU are very expensive.
Currently my best solution is libjpeg-turbo (http://libjpeg-turbo.virtualgl.org/) using the headers from http://www.opengl24.de/header/libjpeg
Compression speed is 7 to 8 times faster than TJPegImage, I'm not entirely sure vs IPP (they claim to be in the same ballpark).
Any suggestions?
This is to generate a lot of JPEG files on the fly server-side.
Eric
I was under the impression that a known or predictable nonce / salt was as good as no salt from a brute-force hacking point of view, for the same reason that a salted password hash with SHA256 won't be enough to secure password shorter than 8-9 characters from a GPU brute-force crack if the salt is known and SHA256 is not applied thousands of times.
I've read that given the GPU perfs, an ASIC chip could likeley brute-force a salted hash password up to 10-12 characters passwords (numbers, upper and lower case characters and the common punctuation symbols) in a short time frame, and that this was the reason why even salted password databases were hacked these days.
But that may not apply to the situation here ![]()
But this is still a client-defined nonce, so IMHO this is not the weakness of the algorithm.
Didn't you said on the server side that a value derived from GetTickCount is used as well?
I observed Random() has a similar entropy to real data
I've observed the opposite (http://delphitools.info/2011/12/13/pimp … -xorshift/)
On Server side, we use a simple value derived from GetTickCount, which will be valid for about 5 minutes.
What about using RDTSC? It's wildly varying, especially on machines with multiple processors.
On Client side, TSQLRestServerAuthenticationDefault.ClientSetUser() uses SHA256(NowToString) which does a pretty good job.
Wasn't the randomness of it quite low? There were only 86400 different hash values possible per day, and they are predictable long in advance.
I'm a bit wary of pseudo-random generated from time-based seeds at the millisecond level, since the machine time is usually known at that level of precision (these days, most machines are time-synchronized so they're typically within a second of the reference time).
While GetTickCount is a bit less predictable since it depends on the time the machine was last rebooted, it doesn't evolve very fast, and for Windows servers, you can make a good guess based on the latest critical windows updates release dates.
Anyway, my old quad-core CPU can f.i. compute 6 million SHA256 hashes per second with SynCrypto, that's enough to brute-force the whole 42 days range of GetTickCount-based salted hashes in about 10 minutes, and a GPU brute-forcers could scan the whole range in a matter of seconds.
I.FromNow;
inc(I.Value,GetTickCount+PtrUInt(Sender));
Given the above, since I.FromNow will be guessable, GetTickCount range is limited, so the PtrUInt(Sender) is the only portion that strengthens the nonce, but the range isn't that huge and similar values will occur between runs of the executable (since the TSQLRestClientURI instance size is rather large, there is a good change it'll be allocated from a highly-aligned sub-allocator block in the memory manager)
Thanks. Client time stamp looks like a simple enough varying salt to validate.
I suppose some server-provided salt could also periodically be passed down to the client in the encrypted message to provide further strengthening.
What do you use for generating nonces in the field? The tests in mORMot use the Delphi Random function which is very weak and Randomize seeds exclusively on the machine time.
I would rather change the AES cypher key for every request, adding a random nonce at the beginning of the stream, then using it as salt for every AES key computation.
I see, even though the first AES block of a message is always 100% new random, and that random carries over the rest of the message through CFB, a message is "correct" in isolation and thus can be replayed.
However, that raises another question, to avoid the replay, it means that the nonce must be provided by the other side of the communication channel? Ie. for a client to server message, the client would have to use a nonce provided by the server, and vice-versa? (otherwise unless the server caches recent nonces, the client could replay by reusing the same nonce?)
Just a small post to ensure I haven't missed something obvious and I'm using everything "right"
The goal here is to establish a communication TCP channel, authenticated and encrypted by symmetric keys.
First data I send is a nonce of 16 bytes of random, followed by the HMAC_SHA256 of the connection key (implementation below) with the nonce as message. This is used to authenticate the client-side of the connection.
procedure HMAC_SHA256(const key : RawByteString; msgPtr : Pointer; msgLength : Integer; var result : TSHA256Digest);
var
i, n : Integer;
pad : array [0..31] of Byte;
sha : TSHA256;
firstPass : TSHA256Digest;
begin
n:=Length(key);
for i:=0 to n-1 do
pad[i]:=$36 xor Ord(key[i+1]);
for i:=n to High(pad) do
pad[i]:=$36;
sha.Init;
sha.Update(@pad, SizeOf(pad));
sha.Update(msgPtr, msgLength);
sha.Final(firstPass);
for i:=0 to n-1 do
pad[i]:=$5c xor Ord(key[i+1]);
for i:=n to High(pad) do
pad[i]:=$5c;
sha.Init;
sha.Update(@pad, SizeOf(pad));
sha.Update(@firstPass, SizeOf(firstPass));
sha.Final(Result);
end;Then for the rest of the stream, I'm using a TAESCFB, where the key is the output of SHA256Weak of the connection key (in case the users entered a weak key).
The initialization vector is static, and the TAESCFB is created only once for the whole duration of the connection, *but* each message sent down the wire is pre-padded with 16 bytes of random (new random generated for each message), and those bytes are ignored on the other end. The messages themselves are made of compressed content followed by a simple CRC32.
The random bytes for nonce & padding come from CryptGenRandom, and are further XOR-ed by a weak random function based on RDTSC, QueryPerformanceCounter & GetTickCount (to minimize vulnerability to automated hacks in case a weakness in CryptGenRandom were to be uncovered).
Anything obvious I missed?
Is anyone maintaining a standard public repository for mORMot?
git, svn, or anything else would do, or a bridge from fossil (like git-svn does between svn and git).
Currently I'm manually synchronizing with an internal SVN, but that's labor-intensive, and of course all the check-in history is lost (I end up with just "updated from mORMot" and similar comments of mine).
Also for open-source projects, it's a little bit complicated to have dependencies to mORMot, as the zip downloads are impractical, and fossil requires login/password, so everyone ends up with more or less outdated forks...
Nice job!
64bit compiler is quite stable IME, but the 64bit debugger can be a bit more problematic (at least in XE2)
A lot of the 64bit RTL is quite less efficient, several fastcode routines and previously (old) well-thought out RTL asm routines were replaced by Pascal ones that suffer from a mix of poor implementation/algorithmic choices and compiler optimization limitations. So comparatively, the Synopse routines should be even more preferable in 64bit.
I'm currently fighting against UniDAC + Zeos database backends, to integrate them with our SynDB classes.
Impressive stuff!
Now, back to SMS.
Following this from afar at the moment (spare time goes into improvements & fixes for 1.1).
With 1.1 there is some RTTI capability in SMS (class attributes, reading & writing published fields, invoking published properties getters & setters), it's rather raw and not wrapped up, but it's there ![]()
If I'm right, putting the DLL in the same folder as your executable will make it find 'first', independent of other SQLITE3.DLL's that may be on the system
If you use dynamic binding, you can load a specific DLL file in any particular path (it doesn't even have to be named '.dll').
I've used that to bundled DLLs as resources of EXE, then on startup they're extracted to the temp directory and loaded from there. If you create the DLL file with the temporary flag in Windows, it doesn't even really get written to the HDD, and you can use file locks to prevent other apps from accessing or modifying it.
That sidesteps the DLL and Windows built-in DLL resolution entirely.
What other compilers produce Delphi-compatible obj? I quickly looked a while ago, but without much success, if one of the top grade C compilers could be used, that could indeed be convenient.
FWIW the bundling of the dll in the exe is what I've been using for a while, there are two ways to do, one is to simply extract the resource to a temporary file (with a random name, that windows cleans up automatically), this works fine IME, never had any issues with anti-virus with it.
The other is to map the dll directly from the resource. I haven't tried it, this avoid the need to extract anything but requires some low-level wizardry.
I've ran a few tests between SynSQLite3 (that uses the .obj compiled by bcc32) and the "official" SQLite3.dll (3.7.15.1 on both sides)
The DLL is obviously compiled with a better C compiler, and it is executing queries about 25% faster overall.
Are there any plans to being able to use the dll instead of the obj? The dll could also be bundled as resource, and extracted as a temp file on startup, to avoid external dependencies)
By stateful I mean when you want to use the websocket not to push notifications, but to establish a connection to the server in which the actions related to a frame sent through the websocket aren't fully defined by that frame, but also defined by previous frames, and where that state isn't shared with other websockets (like in FTP or SMTP f.i.).
That makes a it a special case where the group consists of a single websocket (and then you only have to generate a unique name for the group, using Time+Random or whatever)
The concept of "client" wouldn't be part of the mechanism, it would be something you would add on top, and same goes for multiplexing on the same websocket.
For classic client-server I don't think WebSockets are really useful, as the browser will maintain connections (especially over SSL), and WebSockets frames have packaging as well that main not be wholly more efficient (unless you have large cookies...).
However WebSockets works well for pushing content and notifications, where it will have less server overhead than long polling, and less latency than periodic polling.
What I have in mind for websockets would basically be to attach them to a "named group", each named group would be linked to a processing (a script f.i.) and a set of in-memory properties. Any other server-side processing could post messages/content to a "named group", which would then be dispatched to all clients on the other side of the websockets.
This should AFAICT solve the need for push notifications very simply: just attach all the websockets to the same "named group" / notification channel.
And individual (stateful) websocket connections would be named groups with only one websocket in them.
I can provide support for XE3.
XE3 uses could be problematic due to the dotted namespaces, though as long as the aliases work, that should be okay (ie. not looking forwards to ifdef's in the uses clauses...)
Do you plan to add WebSockets support on HttpSys2 server side?
Eventually yes, though the relevant functionality was added in Win8/Win2012, and I have access to neither at the moment...
Do not know if here is the place to report, but know Eric will see it.
You can post in the issue tracker (http://code.google.com/p/dwscript/issues/list)
Eric, in order to compile the server (Delphi XE3) I have to correct following
This will require some ifdef'ing: in XE and previous versions, all those functions are declared as "var xxx : cardinal".
As I don't have XE3 to test, what should those ifdefs be?f.i. does this work in XE3?
{$if CompilerVersion < 24.0} // XE3
completionKey : DWORD;
{$else}
completionKey : DWORD_PTR;
{$ifend}Updated & simplified the wrappers.
I've added UIB driver, it's a bit heavier in terms of code size and dependencies, but full-featured and shows it's simple to wrap just any db layer.
Works all right AFAICT once the 'protected' are replaced by 'private' at the lines mentioned by Bojop
But I was not able to find out a similar issue in this case.
It was with SynDBODBC.
Compiler bug confirmed: issue comes and goes when building/rebuilding... and that's an "object" as in the other bug you linked.
Though since it uses inheritance and virtual methods, it can't be replaced by a record, but has to become a class, which means various other changes in the rest of the code to create/destroy manually, but that's probably the only option as compiler support for "object" is becoming weaker and weaker.
Could you send us your FreeIB layer? webcontact01 at synopse dot info
Sent.
Why did you specify SynDBODBC for DWS?
because that's the only unit I looked at initially ![]()
I've re-based on SynDB, I'll commit so you can take a look.
I'm getting a leak in simple statements, apparently TSQLDBStatementWithParamsAndColumns has a fColumn field of TDynArrayHashed that isn't freed, and that's the only leak I'm seeing... the FastMM4 log says
This block was allocated by thread 0x544, and the stack trace (return addresses) at the time was:
40495D [System.pas][System][@ReallocMem][3935]
409932 [System.pas][System][@DynArraySetLength][26579]
87A8C7 [SynCommons.pas][SynCommons][TDynArrayHashed.AddAndMakeUniqueName][19969]
8F0ED6 [SynDBODBC.pas][SynDBODBC][TODBCStatement.BindColumns][1082]
8F2393 [SynDBODBC.pas][SynDBODBC][TODBCStatement.Prepare][1441]
8F3B4A [dwsSynDBDatabase.pas][dwsSynDBDatabase][TdwsSynDBDataSet.Create][227]
8F3ABA [dwsSynDBDatabase.pas][dwsSynDBDatabase][TdwsSynDBDataBase.Query][211]
Firebird usually, Oracle & MS SQL for larger uses or when the customer already has licenses/admins, and SQLite for everything else.
For Firebird we used to use IBX a long time ago, but due to various bugs and bloat, we've fallen down to the FreeIB layer that IBX was built upon, with a few fixes, it's still running smoothly. There doesn't seem to be any official place for FreeIB anymore, or I would have published the fixes (even though these aren't extensive, and are essentially related to adding Unicode support and fixing minor blob issues), though I'm not sure what the Borland license headers mean (and so if those files are really redistributable from the Borland version, if the original open-source version should be used, or if headers should be remade from scratch from the C headers).
Btw, just added SynDBODBC wrapper, worked like a charm ![]()
If I were you, I would stay away from Zeos, or use DBExpress components.
The best solution could be some abstract interfaces, then several implementation classes targeting various DB providers.
I suspect that you will find out how SynDB*.pas unit are easy to work with.
Okay, good to know, I'll go directly for SynDB then!
We've been evolving our own DB connection layers over the years @work, so I haven't used any of the bundled Delphi DB components in years (except to test occasionally... and shake head in disbelief). Having a new source of fast & tested drivers is good!
Also you mentioned ORM, I've not looked into how you're tying mORMot to the servers yet, f.i. to have a ".dws" handler cooperate with a native Delphi mORMot handler.
I guess you're supposed to subclass, check the request, and then call inherited if the request is not handled? (if so, there would be nothing special required for me to make the dws http server compatible with other Delphi-based mORMot handlers)
Ok, I'll look into what's wrong.
At some point in time the Delphi TService support wasn't available in all Delphi editions, so that's why I went for mORMotService (and your versions was going to be lighter and more "fixable" anyway).
Is it just me or is service shutdown a bit "brutal" and you get messages when shutting down from the service manager? (Services.msc)
@ab: in dwsWindowsServices I added a couple features you may want to integrate - so I can remove my intermediate class
- one is the ability to set the service description, the other is to detect is the exe was launched by the SCM. This allows to make executables that can work both as application and as service (like DWSWebServer demo).
Thanks ![]()
For the HTTPS.SYS API version 2, I will certainly integrate it to Synopse, but perhaps with some syntax differences (e.g. using enumerations and sets for flags, instead of plain C constants).
You might want to start from the xxm header translation instead (http://sourceforge.net/p/xxm/code/240/t … tpapi2.pas), it's more complete.
I only found it while I was almost done... and had hacked my way through the minimal header requirements (so I don't have everything in the http.sys 2.0)
Note that some of your code already do not include fixes made for 64 bit compilation, I committed last days.
This is the limit of forks.
Well it was either fork or hack SynCrtSock to death because some methods and types were buried in the implementation section ![]()
And hacking to death would have been far more troublesome to keep sync'ed with your official version.
In the next release you'll split SynCrtSock in many smaller/simpler units so a new HttpAppi server can be subclassed more easily?
A TDataSet is a start, but we may benefit of something stronger, like an ORM.
I went for the minimal interface that would be both functional and allow wrapping various db techs ![]()
Blob support is still MIA and some things are going to change (DataType will become an enum, a DeclaredType with the raw db type string, and probably some minimal standardized metadata queries)
I currently have a wrapper for SynSQlite, our proprietary drivers, and I would like to add some more open-source drivers wrappers, like for ZeosLib?
I've never used ZeosLib though, but I've spotted it in Synopse directories, and noticed some recent updates to it. This would be mostly to add support for the usual suspects (MySQL, SQLServer, Oracle, Frebird & PostgresQL).
What about your direct SQL statements in .dws files?
Haven't started on it just yet, as I was wrapping up the server & setting up the minimal DB interfaces.
But this is certainly something I'll give a try, coupled with some JSON connector enhancements and beig able to expose script functions to SQLite, you could use it write things like
JSON.stringify(select field1, MyFunc(field2) from someTable where field3=@myVariable)Which would be not just convenient, but also would catch SQL syntax errors at compile time.
First version is out there ![]()
You'll need trunk latest DWScript & Synopse files, Win2008 or Vista or better (http.sys 2.0 requirement)
I made precompiled binary with mini demo site for those that want to test directly:
http://code.google.com/p/dwscript/downl … Server.zip
For config options and server doc, see http://code.google.com/p/dwscript/wiki/WebServer
At the moment telling notepad++ that .dws files are highlighted as html works "almost" well enough.
Demo includes a basic memory + cpu usage monitor, a minimal DB (SQLite) exemple, and some special cases.
Throttling (CPU and Bandwidth), SSL and NCSA logging are supported too.
Nice! Thanks ![]()
While I have your ear, my I abuse by asking for a FieldDeclaredTypeS? (sqlite3_column_decltype...)
function TSQLRequest.FieldDeclaredTypeS(Col: Integer): String;
var P: PUTF8Char;
begin
if cardinal(Col)>=cardinal(FieldCount) then
raise ESQLite3Exception.Create(RequestDB, SQLITE_RANGE);
P := pointer(sqlite3_column_decltype(Request,Col));
result := UTF8DecodeToString(P,SynCommons.StrLen(P));
end;Btw, any chance of supporting the WideChar variants in SQLite? ie sqlite3_bind_text16, sqlite3_column_text16, etc. or are they missing from the .obj?
Thanks for the extra check!
1) good point, eliminated
2) yes, one of the key reason behind the move to http.sys 2.0 is that authentication is supported in the kernel driver (not just faster and less code required, but also less trouble with service/application access rights)
I'm getting memory leaks with SynSQLite3 each time I open or close a DB, f.i. with just
procedure Test;
var
db : TSQLDatabase;
begin
db:=TSQLDatabase.Create(':memory:');
db.DBOpen;
db.DBClose;
db.Free;
end;The leaks come from sqlite3_memory_highwater through TSQLDatabase.DBOpen according to FastMM.
These are not one-time leaks, the more you call the above procedure, the more you leak. Any solutions?
I've got it working now, with logs & bandwidth throttling too (haven't tried authentication yet, nor any of the other properties). Most trouble I had was with a MS documentation bug on MSDN.
If you want to have a look, you can find the relevant files in DWScript SVN under Libraries\SimpleServer, though the rest of the demo in the SVN is WIP and doesn't use them yet, once I get everything in working order, I'll commit the rest.
Btw, I made a SetCompressHeader optimization that should be easy to backport (eliminates the temporary string).
Since library can be loaded dynamicaly, we may be able to include both entries if available.
Yes, though the code above currently makes no attempt at distinguishing between v1 & v2.
The snags with supporting both will be a change in the request/response record (they added a couple fields), and having all the v2 functions optional from v1.
That said, the changes from v1 to v2 are rather simple, with some code not requiring any change at all.
FWIW I've started an experimental fork to see how far I can go with Http API 2.0 support, I'll post the relevant files in the DWS SVN.
I've found a partial (but dirty) workaround by importing HttpCancelHttpRequest from http 2.0, and aborting the request when the headers have been received.
F.i. this will forbid any posts larger than 1kB
if InContentLength<>0 then begin
if InContentLength>1024 then begin
//SendError(412, 'Content-Length too large');
Http.CancelHttpRequest(fReqQueue, Req^.RequestId, nil);
continue;
end;It's a bit dirty because the request is canceled, so you can't send a response.
The alternative is to just fetch all the content in a rotating buffer and discard everything as it comes in, this allows sending the error response, but then that means your incoming bandwidth will have been eaten, so the cancel may not be that dirty (and you can catch the error on the client side if it's a legit post attempt).
Delving into it, I found Http 2.0 API includes a lot of useful stuff, like kernel-level authentication, static cache, logging, etc.
It ups the requirements to Vista or Windows 2008 though, but looks worth it if you're going to front the server on the wild web (otherwise, it's not too hard to DDOS an HttpAPI 1.0 server by sending in large simultaneous posts that'll keep the THttpApiServer.Execute threads busy eating all the RAM).
Are there any plans to up HttpAPI to 2.0 level?
If so, maybe HttpAPI support it should be taken out of the SynCrtSock unit, so it becomes more easy to pick one or the other by just using the relevant unit.
At a minimum, having an OnHeaderReceived event would be nice, so the above header-related processing could be handled in our code.
Is there a way to limit maximum upload size at the http.sys level? ie. before the Process event is called.
I'm mostly worried about limiting the amount of RAM attempts at large uploads could consume. I'm running a test server on a shoestring RAM budget, literally, think Ikoula's 1€ VMs and wanting to stay below 512 MB RAM ![]()
In IIS there are maxRequestLength and maxAllowedContentLength settings, what are the equivalent there? (quickly scanned the Http Server API, but couldn't find how you set them)
Also what about bandwidth limitations? (HttpServerBandwidthProperty)
Any body got experience with them?
3) bad performance under Windows virtual machine
Yep, noticed that.
Also it is single-threaded, and in my tests it reached 100% CPU utilisation of its core (ie. 25% on my quad-core), without having the Synopse web server maximized... so it was also measuring its own performance as a client rather than that of the server.
I tried to alleviate it by running it from different client machines at the same time, but that's not very practical.
mORMot is VERY FAST!
Yep! ![]()
Problem is, it's so fast we can't claim it's faster than the rest, because test clients aren't fast enough to differentiate...
Making a custom test client could alleviate that, but then it would raise issues of fairness of the test...
Any suggestions for a web server stress tool?
I had been using JMeter so far, but the current HttpAPI Server + DWScript is too fast on simple queries compared to JMeter, and I'm seeing a 10 to 1 cpu usage (10 for JMeter, 1 for the server), and I don't have 10 client machines to use to balance the client load ![]()
Did your own server uses IOCP?
Initially it was using events & signaling, got changed a couple years ago when I introduced IOCP-based worker threads and futures (aka promises).
Currently our DB layer is asynchronous too, and a few background caching and UI tasks have been converted too.
I'm quite sure LZRW1 will be slower than our SynLZ implementation
I tested here, and indeed it is! well done!
The compression is also better in all scenarios I tested (sometimes not by much, but always better).
I've just replaced LZRW1 with SynLZ for the internal test middle-ware here, it should be seeing a few gigabytes of LAN traffic in the next days ![]()
Unless I misunderstood SynLZ is LZab? (lempel-ziv-arnaud-bouchez i.e designed by you?)
a hashing limitation makes SynLZ sometimes unable to pack continuous blocks of same byte
What does that mean exactly? That it will crash or corrupt, or just that the compression ratio won't be good?
Using a parameter defined as a class has a very low overhead, in fact (from real profiling on our stubbing routines).
I'll see how to implement it.
Thinking on it, maybe the current THttpApiServer class could remain in a similar or "low level no bells nor whistles" fashion, and a new subclass be introduced with the extra http response/request class?
This would also have the benefit of "opening up" THttpApiServer a bit for subclassing (currently it can't really be sub-classed, as all the logic is private or in SynCrtSock's implementation)
And with the above in mind, it would be nice if the Process event weren't called directly, but rather called from a DoProcess virtual method, with would facilitate subclassing and adding custom processing before/after/in-place-of the request (such as standard http logs)