Bug 1563824 - New error NS_ERROR_TOO_MANY_REQUESTS for 429 response r=mayhemer

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Kershaw Chang 2019-07-06 21:46:00 +00:00
parent f56a5c0ec4
commit a53a39a584
9 changed files with 50 additions and 1 deletions

View File

@ -4367,6 +4367,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:
// Proxy connection was refused.
error = "proxyConnectFailure";
break;
@ -6962,6 +6963,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_BLOCKED_BY_POLICY) &&
(isTopFrame || UseErrorPages())) {
DisplayLoadError(aStatus, url, nullptr, aChannel);

View File

@ -148,6 +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_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")

View File

@ -1042,6 +1042,9 @@ void SpdyConnectTransaction::MapStreamToHttpConnection(
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;

View File

@ -1960,6 +1960,9 @@ nsresult nsHttpChannel::ProcessFailedProxyConnect(uint32_t httpStatus) {
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
@ -2786,7 +2789,8 @@ nsresult nsHttpChannel::ContinueProcessResponse3(nsresult rv) {
break;
case 425:
// Do not cache 425.
case 429:
// Do not cache 425 and 429.
CloseCacheEntry(false);
MOZ_FALLTHROUGH; // process normally
default:

View File

@ -709,6 +709,7 @@ bool nsHttpResponseHead::MustValidate() {
case 407:
case 412:
case 416:
case 429:
default: // revalidate unknown error pages
LOG(("Must validate since response is an uncacheable error page\n"));
return true;

View File

@ -112,6 +112,9 @@ function connect_handler(request, response) {
response.setStatusLine(request.httpVersion, 407, "Authenticate");
// And deliberately no Proxy-Authenticate header
break;
case "429.example.com":
response.setStatusLine(request.httpVersion, 429, "Too Many Requests");
break;
case "502.example.com":
response.setStatusLine(request.httpVersion, 502, "Bad Gateway");
break;
@ -127,6 +130,7 @@ add_task(async function setup() {
http_server = new HttpServer();
http_server.identity.add("https", "404.example.com", 443);
http_server.identity.add("https", "407.example.com", 443);
http_server.identity.add("https", "429.example.com", 443);
http_server.identity.add("https", "502.example.com", 443);
http_server.identity.add("https", "504.example.com", 443);
http_server.registerPathHandler("CONNECT", connect_handler);
@ -195,6 +199,17 @@ add_task(async function proxy_host_not_found_failure() {
Assert.equal(http_code, undefined);
});
// 429 Too Many Requests means we sent too many requests.
add_task(async function proxy_too_many_requests_failure() {
const { status, http_code } = await get_response(
make_channel(`https://429.example.com/`),
CL_EXPECT_FAILURE
);
Assert.equal(status, Cr.NS_ERROR_TOO_MANY_REQUESTS);
Assert.equal(http_code, undefined);
});
add_task(async function shutdown() {
await new Promise(resolve => {
http_server.stop(resolve);

View File

@ -276,6 +276,21 @@ add_task(async function proxy_host_not_found_failure() {
);
});
add_task(async function proxy_too_many_requests_failure() {
const { status, http_code } = await get_response(
make_channel(`https://429.example.com/`),
CL_EXPECT_FAILURE
);
Assert.equal(status, Cr.NS_ERROR_TOO_MANY_REQUESTS);
Assert.equal(http_code, undefined);
Assert.equal(
await proxy_session_counter(),
1,
"No new session created by 429 after 504"
);
});
// Make sure that the above error codes don't kill the session and we still reach the end server
add_task(async function proxy_success_still_one_session() {
const foo = await get_response(

View File

@ -1213,6 +1213,12 @@ if (http2_internal) {
stream.end();
return;
}
if (target == '429.example.com:443') {
// 429 Too Many Requests, a response code that a proxy should return when receiving too many requests
stream.respond({ ':status': 429 });
stream.end();
return;
}
if (target == '502.example.com:443') {
// 502 Bad Gateway, a response code mostly resembling immediate connection error
stream.respond({ ':status': 502 });

View File

@ -331,6 +331,8 @@ with modules["NETWORK"]:
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.