Make Abort() interrupt the libcurl and NSURLSession transports#34
Draft
bkaradzic-microsoft wants to merge 1 commit into
Draft
Make Abort() interrupt the libcurl and NSURLSession transports#34bkaradzic-microsoft wants to merge 1 commit into
bkaradzic-microsoft wants to merge 1 commit into
Conversation
UrlRequest::Abort() cancels m_cancellationSource, but only the Windows backend observed it (its WinRT continuations are guarded by .then(m_cancellationSource)). The libcurl and NSURLSession backends ignored it, so an in-flight request blocked until the transport's own timeout -- and a consumer's cancellation (e.g. fetch's AbortSignal in JsRuntimeHost) could not actually stop the work. Noted as a follow-up in BabylonJS#31. - libcurl: curl_easy_perform runs synchronously on a worker thread and does not watch the cancellation source. Install a CURLOPT_XFERINFOFUNCTION progress callback (with CURLOPT_NOPROGRESS=0) that returns non-zero once m_cancellationSource is cancelled; curl_easy_perform then returns CURLE_ABORTED_BY_CALLBACK, which PerformAsync records as the transport error (cancelled() is safe to poll cross-thread). CURLE_ABORTED_BY_CALLBACK is added to the stable-symbol map. - NSURLSession: register a cancellation listener that [task cancel]s the in-flight data task; its completion handler then fires with NSURLErrorCancelled. The listener ticket is a derived member, released before m_cancellationSource. Adds an offline-deterministic abort test backed by a loopback server that accepts but never responds (so the request hangs until aborted), asserting the request is interrupted promptly with CURLE_ABORTED_BY_CALLBACK / NSURLErrorCancelled. Skipped on the Windows backend, which observes Abort() but does not populate the transport-error accessors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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.
Makes
UrlRequest::Abort()actually interrupt the libcurl and NSURLSession transports. TodayAbort()cancelsm_cancellationSource, but only the Windows backend observes it (its WinRT continuations are guarded by.then(m_cancellationSource)); the curl and NSURLSession backends ignore it, so an in-flight request blocks until the transport's own timeout and a consumer's cancellation can't actually stop the work. This was flagged as a follow-up in #31 ("UrlRequest::Abort()only has an effect on the Windows backend today").It's the transport-side prerequisite for fetch
AbortSignalsupport in JsRuntimeHost (BabylonJS/JsRuntimeHost#196): the polyfill there wiresinit.signaltoUrlRequest::Abort(), which currently no-ops on Linux/Apple.Changes
curl_easy_performruns synchronously on a worker thread and doesn't watch the cancellation source. Install aCURLOPT_XFERINFOFUNCTIONprogress callback (withCURLOPT_NOPROGRESS=0) that returns non-zero oncem_cancellationSourceis cancelled — libcurl invokes it periodically during the transfer (including while connecting), socurl_easy_performreturnsCURLE_ABORTED_BY_CALLBACK, whichPerformAsyncalready records as the transport error.cancelled()is safe to poll from the worker thread whileAbort()is called from another.CURLE_ABORTED_BY_CALLBACKis added to the stable-symbol map.[task cancel]s the in-flight data task; its completion handler then fires withNSURLErrorCancelled. The listener ticket is a derived member, released beforem_cancellationSource(a base member).Tests
Adds
AbortInterruptsInFlightRequest, backed by a new offline-deterministicHangingServerfixture (a loopback listener that accepts but never responds, so the request hangs until aborted). It asserts the request is interrupted promptly and reportsCURLE_ABORTED_BY_CALLBACK(42)/NSURLErrorCancelled(-999). Skipped on the Windows backend, which observesAbort()but doesn't populate the transport-error accessors.I could only build/run on Win32, where the abort test skips (the Windows backend already aborts) and the success case passes — so the test file compiles and the harness is sound, but the curl and NSURLSession code paths are not yet exercised. UrlLib
mainhas no CI yet (the workflows are in #32, still open), so this PR doesn't get automated Linux/macOS runs.Before merging, this needs the curl/NSURLSession paths validated — easiest once #32 lands (its Linux + macOS jobs run
UrlLibTests), or via the fork-mirror approach used for #31, or a maintainer build on Linux/macOS. Happy to set up whichever you prefer.Related: #31, #32, BabylonJS/JsRuntimeHost#196.
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com