Hello,
This patch introduces a new ACL-driven " risky_server_pconn_reuse" option.
This option provides fine-grained control over persistent connection
reuse when forwarding HTTP requests that Squid cannot retry. It is useful
in environments where opening new connections is very expensive
(e.g., all connections are secured with TLS with complex client and server
certificate validation) and race conditions associated with persistent
connections are very rare and/or only cause minor problems.
Example:
acl SpeedIsWorthTheRisk method POST
risky_server_pconn_reuse allow SpeedIsWorthTheRisk
Regards,
Eduard.
Added a new ACL-driven risky_server_pconn_reuse option.
This option provides fine-grained control over persistent connection
reuse when forwarding HTTP requests that Squid cannot retry. It is useful
in environments where opening new connections is very expensive
(e.g., all connections are secured with TLS with complex client and server
certificate validation) and race conditions associated with persistent
connections are very rare and/or only cause minor problems.
=== modified file 'src/FwdState.cc'
--- src/FwdState.cc 2016-02-13 05:44:58 +0000
+++ src/FwdState.cc 2016-03-07 10:55:35 +0000
@@ -560,68 +560,61 @@
}
if (entry->store_status != STORE_PENDING)
return false;
if (!entry->isEmpty())
return false;
if (n_tries > Config.forward_max_tries)
return false;
if (squid_curtime - start_t > Config.Timeout.forward)
return false;
if (flags.dont_retry)
return false;
if (request->bodyNibbled())
return false;
// NP: not yet actually connected anywhere. retry is safe.
if (!flags.connected_okay)
return true;
if (!checkRetriable())
return false;
return true;
}
-/*
- * FwdState::checkRetriable
- *
- * Return TRUE if this is the kind of request that can be retried
- * after a failure. If the request is not retriable then we don't
- * want to risk sending it on a persistent connection. Instead we'll
- * force it to go on a new HTTP connection.
- */
+/// Whether we may try sending this request again after a failure.
bool
FwdState::checkRetriable()
{
// Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
// complicated] code required to protect the PUT request body from being
// nibbled during the first try. Thus, Squid cannot retry some PUTs today.
if (request->body_pipe != NULL)
return false;
// RFC2616 9.1 Safe and Idempotent Methods
return (request->method.isHttpSafe() || request->method.isIdempotent());
}
void
FwdState::serverClosed(int fd)
{
// XXX: fd is often -1 here
debugs(17, 2, "FD " << fd << " " << entry->url() << " after " <<
(fd >= 0 ? fd_table[fd].pconn.uses : -1) << " requests");
if (fd >= 0 && serverConnection()->fd == fd)
fwdPconnPool->noteUses(fd_table[fd].pconn.uses);
retryOrBail();
}
void
FwdState::retryOrBail()
{
if (checkRetry()) {
debugs(17, 3, HERE << "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
// we should retry the same destination if it failed due to pconn race
@@ -1158,63 +1151,68 @@
case Http::scServiceUnavailable:
return Config.retry.onerror;
default:
return false;
}
/* NOTREACHED */
}
/**
* Decide where details need to be gathered to correctly describe a persistent connection.
* What is needed:
* - the address/port details about this link
* - domain name of server at other end of this link (either peer or requested host)
*/
void
FwdState::pconnPush(Comm::ConnectionPointer &conn, const char *domain)
{
if (conn->getPeer()) {
fwdPconnPool->push(conn, NULL);
} else {
fwdPconnPool->push(conn, domain);
}
}
Comm::ConnectionPointer
FwdState::pconnPop(const Comm::ConnectionPointer &dest, const char *domain)
{
+ bool retriable = checkRetriable();
+ if (!retriable && Config.accessList.riskyServerPconnReuse) {
+ ACLFilledChecklist ch(Config.accessList.riskyServerPconnReuse, request, NULL);
+ retriable = (ch.fastCheck() == ACCESS_ALLOWED);
+ }
// always call shared pool first because we need to close an idle
// connection there if we have to use a standby connection.
- Comm::ConnectionPointer conn = fwdPconnPool->pop(dest, domain, checkRetriable());
+ Comm::ConnectionPointer conn = fwdPconnPool->pop(dest, domain, retriable);
if (!Comm::IsConnOpen(conn)) {
// either there was no pconn to pop or this is not a retriable xaction
if (CachePeer *peer = dest->getPeer()) {
if (peer->standby.pool)
conn = peer->standby.pool->pop(dest, domain, true);
}
}
return conn; // open, closed, or nil
}
void
FwdState::initModule()
{
RegisterWithCacheManager();
}
void
FwdState::RegisterWithCacheManager(void)
{
Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
}
void
FwdState::logReplyStatus(int tries, const Http::StatusCode status)
{
if (status > Http::scInvalidHeader)
return;
assert(tries >= 0);
=== modified file 'src/SquidConfig.h'
--- src/SquidConfig.h 2016-01-15 06:47:59 +0000
+++ src/SquidConfig.h 2016-03-07 10:51:00 +0000
@@ -338,60 +338,61 @@
#if USE_OPENSSL
bool logTlsServerHelloDetails;
#endif
} onoff;
int pipeline_max_prefetch;
int forward_max_tries;
int connect_retries;
class ACL *aclList;
struct {
acl_access *http;
acl_access *adapted_http;
acl_access *icp;
acl_access *miss;
acl_access *NeverDirect;
acl_access *AlwaysDirect;
acl_access *ASlists;
acl_access *noCache;
acl_access *sendHit;
acl_access *storeMiss;
acl_access *stats_collection;
#if SQUID_SNMP
acl_access *snmp;
#endif
#if USE_HTTP_VIOLATIONS
acl_access *brokenPosts;
+ acl_access *riskyServerPconnReuse;
#endif
acl_access *redirector;
acl_access *store_id;
acl_access *reply;
Acl::Address *outgoing_address;
#if USE_HTCP
acl_access *htcp;
acl_access *htcp_clr;
#endif
#if USE_OPENSSL
acl_access *ssl_bump;
#endif
#if FOLLOW_X_FORWARDED_FOR
acl_access *followXFF;
#endif /* FOLLOW_X_FORWARDED_FOR */
/// acceptible PROXY protocol clients
acl_access *proxyProtocol;
/// spoof_client_ip squid.conf acl.
/// nil unless configured
acl_access* spoof_client_ip;
acl_access *on_unsupported_protocol;
acl_access *ftp_epsv;
acl_access *forceRequestBodyContinuation;
} accessList;
=== modified file 'src/cf.data.pre'
--- src/cf.data.pre 2016-02-19 17:19:25 +0000
+++ src/cf.data.pre 2016-03-07 10:51:00 +0000
@@ -9605,31 +9605,66 @@
NAME: force_request_body_continuation
TYPE: acl_access
LOC: Config.accessList.forceRequestBodyContinuation
DEFAULT: none
DEFAULT_DOC: Deny, unless rules exist in squid.conf.
DOC_START
This option controls how Squid handles data upload requests from HTTP
and FTP agents that require a "Please Continue" control message response
to actually send the request body to Squid. It is mostly useful in
adaptation environments.
When Squid receives an HTTP request with an "Expect: 100-continue"
header or an FTP upload command (e.g., STOR), Squid normally sends the
request headers or FTP command information to an adaptation service (or
peer) and waits for a response. Most adaptation services (and some
broken peers) may not respond to Squid at that stage because they may
decide to wait for the HTTP request body or FTP data transfer. However,
that request body or data transfer may never come because Squid has not
responded with the HTTP 100 or FTP 150 (Please Continue) control message
to the request sender yet!
An allow match tells Squid to respond with the HTTP 100 or FTP 150
(Please Continue) control message on its own, before forwarding the
request to an adaptation service or peer. Such a response usually forces
the request sender to proceed with sending the body. A deny match tells
Squid to delay that control response until the origin server confirms
that the request body is needed. Delaying is the default behavior.
DOC_END
+NAME: risky_server_pconn_reuse
+IFDEF: USE_HTTP_VIOLATIONS
+TYPE: acl_access
+DEFAULT: none
+DEFAULT_DOC: Open new connections for forwarding requests Squid cannot retry safely.
+LOC: Config.accessList.riskyServerPconnReuse
+DOC_START
+ This option provides fine-grained control over persistent connection
+ reuse when forwarding HTTP requests that Squid cannot retry. It is useful
+ in environments where opening new connections is very expensive
+ (e.g., all connections are secured with TLS with complex client and server
+ certificate validation) and race conditions associated with persistent
+ connections are very rare and/or only cause minor problems.
+
+ HTTP prohibits retrying unsafe and non-idempotent requests (e.g., POST).
+ Squid limitations also prohibit retrying all requests with bodies (e.g., PUT).
+ By default, when forwarding such "risky" requests, Squid opens a new
+ connection to the server or cache_peer, even if there is an idle persistent
+ connection available.
+
+ If an allow rule matches, Squid reuses an available idle persistent connection
+ (if any) for the request that Squid cannot retry. If a deny rule matches, then
+ Squid opens a new connection for the request that Squid cannot retry.
+
+ This option does not affect requests that Squid can retry. They will reuse idle
+ persistent connections (if any).
+
+ This clause only supports fast acl types.
+ See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
+
+ Example:
+ acl SpeedIsWorthTheRisk method POST
+ risky_server_pconn_reuse allow SpeedIsWorthTheRisk
+DOC_END
+
EOF
_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev