tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 3bc4ad2c92f29745f64d1f8debaecdc6d2949b97
parent e05257d0e2e7e1dde6925143f43feadd3e2f9d6e
Author: Kershaw Chang <kershaw@mozilla.com>
Date:   Thu, 27 Nov 2025 13:32:40 +0000

Bug 2002687 - Don't retry transaction when it's cancelled, r=necko-reviewers,valentin

Differential Revision: https://phabricator.services.mozilla.com/D274258

Diffstat:
Mnetwerk/protocol/http/nsHttp.h | 11+++++++++--
Mnetwerk/protocol/http/nsHttpChannel.cpp | 2+-
Mnetwerk/protocol/http/nsHttpTransaction.cpp | 5+++--
Mnetwerk/socket/neqo_glue/src/lib.rs | 31++++++++++++-------------------
4 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/netwerk/protocol/http/nsHttp.h b/netwerk/protocol/http/nsHttp.h @@ -485,11 +485,18 @@ nsresult HttpProxyResponseToErrorCode(uint32_t aStatusCode); // Convert an alpn string to SupportedAlpnType. SupportedAlpnRank IsAlpnSupported(const nsACString& aAlpn); -static inline bool AllowedErrorForHTTPSRRFallback(nsresult aError) { +// Keep this list in sync with the error mapping in +// neqo_glue/src/lib.rs::into_nsresult(). These are the network/NSS errors for +// which we allow a transaction to retry. +static inline bool AllowedErrorForTransactionRetry(nsresult aError) { return psm::IsNSSErrorCode(-1 * NS_ERROR_GET_CODE(aError)) || aError == NS_ERROR_NET_RESET || aError == NS_ERROR_CONNECTION_REFUSED || - aError == NS_ERROR_UNKNOWN_HOST || aError == NS_ERROR_NET_TIMEOUT; + aError == NS_ERROR_UNKNOWN_HOST || aError == NS_ERROR_NET_TIMEOUT || + aError == NS_ERROR_NOT_CONNECTED || + aError == NS_ERROR_SOCKET_ADDRESS_IN_USE || + aError == NS_ERROR_FILE_ALREADY_EXISTS || + aError == NS_ERROR_NET_INTERRUPT; } [[nodiscard]] nsresult MakeOriginURL(const nsACString& origin, diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp @@ -6967,7 +6967,7 @@ nsHttpChannel::Cancel(nsresult status) { static_cast<uint32_t>(status), mCanceledReason.get())); MOZ_ASSERT_IF(!(mConnectionInfo && mConnectionInfo->UsingConnect()) && NS_SUCCEEDED(mStatus), - !AllowedErrorForHTTPSRRFallback(status)); + !AllowedErrorForTransactionRetry(status)); mEarlyHintObserver = nullptr; mWebTransportSessionEventListener = nullptr; diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -1337,7 +1337,8 @@ void nsHttpTransaction::Close(nsresult reason) { // treat it as NS_ERROR_NET_RESET so the transaction will retry once. // NOTE: This is a temporary workaround; the proper fix belongs in // the Happy Eyeballs project. - if (NS_FAILED(reason) && mHttp3BackupTimerCreated && mHttp3BackupTimer) { + if (NS_FAILED(reason) && AllowedErrorForTransactionRetry(reason) && + mHttp3BackupTimerCreated && mHttp3BackupTimer) { reason = NS_ERROR_NET_RESET; } @@ -1392,7 +1393,7 @@ void nsHttpTransaction::Close(nsresult reason) { // to make sure this transaction can be restarted with the same conncetion // info. bool shouldRestartTransactionForHTTPSRR = - mOrigConnInfo && AllowedErrorForHTTPSRRFallback(reason) && + mOrigConnInfo && AllowedErrorForTransactionRetry(reason) && !mDoNotRemoveAltSvc; // diff --git a/netwerk/socket/neqo_glue/src/lib.rs b/netwerk/socket/neqo_glue/src/lib.rs @@ -41,11 +41,11 @@ use neqo_transport::{ Error as TransportError, Output, OutputBatch, RandomConnectionIdGenerator, StreamId, Version, }; use nserror::{ - nsresult, NS_BASE_STREAM_WOULD_BLOCK, NS_ERROR_CONNECTION_REFUSED, NS_ERROR_FAILURE, - NS_ERROR_FILE_ALREADY_EXISTS, NS_ERROR_ILLEGAL_VALUE, NS_ERROR_INVALID_ARG, - NS_ERROR_NET_HTTP3_PROTOCOL_ERROR, NS_ERROR_NET_INTERRUPT, NS_ERROR_NET_RESET, - NS_ERROR_NET_TIMEOUT, NS_ERROR_NOT_AVAILABLE, NS_ERROR_NOT_CONNECTED, NS_ERROR_OUT_OF_MEMORY, - NS_ERROR_SOCKET_ADDRESS_IN_USE, NS_ERROR_UNEXPECTED, NS_OK, NS_ERROR_DOM_INVALID_HEADER_NAME, + nsresult, NS_BASE_STREAM_WOULD_BLOCK, NS_ERROR_CONNECTION_REFUSED, + NS_ERROR_DOM_INVALID_HEADER_NAME, NS_ERROR_FILE_ALREADY_EXISTS, NS_ERROR_ILLEGAL_VALUE, + NS_ERROR_INVALID_ARG, NS_ERROR_NET_HTTP3_PROTOCOL_ERROR, NS_ERROR_NET_INTERRUPT, + NS_ERROR_NET_RESET, NS_ERROR_NET_TIMEOUT, NS_ERROR_NOT_AVAILABLE, NS_ERROR_NOT_CONNECTED, + NS_ERROR_OUT_OF_MEMORY, NS_ERROR_SOCKET_ADDRESS_IN_USE, NS_ERROR_UNEXPECTED, NS_OK, }; use nsstring::{nsACString, nsCString}; use thin_vec::ThinVec; @@ -2398,6 +2398,7 @@ pub unsafe extern "C" fn neqo_http3conn_webtransport_set_sendorder( /// /// Note that this conversion is specific to `neqo_glue`, i.e. does not aim to /// implement a general-purpose conversion. +/// Treat NS_ERROR_NET_RESET as a generic retryable error for the upper layer. /// /// Modeled after /// [`ErrorAccordingToNSPR`](https://searchfox.org/mozilla-central/rev/a965e3c683ecc035dee1de72bd33a8d91b1203ed/netwerk/base/nsSocketTransport2.cpp#164-168). @@ -2448,16 +2449,6 @@ fn into_nsresult(e: &io::Error) -> nsresult { // TODO: nightly-only for now <https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.FilesystemLoop>. // io::ErrorKind::FilesystemLoop => NS_ERROR_FILE_UNRESOLVABLE_SYMLINK, - - // > NSPR's socket code can return these, but they're not worth breaking out - // > into their own error codes, distinct from NS_ERROR_FAILURE: - // > - // > PR_BAD_DESCRIPTOR_ERROR - // > PR_INVALID_ARGUMENT_ERROR - // - // <https://searchfox.org/mozilla-central/rev/a965e3c683ecc035dee1de72bd33a8d91b1203ed/netwerk/base/nsSocketTransport2.cpp#231> - io::ErrorKind::InvalidInput => NS_ERROR_FAILURE, - io::ErrorKind::TimedOut => NS_ERROR_NET_TIMEOUT, io::ErrorKind::Interrupted => NS_ERROR_NET_INTERRUPT, @@ -2477,7 +2468,7 @@ fn into_nsresult(e: &io::Error) -> nsresult { | io::ErrorKind::InvalidData | io::ErrorKind::WriteZero | io::ErrorKind::Unsupported - | io::ErrorKind::Other => NS_ERROR_FAILURE, + | io::ErrorKind::Other => NS_ERROR_NET_RESET, // TODO: available since Rust v1.83.0 only // <https://doc.rust-lang.org/std/io/enum.ErrorKind.html>. @@ -2491,11 +2482,13 @@ fn into_nsresult(e: &io::Error) -> nsresult { // | io::ErrorKind::ArgumentListTooLong // | io::ErrorKind::NetworkDown // | io::ErrorKind::StaleNetworkFileHandle - // | io::ErrorKind::StorageFull => NS_ERROR_FAILURE, + // | io::ErrorKind::StorageFull => NS_ERROR_NET_RESET, // TODO: nightly-only for now <https://doc.rust-lang.org/std/io/enum.ErrorKind.html>. - // io::ErrorKind::CrossesDevices | io::ErrorKind::InvalidFilename => NS_ERROR_FAILURE, - _ => NS_ERROR_FAILURE, + // io::ErrorKind::CrossesDevices + // | io::ErrorKind::InvalidFilename + // | io::ErrorKind::InvalidInput => NS_ERROR_NET_RESET, + _ => NS_ERROR_NET_RESET, } }