Act nowcan affect a running systemThe two merge commits need no individual entry. Merge #554 introduces THttpServerRequestAbstract.SetOutStream and related stream ownership/range handling; merge #572 lands the HTTP API WebSocket lazy-initialization change reviewed in its non-merge commit. Version bookkeeping files were ignored.
Thread shutdown cleanup becomes automatic—and changes callback types
Thread termination is now centralized in TThreadAbstract, with source-breaking callback and REST/ORM method signatures for applications that override or assign them. A separate fix prevents TWebSocketProtocol.SetEncryptKey from silently disabling encryption when aSettings is nil. Windows HTTP API WebSocket startup, several shared caches and periodic cleanup triggers also receive concurrency fixes, while a merged feature lets HTTP handlers stream response bodies from TStream.
TL;DR
- TOnNotifyThread now receives TThreadAbstract, TSynLogFamily.OnThreadEnded is removed, and related REST/ORM virtual methods use TThreadAbstract.
- TWebSocketProtocol.SetEncryptKey now keeps encryption enabled when called with a non-empty key and aSettings = nil.
- HTTP API WebSocket initialization is lazy and serialized; Wine is explicitly kept away from incomplete websocket.dll and http.sys paths.
- HTTP handlers can now return a TStream through SetOutStream; socket servers stream it, while http.sys and REST-over-WebSockets buffer it within documented limits.
- CAS and locking fixes prevent duplicate idle, session, cache-purge and connection-purge work under concurrent requests.
Upgrade advice
Take build 2.4.16737 if you rely on WebSocket encryption with a nil settings pointer, Windows HTTP API WebSockets, or the affected shared caches. Recompile custom thread callbacks and REST/ORM descendants: TOnNotifyThread and several virtual methods now require TThreadAbstract. Direct callers of LockedGet32 must rename the call to LockedReset32. The raw payload reports no later successor for these changes within this edition.
33 of 33 entries · 35 commits upstream
1
High
REST and ORM thread hooks now require TThreadAbstract
Public BeginCurrentThread, EndCurrentThread, OnBeginCurrentThread, OnEndCurrentThread, HttpThreadStart and HttpThreadTerminate declarations across mormot.rest.core, mormot.rest.server, mormot.rest.http.server and mormot.orm use TThreadAbstract instead of TThread. The old explicit log-family cleanup is removed.
Breaking changes
mormot.orm.core+5
69869f49+33-36
rest/orm: use TOnNotifyThread new definition
Impact
Custom descendants overriding these virtual methods and method variables assigned to the hooks can fail to compile until their Sender parameter is narrowed to TThreadAbstract. Runtime cleanup then comes from the new base class path.
Migration required
Search overrides and callbacks for BeginCurrentThread, EndCurrentThread, OnBeginCurrentThread, OnEndCurrentThread, HttpThreadStart and HttpThreadTerminate; change Sender: TThread to Sender: TThreadAbstract and recompile.
Public API
TRest.BeginCurrentThread / TRest.EndCurrentThreadsignature-changed — Sender changes from TThread to TThreadAbstract.TRestOrmParent.BeginCurrentThread / TRestOrmParent.EndCurrentThreadsignature-changed — Sender changes from TThread to TThreadAbstract.
2
High
TOnNotifyThread is narrowed and the log-family callback is removed
mormot.core.threads changes TOnNotifyThread from procedure(Sender: TThread) to procedure(Sender: TThreadAbstract). It adds TThreadAbstract.OnThreadEnded and mormot.core.log removes TSynLogFamily.OnThreadEnded; TLoggedThread cleanup is moved away from its own DoTerminate override.
Breaking changes
mormot.core.log+1
f1f8d766+12-13
core: breaking change of TSynLogFamily.OnThreadEnded into TThreadAbstract
Impact
Existing callback methods declared with Sender: TThread are assignment-incompatible with TOnNotifyThread, and direct references to TSynLogFamily.OnThreadEnded no longer compile. This is a source migration for Delphi and FPC projects.
Migration required
Search for TOnNotifyThread assignments and Sender: TThread handlers, change them to Sender: TThreadAbstract, and replace TSynLogFamily.OnThreadEnded references with TThreadAbstract.OnThreadEnded or automatic TThreadAbstract cleanup.
Public API
TOnNotifyThreadsignature-changed — Sender is now TThreadAbstract instead of TThread.TSynLogFamily.OnThreadEndedremoved — Cleanup moves to TThreadAbstract.TThreadAbstract.OnThreadEndedadded — Wrapper around TSynLog.NotifyThreadEnded using the new callback type.
3
High
LockedGet32 is renamed and can now atomically install any integer
mormot.core.base replaces the public LockedGet32(Target) function with LockedReset32(Target, New), where New defaults to zero. mormot.net.async updates both wake-up counter call sites to the new name.
Breaking changes
mormot.core.base+1
bcf834a5+9-9
core: new LockedReset32() wrapper function
Impact
Code that calls LockedGet32 directly will no longer compile. The default LockedReset32 call preserves the old exchange-with-zero behavior; the new parameter also supports another replacement value.
Migration required
Search for LockedGet32 and rename each call to LockedReset32; pass New only when a value other than zero is required.
Public API
LockedGet32removed — Replaced by LockedReset32.LockedReset32added — Atomically returns Target^ and replaces it with New, which defaults to zero.
4
High
A nil WebSocket settings pointer no longer disables encryption
TWebSocketProtocol.SetEncryptKey in mormot.net.ws.core now exits only for an empty key, not for a nil aSettings. With nil settings it tries default ECDHE file handling, then full key syntax, and finally derives the legacy Sha256Weak key for AES-CTR-128.
Security
mormot.net.ws.core
57660dac+18-11
net: fixed TWebSocketProtocol.SetEncryptKey() with aSettings = nil
Impact
Previously, a non-empty key combined with a nil settings pointer cleared fEncryption and returned, silently leaving the protocol unsecured. The same call now establishes encryption, using documented compatibility defaults when no settings are available.
Upgrade recommended
Upgrade any endpoint that calls SetEncryptKey with a non-empty key and nil settings, then verify both peers negotiate the expected cipher. Prefer explicit PBKDF2 settings for newly configured passwords.
Public API
TWebSocketProtocol.SetEncryptKeybehaviour-changed — nil aSettings now selects compatibility defaults instead of disabling encryption.
Units
5
High
HTTP API WebSocket construction now initializes websocket.dll safely
THttpApiWebSocketServer.Create in mormot.net.server calls WebSocketApiInitialize before testing WebSocketApi.WebSocketEnabled. mormot.lib.winhttp performs DLL loading and export binding under the reentrant global lock, and new tests cover constructor-first and 16-thread initialization.
Fixes
mormot.lib.winhttp+1
41dbfbba+211-18
fix: initialize HTTP API WebSockets lazily
Impact
A Windows HTTP API WebSocket server can be the first WebSocket API user in the process without incorrectly raising 'not supported', and concurrent first use cannot observe partially bound function pointers.
Upgrade recommended
Upgrade Windows services that construct THttpApiWebSocketServer before any WinHTTP WebSocket client use.
Public API
THttpApiWebSocketServer.Createbehaviour-changed — Performs lazy WebSocket API initialization before availability is checked.
6
Medium
Final concurrency cleanup prevents an older cache result from winning
In mormot.core.os, TCachedValue.Cache now stores a slow callback result only if TixShr still matches the tick claimed before the callback. The commit also switches TSynDictionary reads to VCardinal and simplifies equivalent code in mormot.rest.server, with comments in the other touched units.
Fixes
mormot.core.json+4
14d901e8+16-16
all: some refactoring after today's commits
Impact
Concurrent callers can no longer let an older, slower computation overwrite a newer cached value. Existing Delphi and FPC application code has no API change from this commit.
Upgrade recommended
Take this final build if your code uses TCachedValue from multiple threads.
7
Medium
REST server timestamp cache gains atomic refresh and locked reads
TRest.GetServerTimestamp in mormot.rest.core uses LockedExc32 to elect one refresher for each 512 ms slot. A TLightLock now protects writes and reads of the cached TTimeLogBits value.
Fixes
mormot.rest.core
ad1dcbf5+18-12
rest: made TRest.GetServerTimestamp atomic
Impact
Parallel REST requests see a consistently copied server timestamp, including on 32-bit Delphi/FPC where a 64-bit value is not naturally atomic. No application API changes.
Upgrade recommended
Upgrade if the same TRest instance serves concurrent requests on a 32-bit target.
Units
8
Medium
Recycled logging thread slots now reset their complete local state
TSynLog.NotifyThreadEnded in mormot.core.log now clears ThreadNumber as the one-time recycled marker, while InitThreadNumber resets RecursionCount and Flags before assigning a reused slot. ThreadBitLo remains the lazy initialization marker.
Fixes
mormot.core.log
35d353c9+13-9
core: fixed TSynLog.NotifyThreadEnded threads recycling
Impact
Short-lived threads that reuse TSynLog slots no longer inherit recursion or per-thread logging flags from a previous thread. This prevents silent logging suppression or stale thread-specific behavior.
Upgrade recommended
Upgrade services that create and destroy many logging threads or customize per-thread TSynLog flags.
Units
9
Medium
Kerberos keytab refresh is serialized without holding the lock during reload
TServerSspiKeyTab.TryRefresh in mormot.lib.gssapi uses fSafe to claim each two-second refresh window, then calls SetKeyTab after releasing the lock. The tick is offset by one so the first valid interval is not mistaken for the initial zero.
Fixes
mormot.lib.gssapi
6f53f3d7+14-7
lib: optimized TServerSspiKeyTab.TryRefresh thread safety
Impact
Concurrent SSPI/GSSAPI authentication attempts no longer reload the same keytab together, and unrelated callers do not wait under the lock for file parsing. Public APIs are unchanged.
Upgrade recommended
Upgrade Kerberos-backed servers that refresh a keytab while serving concurrent requests.
Units
10
Medium
WebSocket DLL probing is attempted once and disabled on Wine
TWebSocketApi gains a Tested flag in mormot.lib.winhttp. WebSocketApiInitialize records the first load attempt inside the global lock, avoids repeated failed loads and returns immediately on Wine, whose websocket.dll exposes only partial stubs.
Fixes
mormot.lib.winhttp
2f0cdace+14-6
lib: fixed WebSocketApiInitialize
Impact
Unsupported Windows environments stop repeatedly probing the DLL, while Wine no longer appears WebSocket-capable merely because stub exports exist. Native supported systems initialize once.
Upgrade recommended
Take this together with the lazy-initialization and wsWeakHttpSys commits for Windows or Wine deployments.
Public API
TWebSocketApi.Testedadded — Records that websocket.dll availability was already tested.
Units
11
Medium
Concurrent REST requests no longer trigger OnIdle together
TRestServer.Uri in mormot.rest.server replaces the read-then-write fOnIdleLastTix test with a LockedExc32 compare-and-swap. Only the request that advances the tick calls OnIdle.
Fixes
mormot.rest.server
7df2308e+8-8
rest: fixed TRestServer.OnIdle trigger
Impact
OnIdle handlers are no longer entered concurrently merely because requests finish in the same tick. Backends with non-reentrant idle work avoid duplicate maintenance and races.
Upgrade recommended
Upgrade if TRestServer.OnIdle performs stateful or non-reentrant maintenance.
Public API
TRestServer.OnIdlebehaviour-changed — At most one request invokes it for a given tick.
Units
12
Medium
Global time cache compare-and-swap no longer aliases its expected value
FromGlobalTime in mormot.core.datetime copies GlobalTime.clock into a local c variable and supplies that stable expected value to LockedExc32. The prior call used clock as both the target and expected argument.
Fixes
mormot.core.datetime
f7cfb5db+8-5
core: fixed FromGlobalTime() atomicity
Impact
Concurrent timestamp formatting now has a well-defined CAS election before updating the shared 16 ms cache. Delphi and FPC callers keep the same FromGlobalTime signature and precision.
Upgrade recommended
Upgrade multithreaded servers that frequently format global or local timestamps.
Units
13
Medium
TLoggedThread releases logging state even when it logged nothing
TLoggedThread.DoTerminate in mormot.core.threads removes its early exit when fLog is nil and calls the class-level TSynLog.NotifyThreadEnded unconditionally after inherited DoTerminate. It then clears fLog.
Fixes
mormot.core.threads
2c03b28a+3-5
core: fixed TLoggedThread.DoTerminate
Impact
A TLoggedThread that acquired thread-local logging metadata but emitted no entry now returns its slot correctly. Long-running services avoid gradual exhaustion of the logging thread registry.
Upgrade recommended
Upgrade services with many short-lived TLoggedThread instances, including threads that may complete without logging.
Units
14
Medium
Preconnected tunnel workers now start with a successful network result
TTunnelLocalThread.DoExecute in mormot.net.tunnel assigns res := nrOk when the socket connection was already created by the main thread, before setting fState := stProcessing. The branch previously left res uninitialized or stale.
Fixes
mormot.net.tunnel
677a3579+5-2
net: fixed TTunnelLocalThread process
Impact
Tunnel sessions using a socket connected on the main thread no longer carry an undefined network result into later shutdown or error handling. The connection workflow and API signatures are unchanged.
Upgrade recommended
Upgrade deployments using TTunnelLocalThread with main-thread socket connection setup.
Units
15
Medium
TCachedValue reserves refresh work before releasing its lock
TCachedValue.Cache in mormot.core.os moves the Tix32 assignment inside Safe before invoking the slow Call callback outside the lock. That marks the refresh as claimed before another thread can enter.
Fixes
mormot.core.os
84ab9449+3-3
core: fixed race in TCachedValue.Cache
Impact
Multiple callers no longer start the same expensive cache computation for one interval. The later 14d901e commit additionally prevents a delayed older computation from overwriting a newer result.
Upgrade recommended
Use the edition head rather than stopping here, because 14d901e completes the concurrent cache update guard.
Units
16
Medium
TThreadAbstract now always performs end-of-thread log cleanup
TThreadAbstract.DoTerminate in mormot.core.threads now calls TSynLog.NotifyThreadEnded after inherited termination and the legacy Finished update, swallowing shutdown exceptions. Framework queues and timers remove their explicit OnThreadEnded callbacks; the independent logging flush TThread keeps a manual call.
New features
mormot.core.log+2
8ef4ae1b+30-35
core: TThreadAbstract calls TSynLog.NotifyThreadEnded
Impact
Every descendant that correctly reaches inherited DoTerminate releases its per-thread logging state automatically. Plain TThread descendants that use TSynLog still need to call TSynLog.NotifyThreadEnded themselves.
Worth a look
Public API
TThreadAbstract.DoTerminatebehaviour-changed — Calls TSynLog.NotifyThreadEnded automatically at thread shutdown.
17
Medium
TThreadAbstract exposes Finished consistently on Delphi 7 and 2007
mormot.core.threads adds an emulated public Finished property and fFinished field to TThreadAbstract when the RTL lacks them, setting the flag in DoTerminate. TLoggedThread.ExecuteDone is removed, and mormot.net.tftp.server switches to Finished.
Compiler & platform
mormot.core.threads+1
5678b9d9+31-13
core: emulate TThread.Finished property on Delphi 7/2007
Impact
Legacy Delphi can use the same TThreadAbstract.Finished check as modern Delphi and FPC. Code that referenced the public TLoggedThread.ExecuteDone property must migrate to Finished.
Migration required
Search for TLoggedThread.ExecuteDone and replace it with the inherited Finished property.
Public API
TThreadAbstract.Finishedadded — Emulated for Delphi 7/2007; already supplied by newer RTLs.TLoggedThread.ExecuteDoneremoved — Use Finished instead.
18
Medium
Wine receives an explicit weak-http.sys capability flag
mormot.core.os adds wsWeakHttpSys to TWindowsSpecs and sets it during Wine detection. TRestHttpServer.Create in mormot.rest.http.server now uses that capability flag to fall back from HTTP_API_MODES to useHttpAsync.
Compiler & platform
mormot.core.os+3
b4238a29+10-8
net: introducing wsWeakHttpSys flag
Impact
REST servers running under Wine avoid selecting an http.sys implementation known to be incomplete and use the asynchronous socket server instead. Native Windows behavior is unchanged.
Upgrade recommended
Upgrade Wine deployments that request an HTTP API server mode and verify the logged useHttpAsync fallback.
Public API
TWindowsSpecs.wsWeakHttpSysadded — Marks environments where http.sys should not be selected.
19
Medium
HTTP API WebSocket workers follow the new thread callback type
mormot.net.server changes TSynThreadPoolHttpApiWebSocketServer.OnThreadStart and OnThreadTerminate to accept TThreadAbstract. TSynWebSocketGuard now inherits TThreadAbstract and drops its manual TSynLog.NotifyThreadEnded call.
Compiler & platform
mormot.net.server
f115b536+7-8
net: follow new TThreadAbstract / TOnNotifyThread definitions
Impact
Framework WebSocket worker and guard threads compile with the new TOnNotifyThread contract and receive automatic log cleanup. Custom descendants overriding the protected callbacks may require the same signature update.
Worth a look
Units
20
Low
Dictionary expiry scans gain an atomic one-second gate
TSynDictionary.DeleteDeprecated in mormot.core.json reads the shared tick through the new TSynVarData.VCardinal view and uses LockedExc32 to claim a scan. mormot.core.base adds the VCardinal variant-record field used for that atomic access.
Performance
mormot.core.base+1
c7887dc9+35-33
core: ensure TSynDictionary.DeleteDeprecated trigger is atomic
Impact
Concurrent dictionary users avoid duplicate expiry scans for the same second. Existing TSynDictionary behavior is preserved; code inspecting TSynVarData may use the added unsigned view.
Public API
TSynVarData.VCardinaladded — Unsigned 32-bit overlay for the variant record.
21
Low
Connection-pool expiry scans are elected once per interval
TSqlDBConnectionPropertiesThreadSafe.ThreadSafeConnection in mormot.db.sql replaces an unsynchronized timestamp assignment with LockedExc32 before calling DeleteDeprecated. ClearConnectionPool atomically resets the trigger.
Performance
mormot.db.sql
a6d76aa9+12-9
db: use CAS for TSqlDBConnectionPropertiesThreadSafe.DeleteDeprecated
Impact
Under concurrent database traffic, only one thread performs the optional expired-connection scan every 32 seconds. Backend behavior and public APIs remain unchanged.
Units
22
Low
MVC method-cache purging runs once per second across requests
TMvcRunWithViews processing in mormot.core.mvc now claims fOnIdlePurgeCacheTix32 with LockedExc32 before calling PurgeMethodCache. PurgeMethodCache no longer assigns that tick itself.
Performance
mormot.core.mvc
83f4846b+6-5
mvc: atomic TMvcRunWithViews.PurgeMethodCache
Impact
Concurrent MVC requests avoid redundant full cache scans in the same second. Cached results and application-facing MVC APIs keep the same behavior.
Units
23
Low
Expired REST sessions are purged by one request per interval
TRestServerUriContext.Authenticate in mormot.rest.server now advances fSessionsDeprecatedTix with LockedExc32 before SessionDeleteDeprecated. The purge routine no longer performs a separate non-atomic assignment.
Performance
mormot.rest.server
14d5a05d+6-5
rest: use a CAS trigger for TRestServer.SessionDeleteDeprecated
Impact
Busy authenticated servers avoid multiple request threads entering the same once-per-second expiry scan. Session expiry semantics and public APIs do not change.
Units
24
Low
HTTP log timestamp formatting is limited to one thread per second
THttpLogger.Append in mormot.net.http uses LockedExc32 on fTimeTix32 before SetTimeText. Competing request threads reuse the cached ISO-8601 and NCSA strings instead of formatting them concurrently.
Performance
mormot.net.http
d7b698d8+6-5
net: optimized THttpLogger.Append time update
Impact
High-throughput HTTP logging performs less duplicate date conversion while retaining the existing one-second timestamp cache. No logging format or public API changes.
Units
25
Low
StackTrace declarations compile again with Delphi 7
mormot.core.log places the static directive on the two overloaded TSynLog.StackTrace declarations only when HASINLINE is defined. Older Delphi compilers no longer parse the unsupported directive there.
Compiler & platform
mormot.core.log
332614f5+6-4
code: fixed Delphi 7 compilation
Impact
Delphi 7 builds using mormot.core.log compile again. Newer Delphi and FPC targets keep the same StackTrace API and runtime behavior.
Upgrade recommended
Upgrade if Delphi 7 stopped in the TSynLog.StackTrace declarations.
Units
26
Low
Compiler feature flags now describe TThread.Finished availability
mormot.defines adds HASTTHREADFINISHED for FPC and Unicode Delphi, and documents WINDELPHI before defining it for Delphi on Windows. These conditionals support the surrounding legacy TThread compatibility code.
Compiler & platform
mormot.defines
86422854+6-3
core: added missing HASTTHREADFINISHED conditional
Impact
The framework selects its Finished emulation only on Delphi 7/2007 instead of targets that already provide the property. Application code sees no direct API change.
Units
27
Low
Response-stream follow-up tightens cleanup and test diagnostics
After the SetOutStream merge, mormot.net.http makes OutContentStreamDiscard nil-safe and resets its fields in one place. mormot.net.async clarifies that AsyncResponse discards a pending stream, while tests use RaiseStreamError and ignore expected EStreamError logging.
Under the hood
mormot.net.async+1
7627b1ad+20-26
net: some refactoring after #554
Impact
Owned response streams remain released and delayed asynchronous content still replaces any pending stream. This follow-up does not change the documented SetOutStream API or server capability limits.
28
Low
Startup nonces stop recursively entering the main Random128 generator
TCryptRandomEntropy.Create in mormot.crypt.secure fills its 16-byte per-application nonce through RandomBytes instead of Random128. Related comments clarify that TAes.EncryptInitRandom must avoid Random128 recursion and that OS random calls are fallback seeding.
Under the hood
mormot.core.os.posix+5
a0141ee6+13-23
core: don't call Random128() at startup
Impact
Cryptographic entropy-source initialization avoids re-entering the main PRNG while it is being constructed. The nonce remains random; public random APIs and generated-data formats are unchanged.
29
Low
Global time caching now stores TSynSystemTime directly
mormot.core.datetime changes the GlobalTime cache field from TSystemTime to TSynSystemTime and removes the local absolute alias in FromGlobalTime. Padding still keeps each cache record on one 64-byte line.
Under the hood
mormot.core.datetime
6dda432f+12-11
core: simplified FromGlobalTime() implementation
Impact
This simplifies internal copying without changing the public FromGlobalTime contract or the 16 ms cache precision. Existing Delphi/FPC application code is unaffected.
Units
30
Low
Angelize watchdog drops manual logging cleanup callbacks
mormot.app.agl removes explicit TSynLog.NotifyThreadEnded and log.Family.OnThreadEnded calls from TSynAngelizeRunner and its watchdog creation. Their TThreadAbstract ancestry now supplies the cleanup.
Under the hood
mormot.app.agl
afde3637+4-5
agl: follow new TThreadAbstract feature
Impact
Angelize behavior should remain the same, with one centralized end-of-thread notification instead of manual per-class calls. Application APIs are unchanged.
Units
31
Low
SQLite and PostgreSQL threads align with centralized log cleanup
mormot.db.sql.postgres removes the redundant SynDBLog.NotifyThreadEnded call from its TThreadAbstract-based async thread. The SQLite backup thread remains a plain TThread and retains an explicitly documented SQLite3Log.NotifyThreadEnded call.
Under the hood
mormot.db.raw.sqlite3+1
9a1c1313+4-5
db: adapt to the new TThreadAbstract class
Impact
Database thread logging cleanup should occur exactly once without changing SQLite backup or PostgreSQL async behavior. No application-facing database API changes.
32
Low
Tests and a logging demo adopt TThreadAbstract
The dmvc-ai logging demo and TPipeConsumerThread in test.net.proto now inherit from TThreadAbstract instead of TThread. No framework implementation or public declaration changes in this commit.
Tests
56660c17+4-4
test: favor TThreadAbstract usage
Impact
Application code is unaffected; the changed examples demonstrate the preferred base class so end-of-thread logging cleanup happens automatically.
33
Low
Sha256Weak documentation makes its legacy-only status explicit
Comments in mormot.crypt.core clarify that Sha256Weak pads inputs shorter than 256 bytes, exists only for mORMot 1 compatibility and must not be used for new code or newly generated data. TSynSigner.Pbkdf2 and Modular Crypt are named alternatives.
Docs
mormot.crypt.core
8d60e5ed+7-6
crypt: refined Sha256Weak() documentation
Impact
There is no runtime or API change. The stronger wording helps security reviews identify existing Sha256Weak use as compatibility debt rather than an approved password derivation choice.
Worth a look
Public API
Sha256Weakdeprecated — Documentation says to retain it only for mORMot 1 compatibility; use TSynSigner.Pbkdf2 or Modular Crypt for new data.