diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 3c8f4b819928..84bb0bc51f9f 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4000,7 +4000,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, break; case NS_ERROR_PROXY_CONNECTION_REFUSED: case NS_ERROR_PROXY_AUTHENTICATION_FAILED: - case NS_ERROR_TOO_MANY_REQUESTS: + case NS_ERROR_PROXY_TOO_MANY_REQUESTS: // Proxy connection was refused. error = "proxyConnectFailure"; break; @@ -6563,7 +6563,7 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress, aStatus == NS_ERROR_UNKNOWN_PROXY_HOST || aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED || aStatus == NS_ERROR_PROXY_AUTHENTICATION_FAILED || - aStatus == NS_ERROR_TOO_MANY_REQUESTS || + aStatus == NS_ERROR_PROXY_TOO_MANY_REQUESTS || aStatus == NS_ERROR_BLOCKED_BY_POLICY) && (isTopFrame || UseErrorPages())) { DisplayLoadError(aStatus, url, nullptr, aChannel); diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg index 1d6c017f4f0c..a484202da358 100644 --- a/js/xpconnect/src/xpc.msg +++ b/js/xpconnect/src/xpc.msg @@ -148,7 +148,7 @@ XPC_MSG_DEF(NS_ERROR_PROXY_CONNECTION_REFUSED , "The connection to the pro XPC_MSG_DEF(NS_ERROR_PROXY_AUTHENTICATION_FAILED , "The proxy requires authentication") XPC_MSG_DEF(NS_ERROR_PROXY_BAD_GATEWAY , "The request failed on the proxy") XPC_MSG_DEF(NS_ERROR_PROXY_GATEWAY_TIMEOUT , "The request timed out on the proxy") -XPC_MSG_DEF(NS_ERROR_TOO_MANY_REQUESTS , "Sending too many requests to a proxy") +XPC_MSG_DEF(NS_ERROR_PROXY_TOO_MANY_REQUESTS , "Sending too many requests to a proxy") XPC_MSG_DEF(NS_ERROR_NET_TIMEOUT , "The connection has timed out") XPC_MSG_DEF(NS_ERROR_OFFLINE , "The requested action could not be completed in the offline state") XPC_MSG_DEF(NS_ERROR_PORT_ACCESS_NOT_ALLOWED , "Establishing a connection to an unsafe or otherwise banned port was prohibited") diff --git a/netwerk/protocol/http/TunnelUtils.cpp b/netwerk/protocol/http/TunnelUtils.cpp index 73f8d3f8f836..0a8b5630bf1b 100644 --- a/netwerk/protocol/http/TunnelUtils.cpp +++ b/netwerk/protocol/http/TunnelUtils.cpp @@ -1168,24 +1168,11 @@ void SpdyConnectTransaction::MapStreamToHttpConnection( mTunnelStreamOut = new OutputStreamShim(this, mIsWebsocket); mTunneledConn = new nsHttpConnection(); - switch (httpResponseCode) { - case 404: - CreateShimError(NS_ERROR_UNKNOWN_HOST); - break; - case 407: - CreateShimError(NS_ERROR_PROXY_AUTHENTICATION_FAILED); - break; - case 429: - CreateShimError(NS_ERROR_TOO_MANY_REQUESTS); - break; - case 502: - CreateShimError(NS_ERROR_PROXY_BAD_GATEWAY); - break; - case 504: - CreateShimError(NS_ERROR_PROXY_GATEWAY_TIMEOUT); - break; - default: - break; + if (httpResponseCode != 200) { + nsresult err = HttpProxyResponseToErrorCode(httpResponseCode); + if (NS_FAILED(err)) { + CreateShimError(err); + } } // this new http connection has a specific hashkey (i.e. to a particular diff --git a/netwerk/protocol/http/nsHttp.cpp b/netwerk/protocol/http/nsHttp.cpp index e8942a655222..ab3322d41011 100644 --- a/netwerk/protocol/http/nsHttp.cpp +++ b/netwerk/protocol/http/nsHttp.cpp @@ -841,5 +841,141 @@ void LogHeaders(const char* lineStart) { } } +nsresult HttpProxyResponseToErrorCode(uint32_t aStatusCode) { + MOZ_ASSERT(aStatusCode >= 300, + "Call HttpProxyResponseToErrorCode with successful status code!"); + + nsresult rv; + switch (aStatusCode) { + case 300: + case 301: + case 302: + case 303: + case 307: + case 308: + // Bad redirect: not top-level, or it's a POST, bad/missing Location, + // or ProcessRedirect() failed for some other reason. Legal + // redirects that fail because site not available, etc., are handled + // elsewhere, in the regular codepath. + rv = NS_ERROR_CONNECTION_REFUSED; + break; + // Squid sends 404 if DNS fails (regular 404 from target is tunneled) + case 404: // HTTP/1.1: "Not Found" + // RFC 2616: "some deployed proxies are known to return 400 or + // 500 when DNS lookups time out." (Squid uses 500 if it runs + // out of sockets: so we have a conflict here). + case 400: // HTTP/1.1 "Bad Request" + case 500: // HTTP/1.1: "Internal Server Error" + rv = NS_ERROR_UNKNOWN_HOST; + break; + case 401: + rv = NS_ERROR_PROXY_UNAUTHORIZED; + break; + case 402: + rv = NS_ERROR_PROXY_PAYMENT_REQUIRED; + break; + case 403: + rv = NS_ERROR_PROXY_FORBIDDEN; + break; + case 405: + rv = NS_ERROR_PROXY_METHOD_NOT_ALLOWED; + break; + case 406: + rv = NS_ERROR_PROXY_NOT_ACCEPTABLE; + break; + case 407: // ProcessAuthentication() failed (e.g. no header) + rv = NS_ERROR_PROXY_AUTHENTICATION_FAILED; + break; + case 408: + rv = NS_ERROR_PROXY_REQUEST_TIMEOUT; + break; + case 409: + rv = NS_ERROR_PROXY_CONFLICT; + break; + case 410: + rv = NS_ERROR_PROXY_GONE; + break; + case 411: + rv = NS_ERROR_PROXY_LENGTH_REQUIRED; + break; + case 412: + rv = NS_ERROR_PROXY_PRECONDITION_FAILED; + break; + case 413: + rv = NS_ERROR_PROXY_REQUEST_ENTITY_TOO_LARGE; + break; + case 414: + rv = NS_ERROR_PROXY_REQUEST_URI_TOO_LONG; + break; + case 415: + rv = NS_ERROR_PROXY_UNSUPPORTED_MEDIA_TYPE; + break; + case 416: + rv = NS_ERROR_PROXY_REQUESTED_RANGE_NOT_SATISFIABLE; + break; + case 417: + rv = NS_ERROR_PROXY_EXPECTATION_FAILED; + break; + case 421: + rv = NS_ERROR_PROXY_MISDIRECTED_REQUEST; + break; + case 425: + rv = NS_ERROR_PROXY_TOO_EARLY; + break; + case 426: + rv = NS_ERROR_PROXY_UPGRADE_REQUIRED; + break; + case 428: + rv = NS_ERROR_PROXY_PRECONDITION_REQUIRED; + break; + case 429: + rv = NS_ERROR_PROXY_TOO_MANY_REQUESTS; + break; + case 431: + rv = NS_ERROR_PROXY_REQUEST_HEADER_FIELDS_TOO_LARGE; + break; + case 451: + rv = NS_ERROR_PROXY_UNAVAILABLE_FOR_LEGAL_REASONS; + break; + case 501: + rv = NS_ERROR_PROXY_NOT_IMPLEMENTED; + break; + case 502: + rv = NS_ERROR_PROXY_BAD_GATEWAY; + break; + case 503: + // Squid returns 503 if target request fails for anything but DNS. + /* User sees: "Failed to Connect: + * Firefox can't establish a connection to the server at + * www.foo.com. Though the site seems valid, the browser + * was unable to establish a connection." + */ + rv = NS_ERROR_CONNECTION_REFUSED; + break; + // RFC 2616 uses 504 for both DNS and target timeout, so not clear what to + // do here: picking target timeout, as DNS covered by 400/404/500 + case 504: + rv = NS_ERROR_PROXY_GATEWAY_TIMEOUT; + break; + case 505: + rv = NS_ERROR_PROXY_VERSION_NOT_SUPPORTED; + break; + case 506: + rv = NS_ERROR_PROXY_VARIANT_ALSO_NEGOTIATES; + break; + case 510: + rv = NS_ERROR_PROXY_NOT_EXTENDED; + break; + case 511: + rv = NS_ERROR_PROXY_NETWORK_AUTHENTICATION_REQUIRED; + break; + default: + rv = NS_ERROR_PROXY_CONNECTION_REFUSED; + break; + } + + return rv; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttp.h b/netwerk/protocol/http/nsHttp.h index 2f13af687398..7d0efa53878c 100644 --- a/netwerk/protocol/http/nsHttp.h +++ b/netwerk/protocol/http/nsHttp.h @@ -336,6 +336,11 @@ class ParsedHeaderValueListList { void LogHeaders(const char* lineStart); +// Convert HTTP response codes returned by a proxy to nsresult. +// This function should be only used when we get a failed response to the +// CONNECT method. +nsresult HttpProxyResponseToErrorCode(uint32_t aStatusCode); + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index f72bd9a20b13..5395fe204023 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -1938,67 +1938,7 @@ nsresult nsHttpChannel::ProcessFailedProxyConnect(uint32_t httpStatus) { MOZ_ASSERT(mConnectionInfo->UsingConnect(), "proxy connect failed but not using CONNECT?"); - nsresult rv; - switch (httpStatus) { - case 300: - case 301: - case 302: - case 303: - case 307: - case 308: - // Bad redirect: not top-level, or it's a POST, bad/missing Location, - // or ProcessRedirect() failed for some other reason. Legal - // redirects that fail because site not available, etc., are handled - // elsewhere, in the regular codepath. - rv = NS_ERROR_CONNECTION_REFUSED; - break; - case 403: // HTTP/1.1: "Forbidden" - case 501: // HTTP/1.1: "Not Implemented" - // user sees boilerplate Mozilla "Proxy Refused Connection" page. - rv = NS_ERROR_PROXY_CONNECTION_REFUSED; - break; - case 407: // ProcessAuthentication() failed (e.g. no header) - rv = NS_ERROR_PROXY_AUTHENTICATION_FAILED; - break; - case 429: - rv = NS_ERROR_TOO_MANY_REQUESTS; - break; - // Squid sends 404 if DNS fails (regular 404 from target is tunneled) - case 404: // HTTP/1.1: "Not Found" - // RFC 2616: "some deployed proxies are known to return 400 or - // 500 when DNS lookups time out." (Squid uses 500 if it runs - // out of sockets: so we have a conflict here). - case 400: // HTTP/1.1 "Bad Request" - case 500: // HTTP/1.1: "Internal Server Error" - /* User sees: "Address Not Found: Firefox can't find the server at - * www.foo.com." - */ - rv = NS_ERROR_UNKNOWN_HOST; - break; - case 502: // HTTP/1.1: "Bad Gateway" (invalid resp from target server) - rv = NS_ERROR_PROXY_BAD_GATEWAY; - break; - case 503: // HTTP/1.1: "Service Unavailable" - // Squid returns 503 if target request fails for anything but DNS. - /* User sees: "Failed to Connect: - * Firefox can't establish a connection to the server at - * www.foo.com. Though the site seems valid, the browser - * was unable to establish a connection." - */ - rv = NS_ERROR_CONNECTION_REFUSED; - break; - // RFC 2616 uses 504 for both DNS and target timeout, so not clear what to - // do here: picking target timeout, as DNS covered by 400/404/500 - case 504: // HTTP/1.1: "Gateway Timeout" - // user sees: "Network Timeout: The server at www.foo.com - // is taking too long to respond." - rv = NS_ERROR_PROXY_GATEWAY_TIMEOUT; - break; - // Confused proxy server or malicious response - default: - rv = NS_ERROR_PROXY_CONNECTION_REFUSED; - break; - } + nsresult rv = HttpProxyResponseToErrorCode(httpStatus); LOG(("Cancelling failed proxy CONNECT [this=%p httpStatus=%u]\n", this, httpStatus)); diff --git a/netwerk/test/unit/test_http1-proxy.js b/netwerk/test/unit/test_http1-proxy.js index 7baedec55019..dc00c963bdd9 100644 --- a/netwerk/test/unit/test_http1-proxy.js +++ b/netwerk/test/unit/test_http1-proxy.js @@ -206,7 +206,7 @@ add_task(async function proxy_too_many_requests_failure() { CL_EXPECT_FAILURE ); - Assert.equal(status, Cr.NS_ERROR_TOO_MANY_REQUESTS); + Assert.equal(status, Cr.NS_ERROR_PROXY_TOO_MANY_REQUESTS); Assert.equal(http_code, undefined); }); diff --git a/netwerk/test/unit/test_http2-proxy.js b/netwerk/test/unit/test_http2-proxy.js index 06fbeef071bc..4df0c3baad7f 100644 --- a/netwerk/test/unit/test_http2-proxy.js +++ b/netwerk/test/unit/test_http2-proxy.js @@ -446,7 +446,7 @@ add_task(async function proxy_too_many_requests_failure() { CL_EXPECT_FAILURE ); - Assert.equal(status, Cr.NS_ERROR_TOO_MANY_REQUESTS); + Assert.equal(status, Cr.NS_ERROR_PROXY_TOO_MANY_REQUESTS); Assert.equal(http_code, undefined); Assert.equal( await proxy_session_counter(), diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py index abfb6d6cb51f..91adec6cee78 100755 --- a/xpcom/base/ErrorList.py +++ b/xpcom/base/ErrorList.py @@ -330,14 +330,6 @@ with modules["NETWORK"]: errors["NS_ERROR_NET_INTERRUPT"] = FAILURE(71) # The connection attempt to a proxy failed. errors["NS_ERROR_PROXY_CONNECTION_REFUSED"] = FAILURE(72) - # The proxy requires authentication; used when we can't easily propagate 407s. - errors["NS_ERROR_PROXY_AUTHENTICATION_FAILED"] = FAILURE(407) - # Indicates that we have sent too many requests in a given amount of time. - errors["NS_ERROR_TOO_MANY_REQUESTS"] = FAILURE(429) - # The proxy failed to connect the remote server. - errors["NS_ERROR_PROXY_BAD_GATEWAY"] = FAILURE(502) - # The proxy did get any response from the remote server in time. - errors["NS_ERROR_PROXY_GATEWAY_TIMEOUT"] = FAILURE(504) # A transfer was only partially done when it completed. errors["NS_ERROR_NET_PARTIAL_TRANSFER"] = FAILURE(76) # HTTP/2 detected invalid TLS configuration @@ -460,6 +452,61 @@ with modules["NETWORK"]: # Generic error for non-specific failures during service worker interception errors["NS_ERROR_INTERCEPTION_FAILED"] = FAILURE(100) + # All Http proxy CONNECT response codes + errors["NS_ERROR_PROXY_CODE_BASE"] = FAILURE(1000) + # Redirection 3xx + errors["NS_ERROR_PROXY_MULTIPLE_CHOICES"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 300 + errors["NS_ERROR_PROXY_MOVED_PERMANENTLY"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 301 + errors["NS_ERROR_PROXY_FOUND"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 302 + errors["NS_ERROR_PROXY_SEE_OTHER"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 303 + errors["NS_ERROR_PROXY_NOT_MODIFIED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 304 + errors["NS_ERROR_PROXY_TEMPORARY_REDIRECT"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 307 + errors["NS_ERROR_PROXY_PERMANENT_REDIRECT"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 308 + + # Client error 4xx + errors["NS_ERROR_PROXY_BAD_REQUEST"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 400 + errors["NS_ERROR_PROXY_UNAUTHORIZED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 401 + errors["NS_ERROR_PROXY_PAYMENT_REQUIRED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 402 + errors["NS_ERROR_PROXY_FORBIDDEN"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 403 + errors["NS_ERROR_PROXY_NOT_FOUND"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 404 + errors["NS_ERROR_PROXY_METHOD_NOT_ALLOWED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 405 + errors["NS_ERROR_PROXY_NOT_ACCEPTABLE"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 406 + # The proxy requires authentication; used when we can't easily propagate 407s. + errors["NS_ERROR_PROXY_AUTHENTICATION_FAILED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 407 + errors["NS_ERROR_PROXY_REQUEST_TIMEOUT"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 408 + errors["NS_ERROR_PROXY_CONFLICT"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 409 + errors["NS_ERROR_PROXY_GONE"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 410 + errors["NS_ERROR_PROXY_LENGTH_REQUIRED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 411 + errors["NS_ERROR_PROXY_PRECONDITION_FAILED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 412 + errors["NS_ERROR_PROXY_REQUEST_ENTITY_TOO_LARGE"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 413 + errors["NS_ERROR_PROXY_REQUEST_URI_TOO_LONG"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 414 + errors["NS_ERROR_PROXY_UNSUPPORTED_MEDIA_TYPE"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 415 + errors["NS_ERROR_PROXY_REQUESTED_RANGE_NOT_SATISFIABLE"] = \ + errors["NS_ERROR_PROXY_CODE_BASE"] + 416 + errors["NS_ERROR_PROXY_EXPECTATION_FAILED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 417 + errors["NS_ERROR_PROXY_MISDIRECTED_REQUEST"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 421 + errors["NS_ERROR_PROXY_TOO_EARLY"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 425 + errors["NS_ERROR_PROXY_UPGRADE_REQUIRED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 426 + errors["NS_ERROR_PROXY_PRECONDITION_REQUIRED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 428 + # Indicates that we have sent too many requests in a given amount of time. + errors["NS_ERROR_PROXY_TOO_MANY_REQUESTS"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 429 + errors["NS_ERROR_PROXY_REQUEST_HEADER_FIELDS_TOO_LARGE"] = \ + errors["NS_ERROR_PROXY_CODE_BASE"] + 431 + errors["NS_ERROR_PROXY_UNAVAILABLE_FOR_LEGAL_REASONS"] = \ + errors["NS_ERROR_PROXY_CODE_BASE"] + 451 + + # Server error 5xx + errors["NS_ERROR_PROXY_INTERNAL_SERVER_ERROR"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 500 + errors["NS_ERROR_PROXY_NOT_IMPLEMENTED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 501 + errors["NS_ERROR_PROXY_BAD_GATEWAY"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 502 + errors["NS_ERROR_PROXY_SERVICE_UNAVAILABLE"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 503 + # The proxy did get any response from the remote server in time. + errors["NS_ERROR_PROXY_GATEWAY_TIMEOUT"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 504 + errors["NS_ERROR_PROXY_VERSION_NOT_SUPPORTED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 505 + errors["NS_ERROR_PROXY_VARIANT_ALSO_NEGOTIATES"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 506 + errors["NS_ERROR_PROXY_NOT_EXTENDED"] = errors["NS_ERROR_PROXY_CODE_BASE"] + 510 + errors["NS_ERROR_PROXY_NETWORK_AUTHENTICATION_REQUIRED"] = \ + errors["NS_ERROR_PROXY_CODE_BASE"] + 511 # ======================================================================= # 7: NS_ERROR_MODULE_PLUGINS