HTTP Compliance: reply with 504 (Gateway Timeout) if required validation
failed.
RFC 2616 says that we MUST reply with 504 (Gateway Timeout) if
validation fails and cached reply has proxy-revalidate, must-revalidate
or s-maxage Cache-Control directive.
FwdState::makeConnectingError() method is added to set error status
depending on whether the request was a validation request.
Co-Advisor test cases:
test_case/rfc2616/noSrv-hit-must-reval-s-maxage-resp
test_case/rfc2616/noSrv-hit-must-reval-proxy-revalidate-resp
test_case/rfc2616/noSrv-hit-must-reval-must-revalidate-resp
---------
This patch complements an earlier fix that ensured that we forward the
Squid-generated error to the client instead of sending the stale cached
entry when the cached reply has proxy-revalidate, must-revalidate or
s-maxage Cache-Control directive.
HTTP Compliance: reply with 504 (Gateway Timeout) if required validation failed.
RFC 2616 says that we MUST reply with 504 (Gateway Timeout) if validation fails
and cached reply has proxy-revalidate, must-revalidate or s-maxage Cache-Control
directive.
FwdState::makeConnectingError() method is added to set error status depending on
whether the request was a validation request.
Co-Advisor test cases:
test_case/rfc2616/noSrv-hit-must-reval-s-maxage-resp
test_case/rfc2616/noSrv-hit-must-reval-proxy-revalidate-resp
test_case/rfc2616/noSrv-hit-must-reval-must-revalidate-resp
=== modified file 'src/forward.cc'
--- src/forward.cc 2010-09-13 02:25:09 +0000
+++ src/forward.cc 2010-09-16 06:03:33 +0000
@@ -584,41 +584,41 @@ FwdState::negotiateSSL(int fd)
SSL *ssl = fd_table[fd].ssl;
int ret;
if ((ret = SSL_connect(ssl)) <= 0) {
int ssl_error = SSL_get_error(ssl, ret);
switch (ssl_error) {
case SSL_ERROR_WANT_READ:
commSetSelect(fd, COMM_SELECT_READ, fwdNegotiateSSLWrapper, this, 0);
return;
case SSL_ERROR_WANT_WRITE:
commSetSelect(fd, COMM_SELECT_WRITE, fwdNegotiateSSLWrapper, this, 0);
return;
default:
debugs(81, 1, "fwdNegotiateSSL: Error negotiating SSL connection on FD " << fd <<
": " << ERR_error_string(ERR_get_error(), NULL) << " (" << ssl_error <<
"/" << ret << "/" << errno << ")");
- ErrorState *anErr = errorCon(ERR_SECURE_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
+ ErrorState *const anErr = makeConnectingError(ERR_SECURE_CONNECT_FAIL);
#ifdef EPROTO
anErr->xerrno = EPROTO;
#else
anErr->xerrno = EACCES;
#endif
fail(anErr);
if (fs->_peer) {
peerConnectFailed(fs->_peer);
fs->_peer->stats.conn_open--;
}
comm_close(fd);
return;
}
}
@@ -704,50 +704,50 @@ FwdState::connectDone(int aServerFD, con
FwdServer *fs = servers;
assert(server_fd == aServerFD);
request->recordLookup(dns);
if (Config.onoff.log_ip_on_direct && status != COMM_ERR_DNS && fs->code == HIER_DIRECT)
updateHierarchyInfo();
if (status == COMM_ERR_DNS) {
/*
* Only set the dont_retry flag if the DNS lookup fails on
* a direct connection. If DNS lookup fails when trying
* a neighbor cache, we may want to retry another option.
*/
if (NULL == fs->_peer)
flags.dont_retry = 1;
debugs(17, 4, "fwdConnectDone: Unknown host: " << request->GetHost());
- ErrorState *anErr = errorCon(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
+ ErrorState *const anErr = makeConnectingError(ERR_DNS_FAIL);
anErr->dnsError = dns.error;
fail(anErr);
comm_close(server_fd);
} else if (status != COMM_OK) {
assert(fs);
- ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
+ ErrorState *const anErr = makeConnectingError(ERR_CONNECT_FAIL);
anErr->xerrno = xerrno;
fail(anErr);
if (fs->_peer)
peerConnectFailed(fs->_peer);
comm_close(server_fd);
} else {
debugs(17, 3, "fwdConnectDone: FD " << server_fd << ": '" << entry->url() << "'" );
if (fs->_peer)
peerConnectSucceded(fs->_peer);
#if USE_SSL
if ((fs->_peer && fs->_peer->use_ssl) ||
(!fs->_peer && request->protocol == PROTO_HTTPS)) {
initiateSSL();
return;
@@ -1151,40 +1151,53 @@ FwdState::reforward()
if (request->bodyNibbled())
return 0;
assert(fs);
servers = fs->next;
fwdServerFree(fs);
if (servers == NULL) {
debugs(17, 3, "fwdReforward: No forward-servers left");
return 0;
}
s = e->getReply()->sline.status;
debugs(17, 3, "fwdReforward: status " << s);
return reforwardableStatus(s);
}
+/**
+ * Create "503 Service Unavailable" or "504 Gateway Timeout" error depending
+ * on whether this is a validation request. RFC 2616 says that we MUST reply
+ * with "504 Gateway Timeout" if validation fails and cached reply has
+ * proxy-revalidate, must-revalidate or s-maxage Cache-Control directive.
+ */
+ErrorState *
+FwdState::makeConnectingError(const err_type type) const
+{
+ return errorCon(type, request->flags.need_validation ?
+ HTTP_GATEWAY_TIMEOUT : HTTP_SERVICE_UNAVAILABLE, request);
+}
+
static void
fwdStats(StoreEntry * s)
{
int i;
int j;
storeAppendPrintf(s, "Status");
for (j = 0; j <= MAX_FWD_STATS_IDX; j++) {
storeAppendPrintf(s, "\ttry#%d", j + 1);
}
storeAppendPrintf(s, "\n");
for (i = 0; i <= (int) HTTP_INVALID_HEADER; i++) {
if (FwdReplyCodes[0][i] == 0)
continue;
storeAppendPrintf(s, "%3d", i);
for (j = 0; j <= MAX_FWD_STATS_IDX; j++) {
=== modified file 'src/forward.h'
--- src/forward.h 2010-09-12 00:05:59 +0000
+++ src/forward.h 2010-09-16 05:48:05 +0000
@@ -48,40 +48,41 @@ public:
bool dontRetry() { return flags.dont_retry; }
void dontRetry(bool val) { flags.dont_retry = val; }
bool ftpPasvFailed() { return flags.ftp_pasv_failed; }
void ftpPasvFailed(bool val) { flags.ftp_pasv_failed = val; }
static void serversFree(FwdServer **);
private:
// hidden for safer management of self; use static fwdStart
FwdState(int fd, StoreEntry *, HttpRequest *);
void start(Pointer aSelf);
static void logReplyStatus(int tries, http_status status);
void updateHierarchyInfo();
void doneWithRetries();
void completed();
void retryOrBail();
+ ErrorState *makeConnectingError(const err_type type) const;
static void RegisterWithCacheManager(void);
#if WIP_FWD_LOG
void uninit /**DOCS_NOSEMI*/
static void logRotate /**DOCS_NOSEMI*/
void status() /**DOCS_NOSEMI*/
#endif
public:
StoreEntry *entry;
HttpRequest *request;
int server_fd;
FwdServer *servers;
static void abort(void*);
private:
Pointer self;
ErrorState *err;
int client_fd;