Native SSE streaming, browser profile sync, doc clarifications#23
Open
Bineroflux wants to merge 9 commits into
Open
Native SSE streaming, browser profile sync, doc clarifications#23Bineroflux wants to merge 9 commits into
Bineroflux wants to merge 9 commits into
Conversation
NativeTlsClient gains four new methods (sync + async) backed by the
requestStream / readStream / readStreamAll / cancelStream exports of
the native tls-client library:
RequestStream returns once headers are available, body stays open
ReadStream polls the next chunk; supports timeout heartbeats
ReadStreamAll drains the rest as a normal Response, for the case
where Content-Type turns out NOT to be a stream
CancelStream idempotent teardown
The existing Request() path is unchanged. Older native libraries that
don't expose the streaming entry points still load; IsStreamingSupported
reports false and streaming methods throw a clear error on first use.
* TlsClient.Core: new request/response models (ReadStreamRequest,
ReadStreamAllRequest, CancelStreamRequest, StreamStartResponse,
StreamChunkResponse with EOF / Timeout / Error states and a
GetChunkBytes helper)
* docs/streaming.md (linked from readme.md): usage guide covering
SSE, Content-Type-based branching, timeout semantics, single-
thread tunneling, tuning knobs and troubleshooting
* csproj versions bumped to 1.1.0-stream.1; GeneratePackageOnBuild
removed in favour of explicit dotnet pack
* prepare.js takes an optional PACKAGE_VERSION env var so generated
platform packages can be stamped independently of TLS_CLIENT_VERSION
* .gitignore excludes generated platform package dirs, build/temp
DLL staging, local-nuget pack output, and ad-hoc /runtimes/ staging
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…client identifiers Sync TlsClientIdentifier with the latest entries in the underlying tls-client library's MappedTLSClients map: Chrome146 chrome_146 Chrome146Psk chrome_146_PSK Brave146 brave_146 (new Brave region; Chromium-derived) Brave146Psk brave_146_PSK SafariIos260 safari_ios_26_0 Firefox148 firefox_148 Purely additive — no existing constants are removed and no defaults change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rome133
The chrome_132 entry was removed from the underlying tls-client library's
MappedTLSClients map at some point. Sending it across the FFI silently
falls through to DefaultClientProfile (currently Chrome_133), which means
every default-constructed BaseTlsClient was effectively running with a
Chrome 133 fingerprint while still claiming to be Chrome 132.
Align the C# layer with what the native side actually uses:
* Remove TlsClientIdentifier.Chrome132 (no longer mapped by Go).
* BaseTlsClient parameterless constructor now uses Chrome133, with the
User-Agent bumped from Chrome/132.0.0.0 / OPR/117 to Chrome/133.0.0.0
/ OPR/118 to keep the identifier and UA coherent.
* Update test fixtures (TlsTests, PerformanceTests) that referenced
Chrome132 directly so the project still compiles.
This is a breaking change for anyone explicitly referencing
TlsClientIdentifier.Chrome132 in their own code. The behavioural impact
is nil — those callers were already getting Chrome 133 at runtime.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e doc
Follow-up to the Chrome132 removal. Two related fixes:
* Native.Tests/HeaderTests.Should_Add_UserAgent_Header_Default was
asserting the default UA contains "Chrome/132.0.0.0 ... OPR/117.0.0.0",
but BaseTlsClient's default ctor now emits the Chrome 133 / OPR 118
string. The assertion was stale and would have failed at runtime.
`dotnet build` did not catch it.
* On the API side, the parameterless ApiTlsClient / ApiTlsClientOptions
constructors paired Chrome133 (TLS identifier) with Chrome/132.0.0.0
in the User-Agent — a fingerprint/UA mismatch that predates this
cleanup but is fixed here for coherence with the Native default.
Changes:
- ApiTlsClient(Uri, string) and ApiTlsClientOptions(Uri, string): UA
bumped from Chrome/132.0.0.0 / OPR/117.0.0.0 to Chrome/133.0.0.0 /
OPR/118.0.0.0.
- Native and API HeaderTests UA literals updated to match the new
defaults.
- src/TlsClient.Api/README.md sample updated to match.
- src/Providers/TlsClient.Provider.HttpClient/README.md: replaced
`TlsClientIdentifier.Chrome132` (deleted by the previous commit, so
the snippet would no longer compile) with `Chrome133`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every static fixture in TlsClient.Native.Tests and TlsClient.Native.RestSharp.Tests
hardcoded the maintainer's local path:
NativeTlsClient.Initialize("D:\Tools\tls-client-windows-64-1.13.1.dll");
That makes the suites unrunnable for any contributor (or CI runner) that
doesn't replicate that exact path on disk. Introduce a tiny per-project
NativeTestSetup helper that reads the TLS_CLIENT_NATIVE_DLL environment
variable and falls back to the original hardcoded path when unset, so the
existing maintainer workflow keeps working unchanged.
Each fixture now calls:
NativeTlsClient.Initialize(NativeTestSetup.DllPath);
Set TLS_CLIENT_NATIVE_DLL to the DLL produced for your platform before
running `dotnet test` to override the default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Underlying tls-client-version.txt rolls v1.11.2-stream → v1.14.0-stream, picking up the new Chrome 146 / Brave 146 / Safari iOS 26 / Firefox 148 profiles, the Chrome 132 removal that already landed in this fork, and the streaming-related TimeoutSeconds semantics tweak (negative value disables the deadline for long-lived SSE streams). The wrapper packages bump from 1.1.0-stream.1 to 1.2.0-stream.1: - TlsClient.Core - TlsClient.Native Minor bump reflects the additive identifier surface (commit ccb2e31), the breaking Chrome132 removal (commit 096333c), and the test-infra refactor (commit 824cf46). The platform-specific package (TlsClient.Native.win-x64) is regenerated from the template by build/native-builder/prepare.js with PACKAGE_VERSION=1.2.0-stream.1 and is not tracked in git. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The fixture hardcoded 35.169.229.34 as the target IP. The IP is structurally necessary — the test verifies that RequestHostOverride actually populates the Host: header, which can only be observed when the connection bypasses DNS (otherwise the header derives from the URL and the override does nothing). The hardcoded value, though, was an AWS load balancer address that no longer routes to httpbin, so the test failed environmentally. Resolve httpbin.org's current IPv4 address via Dns.GetHostAddresses at test time. The test stays a real exercise of host override and now self-heals when the upstream CDN rotates addresses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The three Stream* knobs on Request — StreamOutputPath, StreamOutputBlockSize
and StreamOutputEOFSymbol — were public surface but had no XML docs at all.
Now that the underlying native side reliably preserves binary content on
the stream-to-file path (tls-client commit 1322ba3 dropped the binary-
corrupting charset.NewReader from that path), capture the contract:
StreamOutputPath
• response body is streamed to disk; Response.Body is empty
• bytes are byte-exact (post-fix) — including binary content
• file is opened with O_APPEND, so a stale file is appended to
• independent of the streaming RequestStream / ReadStream API
StreamOutputBlockSize
• per-Read buffer size on the native side
• shared with the streaming API; defaults differ
(1024 B stream-to-file / 4096 B streaming)
StreamOutputEOFSymbol
• optional completion sentinel for file tailers
• ignored when StreamOutputPath is null
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tls-client commit aa72213 reworked the cffi-side timeout resolver so
TimeoutSeconds / TimeoutMilliseconds now carries a three-way meaning:
null / 0 → use the native default (30 s)
> 0 → explicit deadline (whole request, including body reads)
< 0 → disable the deadline entirely (long-lived SSE / streaming)
Several wrapper-side docs and snippets predated that change and told
callers to "set Timeout to 0" / "TimeSpan.Zero" to disable the
deadline. Under the new resolver that's wrong — 0 is interpreted as
"use the default", and a long SSE stream gets cut at 30 s. The fix is
to set the duration to a negative value; the idiomatic .NET sentinel
Timeout.InfiniteTimeSpan (-1 ms) round-trips correctly through
BaseTlsClient.PrepareRequest's (int)Options.Timeout.TotalMilliseconds.
* docs/streaming.md
- SSE example switches Timeout = TimeSpan.Zero → InfiniteTimeSpan
- tuning table row spells out the three-way semantics explicitly
- troubleshooting row corrects the "set it to 0" advice
* NativeTlsClient.RequestStream XML doc
- drops "set TimeoutMilliseconds to 0 (or a deliberately large
value)"; explains the disable-via-InfiniteTimeSpan path
* Request.TimeoutMilliseconds / TimeoutSeconds
- new XML docs covering the three cases plus the InfiniteTimeSpan
→ -1 forwarding from TlsClientOptions
* TlsClientOptions.Timeout
- new XML doc calling out the TimeSpan.Zero foot-gun and pointing
at Timeout.InfiniteTimeSpan for streaming
Behaviour-preserving for the wrapper itself; only docs change. Existing
callers that already pass a non-zero positive duration are unaffected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary of changes
Nine commits across three themes:
1. Native SSE / streaming response support
NativeTlsClient—RequestStream,ReadStream,ReadStreamAll,CancelStream(sync +*Async). Wraps the matchingrequestStream/readStream/readStreamAll/cancelStreamexports that landed in Streaming response support for the cffi interface + bug fixes bogdanfinn/tls-client#247.docs/streaming.md— full usage guide: SSE example,Content-Type-based branching,timeoutMssemantics, single-thread tunneling notes, tuning, troubleshooting.readme.mdlinks to it.2. Sync to tls-client v1.14.0
_PSKvariants where applicable).Chrome132constant — was silently downgrading every default-constructedBaseTlsClientto Chrome 133 at runtime because the upstream mapper falls back toDefaultClientProfilefor unknown ids. Default ctor now usesChrome133explicitly. UA literals across the tree aligned to Chrome/133 + OPR/118 for coherence.1.2.0-stream.1.tls-client-version.txt→v1.14.0-stream.3. Test infra + doc clarifications
NativeTestSetuphelper readsTLS_CLIENT_NATIVE_DLL(with a fallback to the existing hardcoded path so the maintainer workflow keeps working). Lets contributors / CI run the Native suites by setting one env var.Should_Override_Hostnow resolveshttpbin.org's IP via DNS at runtime instead of hardcoding a stale AWS LB address that no longer routes there. The IP-based connection is structurally necessary — using a domain would silently mask broken host-override code.Request.StreamOutput*properties and the timeout knobs (TimeoutMilliseconds,TimeoutSeconds,TlsClientOptions.Timeout).TimeSpan.Zerois not "no timeout" — corrects several places that gave that advice. The native side now uses the convention "negative value disables the deadline";Timeout.InfiniteTimeSpanis the right idiom for long-lived SSE streams.0keeps meaning "use the 30 s default".Final notes
made — the root cause, the regression scenario it fixes, what the
resulting code contractually guarantees, and (where applicable) the
verification recipe used to prove the regression test catches the
bug.
a single unit, the commits are intentionally structured to stand on
their own: each fix and the streaming feature can be cherry-picked
or merged in isolation. Pick and choose whichever subset you're
comfortable taking.
(
requestStream/readStream/readStreamAll/cancelStream)that I have also submitted as a separate PR against
bogdanfinn/tls-client.If you'd rather wait for that PR to land before merging this one,
the wrapper still loads cleanly against a native DLL that doesn't
export them —
NativeTlsClient.IsStreamingSupportedreportsfalseand the four streaming methods throw a clear
EntryPointNotFoundExceptionon first use; nothing else regresses.1.2.0-stream.1so my localprerelease feed wouldn't collide with whatever you might tag. Feel
free to rewrite
<Version>inTlsClient.Core.csprojandTlsClient.Native.csproj