Repository navigation
Description
Usage sharing is being aligned across every language to the record the .NET packages write, which draft specifications#65 describes byte for byte. The Python record, read at 1342d3e, differs from it in these ways.
- Document. There is no byte order mark and no XML declaration, and the root is
<Devices version="1.1">where the specification has<Devices>(share_usage.py#L194-L199). - Element order.
Version,Product,FlowElement,Language,LanguageVersionandPlatformcome first, thenSessionId,Sequence,ClientIPandDateSent. The specification starts withSessionId,Sequence,DateSentandClientIP(share_usage.py#L221-L236). ServerIPis never written (share_usage.py#L125-L147).DateSentisdatetime.datetime.now().isoformat(), local time with microseconds such as2026-11-03T14:11:33.760848, where the specification has UTC asyyyy-MM-ddTHH:mm:ss(share_usage.py#L235).Sequenceis empty when it is absent or not a number, where the specification has0, and is not limited to 32 bits (share_usage.py#L308-L316).- Empty elements are written as
<SessionId></SessionId>rather than<SessionId />, andSessionIdandClientIPare written without escaping (share_usage.py#L228-L232). - The three special keys are matched with case, so
Query.Session-Idbecomes an ordinary entry (share_usage.py#L301-L308). FlowElementholds the bare class name, such asShareUsage, rather than the fully qualified name (share_usage.py#L154).- Values are element text with
&,",',<and>escaped, never CDATA, and theNameattribute and element names are not escaped at all (share_usage.py#L244-L255). - Truncation cuts at 512 code points and marks the entry
truncated="true". The cut comes after escaping, so it can split an entity such as&and break the XML. The specification cuts at 10,000 UTF-16 code units behind the[TRUNCATED BY USAGE SHARING]prefix (share_usage.py#L349-L358). - Character replacement turns every character outside U+0020 to U+00FF into U+FFFD, tab, line feed and carriage return included, and marks the entry
replaced="true". Names are not checked. The specification replaces only control characters other than tab, line feed and carriage return, writes each as\xand four lowercase hex digits, and adds<BadSchema>true</BadSchema>(share_usage.py#L325-L367). - A key with no
.raisesIndexErrorin the Evidence filter, so no record is written and, with default settings,process()raises the error to the caller. The specification writes such a key as an element named by the whole key (share_usage_evidencekeyfilter.py#L73-L76). - A response other than 200 is not treated as a failure, and its status and content are not logged. Only exceptions are (share_usage.py#L198-L210).
Also found, outside the record writer:
- When a cookie, allow list or block list is set, a cookie not starting
51D_raisesAttributeError, becauseself.include_sessionis never set (share_usage_evidencekeyfilter.py#L52-L103). - The Flask helper lowercases header names before they become Evidence, so
Nameis lower case whatever the client sent, where the specification keeps the key's case (web.py#L41).
What to change
Write the record exactly as the Processing section in specifications#65 describes, so the same Evidence gives the same bytes as the .NET packages, apart from DateSent and the values that name the runtime.
The pull request goes into the rc branch, not main, because changes are collected there and released together.
Done when
A test writes a record from fixed Evidence, the specification's example among it, and compares the document byte for byte with the expected text. The cases include the byte order mark and declaration, an absent session id (<SessionId />), an absent and a non-numeric sequence (0), a value of more than 10,000 UTF-16 code units, a control character, a value containing ]]> and a key with no ..
The same change for the Rust crates is 51Degrees/51degrees-rust#232.
Activity
jwrosewell commentedon Nov 9, 2026
The record to write is the one in the Processing section of usage-sharing-element.md on
rc, not the one this issue first pointed to. That draft, specifications#65, is closed and was not adopted.So a replaced character marks its element
escaped="true", a shortened value marks ittruncated="true", and there is no CDATA and no BadSchema. .NET keeps its current record for now, as reference-implementation-notes.md records, and moves to the specification's record later.