Purpose: Asynchronous Network Layer for Event-Driven Clients or Servers
- this unit is a part of the Open Source Synopse mORMot framework 2, licensed under a MPL/GPL/LGPL three license - see LICENSE.md
Unit Name | Description | |
---|---|---|
mormot.core.base | Framework Core Shared Types and RTL-like Functions | |
mormot.core.buffers | Framework Core Low-Level Memory Buffer Process | |
mormot.core.data | Framework Core Low-Level Data Processing Functions | |
mormot.core.datetime | Framework Core Low-Level Date and Time Support | |
mormot.core.json | Framework Core Low-Level JSON Processing | |
mormot.core.log | Framework Core Logging | |
mormot.core.os | Framework Core Low-Level Wrappers to the Operating-System API | |
mormot.core.perf | Framework Core Performance and Monitoring Classes | |
mormot.core.rtti | Framework Core Low-Level Cross-Compiler RTTI Definitions | |
mormot.core.search | Framework Core Text, Binary and Time Search Engines | |
mormot.core.text | Framework Core Low-Level Text Processing | |
mormot.core.threads | Framework Core Multi-Threading Support | |
mormot.core.unicode | Framework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion | |
mormot.core.zip | Framework Core Zip/Deflate Compression Support | |
mormot.crypt.secure | Framework Core Authentication and Security Features | |
mormot.net.client | HTTP/HTTPS Client Classes | |
mormot.net.http | HTTP/HTTPS Abstract Process Classes and Definitions | |
mormot.net.server | HTTP/HTTPS Server Classes | |
mormot.net.sock | Low-level access to the OperatingSystem Sockets API (e.g. WinSock2) |
Objects | Description | |
---|---|---|
EAsyncConnections | Exception associated with TAsyncConnection / TAsyncConnections process | |
EHttpAsyncConnections | Exception associated with Event-Driven HTTP Server process | |
TAsyncClient | Implements thread-pooled high-performance TCP multiple clients | |
TAsyncConnection | Abstract class to store one TAsyncConnections connection | |
TAsyncConnections | Implements an abstract thread-pooled high-performance TCP clients or server | |
TAsyncConnectionsSockets | Handle multiple non-blocking connections using TAsyncConnection instances | |
TAsyncConnectionsThread | Used to implement a thread poll to process TAsyncConnection instances | |
TAsyncServer | Implements a thread-pooled high-performance TCP server | |
THttpAsyncClientConnection | Handle one HTTP client connection handled by our non-blocking THttpAsyncServer | |
THttpAsyncClientConnections | Implement HTTP async client requests | |
THttpAsyncConnection | Abstract HTTP server or client connection to our non-blocking THttpAsyncServer | |
THttpAsyncConnections | Event-driven process of HTTP/WebSockets connections | |
THttpAsyncServer | HTTP server using non-blocking sockets | |
THttpAsyncServerConnection | Handle one HTTP server connection to our non-blocking THttpAsyncServer | |
THttpProxyDisk | Define disk cache settings of content for THttpProxyServer | |
THttpProxyMem | Define the caching settings of content for THttpProxyServer | |
THttpProxyServer | Implements a HTTP server with forward proxy and caching | |
THttpProxyServerMainSettings | Define the THttpProxyServer HTTP(S) server settings | |
THttpProxyServerSettings | Define the THttpProxyServer forward proxy process | |
THttpProxyUrl | Define one URL content setting for THttpProxyServer | |
TPollAsyncConnection | Abstract parent to store information aboout one TPollAsyncSockets connection | |
TPollAsyncConnections | Thread-safe storage of several connections | |
TPollAsyncSockets | Read/write buffer-oriented process of multiple non-blocking connections |
TPollAsyncConnection = class(TSynPersistent)
Abstract parent to store
information aboout one TPollAsyncSockets
connection
destructor Destroy; override;
Finalize the instance
function IsClosed: boolean;
Quick check if this instance is still open
function IsDangling: boolean;
Quick check if this instance seems still active, i.e. its Handle
<> 0
function Recv(buf: pointer; var len: integer): TNetResult;
Receive some buffer from the connection, using TLS if possible
function ReleaseMemoryOnIdle: PtrInt;
Called after TAsyncConnections.LastOperationReleaseMemorySeconds
function Send(buf: pointer; var len: integer): TNetResult;
Send some buffer to the connection, using TLS if possible
function TryLock(writer: boolean): boolean;
Acquire an exclusive R/W access to this connection
- returns true if connection has been acquired, setting the wasactive flag
- returns false if it is used by another thread
function WaitLock(writer: boolean; timeoutMS: cardinal): boolean;
Try to acquire an exclusive R/W access to this connection
- returns true if connection has been acquired
- returns false if it is used by another thread, after the timeoutMS period
- only with writer=true after a locked read + process, so unlikely to sleep
procedure UnLock(writer: boolean);
Release exclusive R/W access to this connection
procedure UnLockFinal(writer: boolean);
Release all R/W nested locks
- used when the connection is closed and inactive
property Handle: TPollAsyncConnectionHandle read fHandle;
Read-only access to the handle
number associated with this connection
property Secure: INetTls read fSecure;
Read-only access to the low-level TLS context
property Socket: TNetSocket read fSocket;
Read-only access to the socket
number associated with this connection
TPollAsyncConnections = record
Thread-safe storage of several connections
- use e.g. by TPollAsyncSockets.ProcessWaitingWrite or to implement generational garbage collector of TAsyncConnection
instances
TPollAsyncSockets = class(TObject)
Read/write buffer-oriented process of multiple non-blocking connections
- to be used e.g. for stream protocols (e.g. WebSockets or IoT communication)
- assigned sockets will be set in non-blocking mode, so that polling will work as expected: you should then never use direclty the socket (e.g. via blocking TCrtSocket
), but rely on this class for asynchronous process: TPollAsyncConnection.OnRead() overriden method will receive all incoming data from input buffer, and Write() should be called to add send some data, potentially asynchronous with an internal buffer
- ProcessRead/ProcessWrite methods are to be run for actual communication: either you call those methods from multiple threads, or you run them in loop from a single thread, then define a TSynThreadPool
for running any blocking process (e.g. computing requests answers) from OnRead callbacks
constructor Create(aOptions: TPollAsyncSocketsOptions; aThreadCount: integer); virtual;
Pending soWaitWrite initialize the read/write sockets polling
- fRead and fWrite
TPollSocketsBuffer instances will track pseRead or pseWrite events, and maintain input and output data buffers
destructor Destroy; override;
Finalize buffer-oriented sockets polling, and release all used memory
function ProcessRead(Sender: TSynThread; const notif: TPollSocketResult): boolean;
One or several threads should execute this method
- thread-safe handle of any notified incoming packet
- return true if something has been read or closed, false to retry later
function Start(connection: TPollAsyncConnection): boolean; virtual;
Assign a new connection to the internal reading poll
- the TSocket handle will be set in non-blocking mode from now on - it is not recommended to access it directly any more, but use Write() and handle OnRead() callback
- fRead will poll incoming packets, then call OnRead to handle them, or Unsubscribe and delete the socket when pseClosed is notified
- fWrite
will poll for outgoing packets as specified by Write(), then send any pending data once the socket is ready
- any manual call of Start
() should ensure the connection is non-blocking
function Stop(connection: TPollAsyncConnection; const caller: shortstring): boolean; virtual;
Remove a connection from the internal poll, and shutdown its socket
- most of the time, the connection is released by OnClosed when the other end shutdown the socket; but you can explicitly call this method when the connection (and its socket) is to be shutdown
- this method won't call OnClosed, since it is initiated by the class
function Write(connection: TPollAsyncConnection; data: pointer; datalen: integer; timeout: integer = 5000): boolean; virtual;
Add some data to the asynchronous output buffer of a given connection
- this method may block if the connection is currently writing from another thread (which is not possible from TPollAsyncSockets.Write
), up to timeout milliseconds
function WriteString(connection: TPollAsyncConnection; const data: RawByteString; timeout: integer = 5000): boolean;
Add some data to the asynchronous output buffer of a given connection
procedure ProcessWrite(const notif: TPollSocketResult; sent: integer);
One thread should execute this method with the proper pseWrite notif
- thread-safe handle of any outgoing packets
- sent is the number of bytes already sent from connection.fWr buffer, e.g. via TWinIocp.PrepareNext
(wieSend)
procedure Terminate(waitforMS: integer);
Notify internal socket polls to stop
their polling loop ASAP
property Count: integer read GetCount;
How many connections are currently managed by this instance
property Iocp: TWinIocp read fIocp;
Low-level access to the IOCP
polling class used for all events
property OnFirstRead: TOnPollAsyncProc read fOnFirstRead write fOnFirstRead;
Event called on first ProcessRead
() on a given connection
- is assigned e.g. to TAsyncServer.OnFirstReadDoTls to setup the TLS in one sub-thread of the thread pool
property OnStart: TOnPollAsyncFunc read fOnStart write fOnStart;
Event called on Start
() method success
- warning: this callback should be very quick because it is blocking
property OnStop: TOnPollAsyncProc read fOnStop write fOnStop;
Event called on Stop
() method success
- warning: this callback should be very quick because it is blocking
property Options: TPollAsyncSocketsOptions read fOptions write fOptions;
Some processing options
property ReadBytes: Int64 read fReadBytes;
How many data bytes have been received by this instance
property ReadCount: Int64 read fReadCount;
How many times data has been received by this instance
property ReadWaitMs: integer read fReadWaitMs write fReadWaitMs;
Enable WaitFor() during recv() in ProcessRead
- may enhance responsiveness especially on HTTP
/1.0 connections
- equals 0 ms by default, but could be tuned e.g. to 50 or 100 if needed
- use with care: performance degrades with highly concurrent HTTP
/1.1
property WriteBytes: Int64 read fWriteBytes;
How many data bytes have been sent by this instance
property WriteCount: Int64 read fWriteCount;
How many times data has been sent by this instance
EAsyncConnections = class(ESynException)
Exception associated with TAsyncConnection
/ TAsyncConnections
process
TAsyncConnection = class(TPollAsyncConnection)
Abstract class to store
one TAsyncConnections
connection
- may implement e.g. WebSockets frames, or IoT binary protocol
- each connection will be identified by a TPollAsyncConnectionHandle
integer
- idea is to minimize the resources used per connection, and allow full customization of the process by overriding the OnRead virtual method (and, if needed, AfterCreate/AfterWrite/BeforeDestroy/OnLastOperationIdle)
constructor Create(aOwner: TAsyncConnections; const aRemoteIP: TNetAddr); reintroduce; virtual;
Initialize this instance
procedure Recycle(const aRemoteIP: TNetAddr); virtual;
Reuse this instance for a new incoming connection
property Owner: TAsyncConnections read fOwner;
Read-only access to the associated connections list
property RemoteIP: RawUtf8 read fRemoteIP;
The associated remote IP4/IP6, as text
TAsyncConnectionsSockets = class(TPollAsyncSockets)
Handle multiple non-blocking connections using TAsyncConnection
instances
function Write(connection: TPollAsyncConnection; data: pointer; datalen: integer; timeout: integer = 5000): boolean; override;
Add some data to the asynchronous output buffer of a given connection
- this overriden method will also log the write operation if needed
- can be executed from an TAsyncConnection.OnRead method
property Total: integer read GetTotal;
How many connections have been handled by the poll, from the beginning
TAsyncConnectionsThread = class(TSynThread)
Used to implement a thread poll to process TAsyncConnection
instances
constructor Create(aOwner: TAsyncConnections; aProcess: TAsyncConnectionsThreadProcess; aIndex: integer); reintroduce;
Initialize the thread
destructor Destroy; override;
Finalize the thread resources
property CustomObject: TObject read fCustomObject write fCustomObject;
A TObject instance which will be owned by this thread once assigned
- Destroy
will delete it when needed
- could be used to maintain some thread-speficic resource, e.g. a raw DB connection or a (set of) COM object(s)
property Index: integer read fIndex;
When used as a thread pool, the number of this thread
property Name: RawUtf8 read fName;
The low-level thread name
property Process: TAsyncConnectionsThreadProcess read fProcess;
Which kind of ProcessRead or ProcessWrite this thread is doing
TAsyncConnections = class(TNotifiedThread)
Implements an abstract thread-pooled high-performance TCP clients or server
- internal TAsyncConnectionsSockets
will handle high-performance process of a high number of long-living simultaneous connections
- will use a TAsyncConnection
inherited class to maintain connection state
- don't use this abstract class but either TAsyncServer
or TAsyncClient
- under Linux/POSIX, check your "ulimit -H -n" value: one socket consumes two file descriptors: you may better add the following line to your /etc/limits.conf or /etc/security/limits.conf system file:
* hard nofile 65535
constructor Create(const OnStart, OnStop: TOnNotifyThread; aConnectionClass: TAsyncConnectionClass; const ProcessName: RawUtf8; aLog: TSynLogClass; aOptions: TAsyncConnectionsOptions; aThreadPoolCount: integer); reintroduce; virtual;
Initialize the multiple connections
- don't use this constructor but inherited client/server classes
destructor Destroy; override;
Shut down and finalize the instance, calling Shutdown
function ConnectionFind(aHandle: TPollAsyncConnectionHandle): TAsyncConnection;
High-level access to a connection
instance, from its handle
- use efficient O(log
(n)) binary search
- this method won't keep the main Lock, but this class will ensure that the returned pointer will last for at least 100ms until Free is called
function ConnectionFindAndLock(aHandle: TPollAsyncConnectionHandle; aLock: TRWLockContext; aIndex: PInteger = nil): TAsyncConnection;
High-level access to a connection
instance, from its handle
- use efficient O(log
(n)) binary search
- could be executed e.g. from a TAsyncConnection.OnRead method
- raise an exception if acoNoConnectionTrack option was defined
- returns nil if the handle was not found
- returns the maching instance, and caller should release the lock as:
try ... finally UnLock(aLock); end;
function ConnectionRemove(aHandle: TPollAsyncConnectionHandle): boolean;
Remove an handle from the internal list, and close its connection
- raise an exception if acoNoConnectionTrack option was defined
- could be executed e.g. from a TAsyncConnection.OnRead method
function LockedConnectionSearch(aHandle: TPollAsyncConnectionHandle): TAsyncConnection;
Low-level access to a connection
instance, from its handle
- use efficient O(log
(n)) binary search, since handles are increasing
- caller should have called Lock before this method is done
function ThreadClientsConnect: TAsyncConnection;
Low-level method to connect a client to this server
- is called e.g. from fThreadClients
function Write(connection: TAsyncConnection; data: pointer; datalen: integer; timeout: integer = 5000): boolean;
Add some data to the asynchronous output buffer of a given connection
- could be executed e.g. from a TAsyncConnection.OnRead method
function WriteString(connection: TAsyncConnection; const data: RawByteString; timeout: integer = 5000): boolean;
Add some data to the asynchronous output buffer of a given connection
- could be executed e.g. from a TAsyncConnection.OnRead method
procedure EndConnection(connection: TAsyncConnection);
Call ConnectionRemove
unless acoNoConnectionTrack is set
procedure LogVerbose(connection: TPollAsyncConnection; const ident: RawUtf8; const identargs: array of const; frame: pointer; framelen: integer); overload;
Log
some binary data with proper escape
- can be executed from an TAsyncConnection.OnRead method to track content:
if acoVerboseLog in Sender.Options then Sender.LogVerbose(self,...);
procedure LogVerbose(connection: TPollAsyncConnection; const ident: RawUtf8; const identargs: array of const; const frame: TRawByteStringBuffer); overload;
Log
some binary data with proper escape
- can be executed from an TAsyncConnection.OnRead method to track content:
if acoVerboseLog in Sender.Options then Sender.LogVerbose(...);
procedure SetCpuAffinity(CpuIndex: integer);
Ensure all threads
of the pool is bound to a given CPU core
- may lower performance, but reduce global consumption
procedure SetOnIdle(const aOnIdle: TOnPollSocketsIdle; Remove: boolean = false);
Add or remove a callback run from ProcessIdleTix() internal method
- all callbacks will be triggered once with Sender=nil at shutdown
procedure SetSocketAffinity(SocketIndex: integer);
Ensure all threads
of the pool is bound to a given CPU HW socket
- may enhance performance on multi-socket systems
procedure Shutdown; virtual;
Shut down the instance, releasing all associated threads
and sockets
property Clients: TAsyncConnectionsSockets read fClients;
Access to the TCP client sockets poll
- TAsyncConnection.OnRead should rather use Write() and LogVerbose
() methods of this TAsyncConnections
class instead of using Clients
property Connection: TAsyncConnectionDynArray read fConnection;
Low-level unsafe direct access to the connection
instances
- ensure this property is used in a thread-safe manner, i.e. calling ConnectionFindAndLock
() high-level function, ot via manual
ConnectionLock.ReadOnlyLock; try ... finally ConnectionLock.ReadOnlyUnLock; end;
property ConnectionClass: TAsyncConnectionClass read fConnectionClass write fConnectionClass;
Direct access to the class instantiated for each connection
- as supplied to the constructor, but may be overriden just after startup
property ConnectionCount: integer read fConnectionCount;
Current HTTP
/1.1 / WebSockets connections count
- this is the number of long-living connections - may not appear just after accept, so never for a HTTP
/1.0 short-living request
property ConnectionHigh: integer read fConnectionHigh;
Maximum number of concurrent long-living connections since started
property ConnectionLock: TRWLock read fConnectionLock;
Access to the R/W lock protecting the Connection
[] array
- will WriteLock/block only on connection
add/remove
property KeepConnectionInstanceMS: cardinal read fKeepConnectionInstanceMS write fKeepConnectionInstanceMS;
How many milliseconds a TAsyncConnection
instance is kept alive after closing
- default is 100 ms before the internal GC calls Free on this instance
property LastOperationIdleSeconds: cardinal read fLastOperationIdleSeconds write fLastOperationIdleSeconds;
Will execute TAsyncConnection.OnLastOperationIdle after an idle period
- could be used to send heartbeats after read/write inactivity
- equals 0 (i.e. disabled) by default
property LastOperationReleaseMemorySeconds: cardinal read fLastOperationReleaseMemorySeconds write fLastOperationReleaseMemorySeconds;
Allow idle connection
to release its internal Connection.rd/wr buffers
- default is 60 seconds, which is pretty conservative
- could be tuned in case of high numbers of concurrent connections and constrained memory, e.g. with a lower value like 2 seconds
property LastOperationSec: TAsyncConnectionSec read fLastOperationSec;
The current monotonic time elapsed, evaluated in seconds
- IdleEverySecond will set GetTickCount64
div 1000
property Log: TSynLogClass read fLog;
Access to the associated log
class
property Options: TAsyncConnectionsOptions read fOptions write fOptions;
Allow to customize low-level options
for processing
property ThreadPoolCount: integer read fThreadPoolCount;
How many read threads
there are in this thread pool
property Threads: TAsyncConnectionsThreads read fThreads;
Direct access to the internal AsyncConnectionsThread`s
TAsyncServer = class(TAsyncConnections)
Implements a thread-pooled high-performance TCP server
- will use a TAsyncConnection
inherited class to maintain connection state for server process
constructor Create(const aPort: RawUtf8; const OnStart, OnStop: TOnNotifyThread; aConnectionClass: TAsyncConnectionClass; const ProcessName: RawUtf8; aLog: TSynLogClass; aOptions: TAsyncConnectionsOptions; aThreadPoolCount: integer); reintroduce; virtual;
Run the TCP server
, listening on a supplied IP port
- aThreadPoolCount = 1 is fine if the process is almost non-blocking, like our mormot.net.rtsphttp relay - but not e.g. for a REST/SOA server
- with aThreadPoolCount > 1, a thread will do atpReadPoll, and all other threads will do atpReadPending for socket reading and processing the data
- there will always be two other threads, one for Accept() and another for asynchronous data writing (i.e. sending to the socket)
- warning: should call WaitStarted
() to let Execute bind and run
- for TLS support, set acoEnableTls, and once WaitStarted
() returned, set Server.TLS.CertificateFile/PrivateKeyFile/PrivatePassword properties and call Server.DoTlsAfter(cstaBind)
destructor Destroy; override;
Shut down the server
, releasing all associated threads and sockets
procedure Shutdown; override;
Prepare the server
finalization
procedure WaitStarted(seconds: integer);
To be called just after Create
to wait for Execute to Bind
- will raise an exception on timeout, or if the binding failed
- needed only for raw protocol implementation: THttpServerGeneric
will have its own WaitStarted
method
property Accepted: Int64 read fAccepted;
How many connections have been accepted
since server
startup
- ConnectionCount is the number of long-living connections, this counter is the absolute number of successful accept() calls, including short-living (e.g. HTTP
/1.0) connections
property MaxConnections: integer read fMaxConnections write fMaxConnections;
Above how many active connections accept() would reject
- MaxPending
applies to the actual thread-pool processing activity, whereas MaxConnections
tracks the number of connections even in idle state
property MaxPending: integer read fMaxPending write fMaxPending;
Above how many fClients.fRead.PendingCount accept() would reject
- is mapped by the high-level THttpAsyncServer.HttpQueueLength property
- default is 10000, but could be a lower value e.g. for a load-balancer
- MaxConnections
regulates the absolute number of (idle) connections, whereas this property tracks the actual REST/HTTP
requests pending for the internal thread pool
property Server: TCrtSocket read fServer;
Access to the TCP server
socket
TAsyncClient = class(TAsyncConnections)
Implements thread-pooled high-performance TCP multiple clients
- e.g. to run some load stress tests with optimized resource use
- will use a TAsyncConnection
inherited class to maintain connection state of each connected client
constructor Create(const aServer, aPort: RawUtf8; aClientsCount, aClientsTimeoutSecs: integer; const OnStart, OnStop: TOnNotifyThread; aConnectionClass: TAsyncConnectionClass; const ProcessName: RawUtf8; aLog: TSynLogClass; aOptions: TAsyncConnectionsOptions; aThreadPoolCount: integer = 1); reintroduce; virtual;
Start the TCP client connections, connecting to the supplied IP server
property Port: RawUtf8 read fThreadClients.Port;
property Server: RawUtf8 read fThreadClients.Address;
Server
IP address
EHttpAsyncConnections = class(EAsyncConnections)
Exception associated with Event-Driven HTTP
Server process
THttpAsyncConnection = class(TAsyncConnection)
Abstract HTTP
server or client connection to our non-blocking THttpAsyncServer
THttpAsyncClientConnection = class(THttpAsyncConnection)
Handle one HTTP
client connection handled by our non-blocking THttpAsyncServer
- used e.g. for efficient reverse
proxy support with another server
property OnStateChanged: TOnHttpClientAsync read fOnStateChanged;
Access to the associated progress event callback
property ResponseStatus: integer read fResponseStatus;
Server response HTTP
status code (e.g. 200)
property Tls: TNetTlsContext read fTls write fTls;
Associated TLS
options and informations
THttpAsyncServerConnection = class(THttpAsyncConnection)
Handle one HTTP
server connection to our non-blocking THttpAsyncServer
function GetConnectionOpaque: PHttpServerConnectionOpaque;
Access to the internal two PtrUInt
tags of this connection
- may return nil e.g. behind a nginx proxy
procedure Recycle(const aRemoteIP: TNetAddr); override;
Reuse this instance for a new incoming connection
THttpAsyncConnections = class(TAsyncServer)
Event-driven process of HTTP
/WebSockets connections
property Banned: THttpAcceptBan read fBanned;
Set if hsoBan40xIP has been defined
- indicates e.g. how many accept() have been rejected from their IP
- you can customize its behavior once the server is started by resetting its Seconds/Max/WhiteIP properties, before any connections are made
THttpAsyncClientConnections = class(TSynPersistent)
Implement HTTP
async client requests
- reusing the threads pool and sockets polling of an associated TAsyncConnections
instance (typically a THttpAsyncServer
)
constructor Create(aOwner: TAsyncConnections; aConnectionTimeoutSec: integer); reintroduce;
Initialize the instance for a given TAsyncConnections
- connections will be kept alive up to aConnectionTimeoutSec seconds, ready to be reused
function StartRequest(const aUrl, aMethod, aHeaders: RawUtf8; const aOnStateChanged: TOnHttpClientAsync; aTls: PNetTlsContext; const aDestFileName: TFileName; out aConnection: THttpAsyncClientConnection; aOnStateChange: TOnHttpClientStates = [low(TOnHttpClientState) .. high(TOnHttpClientState)]): TNetResult;
Start an async connection to a remote HTTP
server using a callback
- the aOnStateChanged event will be called after each http.State change
procedure Shutdown;
Called to notify that the main process is about to finish
property UserAgent: RawUtf8 read fUserAgent write fUserAgent;
Allow to customize the User-Agent used by each client connection
THttpAsyncServer = class(THttpServerSocketGeneric)
HTTP
server using non-blocking sockets
constructor Create(const aPort: RawUtf8; const OnStart, OnStop: TOnNotifyThread; const ProcessName: RawUtf8; ServerThreadPoolCount: integer = 32; KeepAliveTimeOut: integer = 30000; ProcessOptions: THttpServerOptions = []); override;
'WinIocp' create
an event-driven HTTP
Server
destructor Destroy; override;
Finalize the HTTP
Server
function Clients: THttpAsyncClientConnections;
Access async
connections to any remote HTTP
server
- will reuse the threads pool and sockets polling of this instance
property Async: THttpAsyncConnections read fAsync;
Direct access to the internal high-performance TCP server
- you could set e.g. Async.MaxConnections or Async.Banned properties
property HeadersDefaultBufferSize: integer read fHeadersDefaultBufferSize write fHeadersDefaultBufferSize;
Initial capacity of internal per-connection Headers buffer
- 2 KB by default is within the mormot.core.fpcx64mm SMALL blocks limit so will use up to 3 locks before contention
property HeadersMaximumSize: integer read fHeadersMaximumSize write fHeadersMaximumSize;
Maximum allowed size in bytes of incoming headers
- is set to 64KB by default, which seems conservative enough
property RequestClass: THttpServerRequestClass read fRequestClass write fRequestClass;
The class used for each THttpServerRequest
instances
THttpProxyMem = class(TSynPersistent)
Define the caching settings of content for THttpProxyServer
- set the memory cache settings if used as exact THttpProxyMem
class
constructor Create; override;
Parsed fIgnoreCsv, fForceCsv setup the default values of this cache
function FromUri(const uri: TUriMatchName): THttpProxyCacheKind;
Check the IgnoreCsv
and ForceCSv
properties against a given URI
property ForceCsv: RawUtf8 read fForceCsv write fForceCsv;
CSV list of GLOB file names to be included in this cache even if its size does not match MaxSize
- e.g. '*.xml'
property IgnoreCsv: RawUtf8 read fIgnoreCsv write fIgnoreCsv;
CSV list of GLOB file names to be excluded to this cache
- e.g. '*.changelog,*.tmp'
property MaxSize: Int64 read fMaxSize write fMaxSize;
Size (in bytes) below which the file should be included in this cache
- default -1 will use the main THttpProxyServerSettings
value
property TimeoutSec: integer read fTimeoutSec write fTimeoutSec;
How many seconds this file should remain in this cache
- default -1 will use the main THttpProxyServerSettings
value
THttpProxyDisk = class(THttpProxyMem)
Define disk cache settings of content for THttpProxyServer
property Path: TFileName read fPath write fPath;
Default '' will use the main THttpProxyServerSettings
value
THttpProxyUrl = class(TSynAutoCreateFields)
Define one URL content setting for THttpProxyServer
constructor Create; override;
Setup the default values of this URL
destructor Destroy; override;
Finalize this instance
property CacheControlMaxAgeSec: integer read fCacheControlMaxAgeSec write fCacheControlMaxAgeSec;
Support optional "Cache-Control: max-age=..." header timeout value
- default 0 value will disable this header transmission
property Disabled: boolean read fDisabled write fDisabled;
This source
won't be processed if this property is set to true
property DiskCache: THttpProxyDisk read fDiskCache write fDiskCache;
Overwrite the main DiskCache
setting to tune on-disk caching
- disk cache is available only for remote URI lookups, i.e. if Source
is defined as 'http
://...' and not as a local file
property IfModifiedSince: boolean read fIfModifiedSince write fIfModifiedSince;
Handle "if-modified-since:" client header as 304 HTTP_NOTMODIFIED
- default true will support 304 results against the resource timestamp
property MemCache: THttpProxyMem read fMemCache write fMemCache;
Overwrite the main MemCache
setting to tune in-memory caching
- can be used for both local file or remote URI lookups
property Methods: TUriRouterMethods read fMethods write fMethods;
Which methods
are applied to the local Source
folder or relayed to the Remote server
- equals by default [urmGet, urmHead]
property RejectCsv: RawUtf8 read fRejectCsv write fRejectCsv;
CSV list of GLOB file or directly names to be rejected as not found
- e.g. '*.secret'
property Source: RawUtf8 read fSource write fSource;
A local folder name or remote origin URL
to ask
- if Source
is a local folder (e.g. 'd:/mysite' or '/var/www/mysite'), the Url
prefix chars will be removed from the client request, then used to locate the file to be served
- if Source
is a remote URI (like http
://....), the Url
prefix chars will be removed from the client request, then appended to this remote URI, which is e.g. 'http
://ftp.debian.org/debian' or 'http
://security.debian.org/debian-security' matching Local 'debian' or 'debian-security' prefixes, to compute a source
remote URI
property Url: RawUtf8 read fUrl write fUrl;
The local URI prefix to use with the main HTTP
(S) server of this instance
- a typical value is e.g. 'debian' for 'http
://ftp.debian.org/debian'
THttpProxyServerMainSettings = class(TSynAutoCreateFields)
Define the THttpProxyServer
HTTP
(S) server settings
constructor Create; override;
Initialize the default settings
function SetupTls(var tls: TNetTlsContext): boolean;
Assign the HTTPS/TLS settings to a context
property CACertificatesFile: TFileName read fCACertificatesFile write fCACertificatesFile;
Optional HTTPS certificates authorities file
property CertificateFile: TFileName read fCertificateFile write fCertificateFile;
Optional HTTPS certificate file name
- should also set PrivateKeyFile
and PrivateKeyPassword
property FaviconFile: TFileName read fFaviconFile write fFaviconFile;
Optional alternate favicon.ico file name
property Log: THttpLoggerSettings read fLog write fLog;
Custom log
settings for the psoEnableLogging option
- e.g. to override default LOGFORMAT_COMBINED
output, or rotation settings
property Options: THttpProxyServerOptions read fOptions write fOptions;
Customize this proxy cache HTTP
/HTTPS process
property Port: RawUtf8 read fPort write fPort;
The local port
used for HTTP
/HTTPS content delivery
- is '8098' by default (THttpPeerCache
uses 8099), unassigned by IANA
- you can bind to a specific 'IP:port
' if needed
property PrivateKeyFile: TFileName read fPrivateKeyFile write fPrivateKeyFile;
Optional HTTPS private key file name
property PrivateKeyPassword: SpiUtf8 read fPrivateKeyPassword write fPrivateKeyPassword;
Optional HTTPS private key file password
property ServerName: RawUtf8 read fServerName write fServerName;
Optional Server name for HTTP
/HTTPS
- to overwrite the default value set by the framework e.g. 'mORMot2 (Linux)'
property ThreadCount: integer read fThreadCount write fThreadCount;
The number of threads of the HTTP
/HTTPS content delivery
- default value is 4 sub-threads which is enough to scale well if no content is to be generated
THttpProxyServerSettings = class(TSynAutoCreateFields)
Define the THttpProxyServer
forward proxy process
constructor Create; override;
Initialize the default settings
procedure AddFolder(const folder: TFileName; const uri: RawUtf8 = ''; RaiseExceptionOnNonExistingFolder: ExceptionClass = nil);
Create
a THttpProxyUrl
definition to serve a local static folder
- if optional ExceptionClass
is supplied, the local folder should exist
procedure AddUrl(one: THttpProxyUrl);
Append
and own a given THttpProxyUrl
definition at runtime
- this instance will be stored and owned in Url
[] array
property DiskCache: THttpProxyDisk read fDiskCache write fDiskCache;
Default on-disk local cache settings
- can be overriden by Url
[].DiskCache
property
property MemCache: THttpProxyMem read fMemCache write fMemCache;
Default in-memory cache settings
- is set to MaxSize = 4KB and TimeoutSec = 5 minutes
- can be overriden by Url
[].MemCache
property
property Server: THttpProxyServerMainSettings read fServer write fServer;
Define the HTTP
/HTTPS server
configuration
property Url: THttpProxyUrlObjArray read fUrl;
Define the remote content sources
THttpProxyServer = class(TSynAutoCreateFields)
Implements a HTTP
server with forward proxy and caching
constructor Create(aSettings: THttpProxyServerSettings); reintroduce; virtual;
Initialize this forward proxy instance
- the supplied aSettings should be owned by the caller (e.g from a main settings
class instance)
destructor Destroy; override;
Finalize this class instance
procedure Start(const aPrivateKeyPassword: SpiUtf8 = '');
Actually start
the HTTP
/HTTPS server
- you can specify a private key password if not already in Settings
- may raise some exceptions if the HTTP
server
cannot be started
procedure Stop;
Finalize the HTTP
/HTTPS server
property Server: THttpAsyncServer read fServer;
The local HTTP
(S) asynchronous server
property Settings: THttpProxyServerSettings read fSettings;
Access to the used settings
TAsyncConnectionClass = class of TAsyncConnection;
Meta-class of one TAsyncConnections
connection
TAsyncConnectionDynArray = array of TAsyncConnection;
Used to store
a dynamic array of TAsyncConnection
TAsyncConnectionSec = type cardinal;
32-bit type used to store
GetTickCount64
div 1000 values
- as used e.g. by TAsyncConnection.fLastOperation
TAsyncConnectionsOptions = set of ( acoOnErrorContinue, acoNoLogRead, acoNoLogWrite, acoVerboseLog, acoWritePollOnly, acoDebugReadWriteLog, acoNoConnectionTrack, acoEnableTls, acoThreadCpuAffinity, acoThreadSocketAffinity, acoReusePort, acoThreadSmooting );
Low-level options for TAsyncConnections
processing
- TAsyncConnectionsSockets.OnError will shutdown the connection on any error, unless acoOnErrorContinue is defined
- acoNoLogRead and acoNoLogWrite could reduce the log verbosity
- acoVerboseLog will log transmitted frames content, for debugging purposes
- acoWritePollOnly will be translated into paoWritePollOnly on server
- acoDebugReadWriteLog would make
low-level send/receive logging
- acoNoConnectionTrack would force to by-pass the internal Connections list if it is not needed - not used by now
- acoEnableTls flag for TLS support, via Windows SChannel or OpenSSL 1.1/3.x
- either acoThreadCpuAffinity or acoThreadSocketAffinity could be set: the first for thread affinity to one CPU logic core, the 2nd for affinity to all logical cores of each CPU HW socket (both exclusive)
- acoReusePort will set SO_REUSEPORT on POSIX, allowing to bind several TAsyncConnections
on the same port, either within the same process, or as separated processes (e.g. to set process affinity to one CPU HW socket)
- acoThreadSmooting will change the ThreadPollingWakeup() algorithm to focus the process on the first threads of the pool - by design, this setting will disable both acoThreadCpuAffinity and acoThreadSocketAffinity
TAsyncConnectionsThreadProcess = ( atpReadPending );
TAsyncConnectionsThread.Execute will directly call TWinIocp.GetNext
()
TAsyncConnectionsThreads = array of TAsyncConnectionsThread;
Dynamic array of TAsyncConnectionsThread
instances
THttpAsyncConnectionsClass = class of THttpAsyncConnections;
Meta-class of THttpAsyncConnections
type
THttpProxyCacheKind = set of ( pckIgnore, pckForce);
The result of THttpProxyMem.FromUri
THttpProxyServerOption = ( psoLogVerbose, psoExcludeDateHeader, psoHttpsSelfSigned, psoReusePort, psoEnableLogging, psoDisableMemCache, psoNoFolderHtmlIndex, psoDisableFolderHtmlIndexCache, psoPublishSha256, psoPublishMd5 );
The available high-level options for THttpProxyServerMainSettings
THttpProxyServerOptions = set of THttpProxyServerOption;
A set of available options for THttpProxyServerMainSettings
THttpProxyUrlObjArray = array of THttpProxyUrl;
Define one or several remote content source(s) for THttpProxyServer
TOnHttpClientAsync = function(state: TOnHttpClientState; connection: THttpAsyncClientConnection): TPollAsyncSocketOnReadWrite of object;
Callback used e.g. by THttpAsyncClientConnection.OnStateChanged
- should return soContinue on success, or anything else to abort/close
- eventually hrsResponseDone or one hrsError* will mark the end of process
TOnHttpClientState = ( hcsBeforeTlsHandshake, hcsAfterTlsHandshake, hcsBeforeSendHeaders, hcsAfterSendHeaders, hcsReadStateChanged, hcsHeadersReceived, hcsFinished, hcsFailed );
Define the TOnHttpClientAsync
callback state machine steps
- hcsBeforeTlsHandshake allows to change connection.Tls parameters
- hcsAfterTlsHandshake can validate the connection.Tls information
- hcsBeforeSendHeaders allows to change emitted connection.Http.Head
- hcsAfterSendHeaders is called just before read subscription
- hcsReadStateChanged is called by connection.OnRead when Http.State changed
- hcsHeadersReceived is called when response has set connection.ResponseStatus and connection.Http.Headers have been set
- hcsFinished is called when a response was received, maybe with a body
- hcsFailed is set on eventual error
TOnHttpClientStates = set of TOnHttpClientState;
Define when the TOnHttpClientAsync
callback is to be executed
TOnPollAsyncFunc = function(Sender: TPollAsyncConnection): boolean of object;
Callback prototype for TPollAsyncSockets.OnStart
events
- should return true if Start() should not subscribe for this connection
TOnPollAsyncProc = procedure(Sender: TPollAsyncConnection) of object;
Callback prototype for TPollAsyncSockets.OnStop
events
TPollAsyncConnectionFlags = set of ( fWasActive, fClosed, fFirstRead, fInList, fReadPending, fFromGC );
Low-level flags used by the state machine about one TPollAsyncConnection
- fWasActive is set by TAsyncConnections.IdleEverySecond to purge rd/wr unused buffers, to avoid calling GetTickCount64
for every activity
- fClosed is set by OnClose virtual method
- fFirstRead is set once TPollAsyncSockets.OnFirstRead
is called
- fSubRead/fSubWrite flags are set when Subscribe() has been called
- fInList indicates that ConnectionAdd() did register the connection
- fReadPending states that there is a pending event for this connection
- fFromGC is set when the connection has been recycled from the GC list
- note: better keep it as 8 items to fit in a byte (faster access)
TPollAsyncConnectionHandle = type integer;
32-bit integer value used to identify an asynchronous connection
- will start from 1, and increase during the TAsyncConnections
live-time
TPollAsyncConnectionHandleDynArray = array of TPollAsyncConnectionHandle;
A dynamic array of TPollAsyncConnectionHandle
identifiers
TPollAsyncSocketOnReadWrite = ( soContinue, soWaitWrite, soDone, soClose );
Define the TPollAsyncSockets.OnRead/AfterWrite method result
- soContinue should continue reading/writing content from/to the socket
- soDone should unsubscribe for the current read/write phase, but should not shutdown the socket yet
- soWaitWrite (for AfterWrite) should wait a little then retry writing
- soClose would shutdown the socket
TPollAsyncSocketsOptions = set of ( paoWritePollOnly );
Possible options for low-level TPollAsyncSockets
process
- as translated from homonymous high-level acoWritePollOnly TAsyncConnectionsOptions
item
ASYNC_OPTION_DEBUG = [ ];
The TAsyncConnectionsOptions
for debugging THttpAsyncServer
- with high-level receive/send block information
ASYNC_OPTION_PROD = [ acoNoLogRead, acoNoLogWrite];
The TAsyncConnectionsOptions
for THttpAsyncServer
running on production
- with low verbosity of the logs - similar to a plain THttpServer
ASYNC_OPTION_VERBOSE = [ acoVerboseLog, acoDebugReadWriteLog];
The TAsyncConnectionsOptions
for fully detailed debug of THttpAsyncServer
- with all possible - and very verbose - log information
- could be used to track performance or heisenbug issues