*/
#include "squid.h"
-#include "clientStream.h"
-#include "client_side_request.h"
-#include "auth/UserRequest.h"
-#include "HttpRequest.h"
-#include "ProtoPort.h"
#include "acl/FilledChecklist.h"
#include "acl/Gadgets.h"
-#include "client_side.h"
-#include "client_side_reply.h"
-#include "Store.h"
-#include "HttpReply.h"
-#include "MemObject.h"
-#include "ClientRequestContext.h"
-#include "SquidTime.h"
-#include "wordlist.h"
-#include "inet_pton.h"
-#include "fde.h"
-
#if USE_ADAPTATION
#include "adaptation/AccessCheck.h"
#include "adaptation/Iterator.h"
#if ICAP_CLIENT
#include "adaptation/icap/History.h"
#endif
-//static void adaptationAclCheckDoneWrapper(Adaptation::ServicePointer service, void *data);
#endif
-
+#include "auth/UserRequest.h"
+#include "clientStream.h"
+#include "client_side.h"
+#include "client_side_reply.h"
+#include "client_side_request.h"
+#include "ClientRequestContext.h"
+#include "comm/Connection.h"
+#include "compat/inet_pton.h"
+#include "fde.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "ip/QosConfig.h"
+#include "MemObject.h"
+#include "ProtoPort.h"
+#include "Store.h"
+#include "SquidTime.h"
+#include "wordlist.h"
+#include "err_detail_type.h"
#if LINGERING_CLOSE
{
start_time = current_time;
setConn(aConn);
+ clientConnection = aConn->clientConn;
dlinkAdd(this, &active, &ClientActiveRequests);
#if USE_ADAPTATION
request_satisfaction_mode = false;
if (calloutContext)
delete calloutContext;
+ clientConnection = NULL;
+
if (conn_)
cbdataReferenceDone(conn_);
PROF_stop(httpRequestFree);
}
-/* Create a request and kick it off */
-/*
+/**
+ * Create a request and kick it off
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
* TODO: Pass in the buffers to be used in the inital Read request, as they are
* determined by the user
*/
-int /* returns nonzero on failure */
+int
clientBeginRequest(const HttpRequestMethod& method, char const *url, CSCB * streamcallback,
CSD * streamdetach, ClientStreamData streamdata, HttpHeader const *header,
char *tailbuf, size_t taillen)
{
size_t url_sz;
- HttpVersion http_ver (1, 0);
ClientHttpRequest *http = new ClientHttpRequest(NULL);
HttpRequest *request;
StoreIOBuffer tempBuffer;
}
/*
- * now update the headers in request with our supplied headers. urLParse
+ * now update the headers in request with our supplied headers. urlParse
* should return a blank header set, but we use Update to be sure of
* correctness.
*/
request->my_addr.SetPort(0);
+ /* Our version is HTTP/1.1 */
+ HttpVersion http_ver(1,1);
request->http_ver = http_ver;
http->request = HTTPMSGLOCK(request);
#if FOLLOW_X_FORWARDED_FOR
/**
- * clientFollowXForwardedForCheck() checks the indirect_client_addr
+ * clientFollowXForwardedForCheck() checks the content of X-Forwarded-For:
* against the followXFF ACL, or cleans up and passes control to
* clientAccessCheck().
+ *
+ * The trust model here is a little ambiguous. So to clarify the logic:
+ * - we may always use the direct client address as the client IP.
+ * - these trust tests merey tell whether we trust given IP enough to believe the
+ * IP string which it appended to the X-Forwarded-For: header.
+ * - if at any point we don't trust what an IP adds we stop looking.
+ * - at that point the current contents of indirect_client_addr are the value set
+ * by the last previously trusted IP.
+ * ++ indirect_client_addr contains the remote direct client from the trusted peers viewpoint.
*/
-
static void
clientFollowXForwardedForCheck(int answer, void *data)
{
ClientRequestContext *calloutContext = (ClientRequestContext *) data;
- ClientHttpRequest *http = NULL;
- HttpRequest *request = NULL;
if (!calloutContext->httpStateIsValid())
return;
- http = calloutContext->http;
- request = http->request;
+ ClientHttpRequest *http = calloutContext->http;
+ HttpRequest *request = http->request;
+
/*
* answer should be be ACCESS_ALLOWED or ACCESS_DENIED if we are
* called as a result of ACL checks, or -1 if we are called when
*/
if (answer == ACCESS_ALLOWED &&
request->x_forwarded_for_iterator.size () != 0) {
+
/*
- * The IP address currently in request->indirect_client_addr
- * is trusted to use X-Forwarded-For. Remove the last
- * comma-delimited element from x_forwarded_for_iterator and use
- * it to to replace indirect_client_addr, then repeat the cycle.
- */
+ * Remove the last comma-delimited element from the
+ * x_forwarded_for_iterator and use it to repeat the cycle.
+ */
const char *p;
const char *asciiaddr;
int l;
- struct in_addr addr;
+ Ip::Address addr;
p = request->x_forwarded_for_iterator.termedBuf();
l = request->x_forwarded_for_iterator.size();
while (l > 0 && ! (p[l-1] == ',' || xisspace(p[l-1])))
l--;
asciiaddr = p+l;
- if (xinet_pton(AF_INET, asciiaddr, &addr) != 0) {
+ if ((addr = asciiaddr)) {
request->indirect_client_addr = addr;
request->x_forwarded_for_iterator.cut(l);
- if (! Config.onoff.acl_uses_indirect_client) {
- /*
- * If acl_uses_indirect_client is off, then it's impossible
- * to follow more than one level of X-Forwarded-For.
- */
- request->x_forwarded_for_iterator.clean();
+ calloutContext->acl_checklist = clientAclChecklistCreate(Config.accessList.followXFF, http);
+ if (!Config.onoff.acl_uses_indirect_client) {
+ /* override the default src_addr tested if we have to go deeper than one level into XFF */
+ Filled(calloutContext->acl_checklist)->src_addr = request->indirect_client_addr;
}
- calloutContext->acl_checklist =
- clientAclChecklistCreate(Config.accessList.followXFF, http);
- calloutContext->acl_checklist->
- nonBlockingCheck(clientFollowXForwardedForCheck, data);
+ calloutContext->acl_checklist->nonBlockingCheck(clientFollowXForwardedForCheck, data);
return;
}
} /*if (answer == ACCESS_ALLOWED &&
request->x_forwarded_for_iterator.clean();
request->flags.done_follow_x_forwarded_for = 1;
- /* If follow XFF is denied, we reset the indirect_client_addr
- to the direct client. Thats the one we are configured to check for */
- if (answer == ACCESS_DENIED) {
- request->indirect_client_addr = request->client_addr;
- }
- /* on a failure, leave it as undefined state ?? */
- else if (answer != ACCESS_ALLOWED) {
- debugs(28, DBG_CRITICAL, "Follow X-Forwarded-For encountered an error. Ignoring address: " << request->indirect_client_addr );
- request->indirect_client_addr = request->client_addr;
+ if (answer != ACCESS_ALLOWED && answer != ACCESS_DENIED) {
+ debugs(28, DBG_CRITICAL, "ERROR: Processing X-Forwarded-For. Stopping at IP address: " << request->indirect_client_addr );
}
/* process actual access ACL as normal. */
if (!http->request->flags.done_follow_x_forwarded_for &&
Config.accessList.followXFF &&
http->request->header.has(HDR_X_FORWARDED_FOR)) {
- http->request->x_forwarded_for_iterator =
- http->request->header.getList(HDR_X_FORWARDED_FOR);
- clientFollowXForwardedForCheck(ACCESS_ALLOWED, this);
+
+ /* we always trust the direct client address for actual use */
+ http->request->indirect_client_addr = http->request->client_addr;
+ http->request->indirect_client_addr.SetPort(0);
+
+ /* setup the XFF iterator for processing */
+ http->request->x_forwarded_for_iterator = http->request->header.getList(HDR_X_FORWARDED_FOR);
+
+ /* begin by checking to see if we trust direct client enough to walk XFF */
+ acl_checklist = clientAclChecklistCreate(Config.accessList.followXFF, http);
+ acl_checklist->nonBlockingCheck(clientFollowXForwardedForCheck, this);
return;
}
#endif /* FOLLOW_X_FORWARDED_FOR */
}
}
+/**
+ * Identical in operation to clientAccessCheck() but performed later using different configured ACL list.
+ * The default here is to allow all. Since the earlier http_access should do a default deny all.
+ * This check is just for a last-minute denial based on adapted request headers.
+ */
+void
+ClientRequestContext::clientAccessCheck2()
+{
+ if (Config.accessList.adapted_http) {
+ acl_checklist = clientAclChecklistCreate(Config.accessList.adapted_http, http);
+ acl_checklist->nonBlockingCheck(clientAccessCheckDoneWrapper, this);
+ } else {
+ debugs(85, 2, HERE << "No adapted_http_access configuration. default: ALLOW");
+ clientAccessCheckDone(ACCESS_ALLOWED);
+ }
+}
+
void
clientAccessCheckDoneWrapper(int answer, void *data)
{
clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
- IpAddress tmpnoaddr;
+ Ip::Address tmpnoaddr;
tmpnoaddr.SetNoAddr();
repContext->setReplyToError(page_id, status,
http->request->method, NULL,
- http->getConn() != NULL ? http->getConn()->peer : tmpnoaddr,
+ http->getConn() != NULL ? http->getConn()->clientConn->remote : tmpnoaddr,
http->request,
NULL,
- http->getConn() != NULL && http->getConn()->auth_user_request ?
+ http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
http->getConn()->auth_user_request : http->request->auth_user_request);
node = (clientStreamNode *)http->client_stream.tail->data;
debugs(93,3,HERE << this << " adaptationAclCheckDone called");
assert(http);
-#if ICAP_CLIENT
+#if ICAP_CLIENT
Adaptation::Icap::History::Pointer ih = http->request->icapHistory();
- if(ih != NULL)
- {
- if (http->getConn() != NULL)
- {
+ if (ih != NULL) {
+ if (http->getConn() != NULL) {
ih->rfc931 = http->getConn()->rfc931;
-#if USE_SSL
- ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->fd].ssl);
-#endif
+#if USE_SSL
+ assert(http->getConn()->clientConn != NULL);
+ ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->clientConn->fd].ssl);
+#endif
}
ih->log_uri = http->log_uri;
ih->req_sz = http->req_sz;
}
+static void
+clientCheckPinning(ClientHttpRequest * http)
+{
+ HttpRequest *request = http->request;
+ HttpHeader *req_hdr = &request->header;
+ ConnStateData *http_conn = http->getConn();
+
+ /* Internal requests such as those from ESI includes may be without
+ * a client connection
+ */
+ if (!http_conn)
+ return;
+
+ request->flags.connection_auth_disabled = http_conn->port->connection_auth_disabled;
+ if (!request->flags.connection_auth_disabled) {
+ if (http_conn->pinning.fd != -1) {
+ if (http_conn->pinning.auth) {
+ request->flags.connection_auth = 1;
+ request->flags.auth = 1;
+ } else {
+ request->flags.connection_proxy_auth = 1;
+ }
+ request->setPinnedConnection(http_conn);
+ }
+ }
+
+ /* check if connection auth is used, and flag as candidate for pinning
+ * in such case.
+ * Note: we may need to set flags.connection_auth even if the connection
+ * is already pinned if it was pinned earlier due to proxy auth
+ */
+ if (!request->flags.connection_auth) {
+ if (req_hdr->has(HDR_AUTHORIZATION) || req_hdr->has(HDR_PROXY_AUTHORIZATION)) {
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ HttpHeaderEntry *e;
+ int may_pin = 0;
+ while ((e = req_hdr->getEntry(&pos))) {
+ if (e->id == HDR_AUTHORIZATION || e->id == HDR_PROXY_AUTHORIZATION) {
+ const char *value = e->value.rawBuf();
+ if (strncasecmp(value, "NTLM ", 5) == 0
+ ||
+ strncasecmp(value, "Negotiate ", 10) == 0
+ ||
+ strncasecmp(value, "Kerberos ", 9) == 0) {
+ if (e->id == HDR_AUTHORIZATION) {
+ request->flags.connection_auth = 1;
+ may_pin = 1;
+ } else {
+ request->flags.connection_proxy_auth = 1;
+ may_pin = 1;
+ }
+ }
+ }
+ }
+ if (may_pin && !request->pinnedConnection()) {
+ request->setPinnedConnection(http->getConn());
+ }
+ }
+ }
+}
+
static void
clientInterpretRequestHeaders(ClientHttpRequest * http)
{
HttpRequest *request = http->request;
HttpHeader *req_hdr = &request->header;
int no_cache = 0;
-#if !(USE_SQUID_ESI) || defined(USE_USERAGENT_LOG) || defined(USE_REFERER_LOG)
-
const char *str;
-#endif
request->imslen = -1;
request->ims = req_hdr->getTime(HDR_IF_MODIFIED_SINCE);
if (request->ims > 0)
request->flags.ims = 1;
-#if USE_SQUID_ESI
- /*
- * We ignore Cache-Control as per the Edge Architecture Section 3. See
- * www.esi.org for more information.
- */
-#else
-
- if (req_hdr->has(HDR_PRAGMA)) {
- String s = req_hdr->getList(HDR_PRAGMA);
+ if (!request->flags.ignore_cc) {
+ if (req_hdr->has(HDR_PRAGMA)) {
+ String s = req_hdr->getList(HDR_PRAGMA);
- if (strListIsMember(&s, "no-cache", ','))
- no_cache++;
+ if (strListIsMember(&s, "no-cache", ','))
+ no_cache++;
- s.clean();
- }
+ s.clean();
+ }
- if (request->cache_control)
- if (EBIT_TEST(request->cache_control->mask, CC_NO_CACHE))
- no_cache++;
+ if (request->cache_control)
+ if (EBIT_TEST(request->cache_control->mask, CC_NO_CACHE))
+ no_cache++;
- /*
- * Work around for supporting the Reload button in IE browsers when Squid
- * is used as an accelerator or transparent proxy, by turning accelerated
- * IMS request to no-cache requests. Now knows about IE 5.5 fix (is
- * actually only fixed in SP1, but we can't tell whether we are talking to
- * SP1 or not so all 5.5 versions are treated 'normally').
- */
- if (Config.onoff.ie_refresh) {
- if (http->flags.accel && request->flags.ims) {
- if ((str = req_hdr->getStr(HDR_USER_AGENT))) {
- if (strstr(str, "MSIE 5.01") != NULL)
- no_cache++;
- else if (strstr(str, "MSIE 5.0") != NULL)
- no_cache++;
- else if (strstr(str, "MSIE 4.") != NULL)
- no_cache++;
- else if (strstr(str, "MSIE 3.") != NULL)
- no_cache++;
+ /*
+ * Work around for supporting the Reload button in IE browsers when Squid
+ * is used as an accelerator or transparent proxy, by turning accelerated
+ * IMS request to no-cache requests. Now knows about IE 5.5 fix (is
+ * actually only fixed in SP1, but we can't tell whether we are talking to
+ * SP1 or not so all 5.5 versions are treated 'normally').
+ */
+ if (Config.onoff.ie_refresh) {
+ if (http->flags.accel && request->flags.ims) {
+ if ((str = req_hdr->getStr(HDR_USER_AGENT))) {
+ if (strstr(str, "MSIE 5.01") != NULL)
+ no_cache++;
+ else if (strstr(str, "MSIE 5.0") != NULL)
+ no_cache++;
+ else if (strstr(str, "MSIE 4.") != NULL)
+ no_cache++;
+ else if (strstr(str, "MSIE 3.") != NULL)
+ no_cache++;
+ }
}
}
}
no_cache++;
}
-#endif
if (no_cache) {
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
if (Config.onoff.reload_into_ims)
request->flags.nocache_hack = 1;
/* ignore range header in non-GETs or non-HEADs */
if (request->method == METHOD_GET || request->method == METHOD_HEAD) {
- request->range = req_hdr->getRange();
+ // XXX: initialize if we got here without HttpRequest::parseHeader()
+ if (!request->range)
+ request->range = req_hdr->getRange();
if (request->range) {
request->flags.range = 1;
else {
req_hdr->delById(HDR_RANGE);
req_hdr->delById(HDR_REQUEST_RANGE);
+ delete request->range;
request->range = NULL;
}
if (req_hdr->has(HDR_AUTHORIZATION))
request->flags.auth = 1;
- ConnStateData *http_conn = http->getConn();
- assert(http_conn);
- request->flags.connection_auth_disabled = http_conn->port->connection_auth_disabled;
- if (!request->flags.connection_auth_disabled) {
- if (http_conn->pinning.fd != -1) {
- if (http_conn->pinning.auth) {
- request->flags.connection_auth = 1;
- request->flags.auth = 1;
- } else {
- request->flags.connection_proxy_auth = 1;
- }
- request->setPinnedConnection(http_conn);
- }
- }
-
- /* check if connection auth is used, and flag as candidate for pinning
- * in such case.
- * Note: we may need to set flags.connection_auth even if the connection
- * is already pinned if it was pinned earlier due to proxy auth
- */
- if (!request->flags.connection_auth) {
- if (req_hdr->has(HDR_AUTHORIZATION) || req_hdr->has(HDR_PROXY_AUTHORIZATION)) {
- HttpHeaderPos pos = HttpHeaderInitPos;
- HttpHeaderEntry *e;
- int may_pin = 0;
- while ((e = req_hdr->getEntry(&pos))) {
- if (e->id == HDR_AUTHORIZATION || e->id == HDR_PROXY_AUTHORIZATION) {
- const char *value = e->value.rawBuf();
- if (strncasecmp(value, "NTLM ", 5) == 0
- ||
- strncasecmp(value, "Negotiate ", 10) == 0
- ||
- strncasecmp(value, "Kerberos ", 9) == 0) {
- if (e->id == HDR_AUTHORIZATION) {
- request->flags.connection_auth = 1;
- may_pin = 1;
- } else {
- request->flags.connection_proxy_auth = 1;
- may_pin = 1;
- }
- }
- }
- }
- if (may_pin && !request->pinnedConnection()) {
- request->setPinnedConnection(http->getConn());
- }
- }
- }
-
+ clientCheckPinning(http);
if (request->login[0] != '\0')
request->flags.auth = 1;
request->flags.loopdetect = 1;
}
-#if FORW_VIA_DB
+#if USE_FORW_VIA_DB
fvdbCountVia(s.termedBuf());
#endif
logReferer(fqdnFromAddr(http->getConn()->log_addr), str, http->log_uri);
#endif
-#if FORW_VIA_DB
+#if USE_FORW_VIA_DB
if (req_hdr->has(HDR_X_FORWARDED_FOR)) {
String s = req_hdr->getList(HDR_X_FORWARDED_FOR);
}
#endif
- if (request->method == METHOD_TRACE || request->method == METHOD_OPTIONS) {
- request->max_forwards = req_hdr->getInt64(HDR_MAX_FORWARDS);
- }
request->flags.cachable = http->request->cacheable();
if ((t = strchr(result, ':')) != NULL) {
http->redirect.status = status;
http->redirect.location = xstrdup(t + 1);
+ // TODO: validate the URL produced here is RFC 2616 compliant absolute URI
} else {
- debugs(85, 1, "clientRedirectDone: bad input: " << result);
+ if (old_request->http_ver < HttpVersion(1,1))
+ debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid 302 redirect Location: " << result);
+ else
+ debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid 303 redirect Location: " << result);
}
- } else if (strcmp(result, http->uri))
- new_request = HttpRequest::CreateFromUrlAndMethod(result, old_request->method);
+ } else if (strcmp(result, http->uri)) {
+ if (!(new_request = HttpRequest::CreateFromUrlAndMethod(result, old_request->method)))
+ debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid request: " <<
+ old_request->method << " " << result << " HTTP/1.1");
+ }
}
if (new_request) {
new_request->my_addr = old_request->my_addr;
new_request->flags = old_request->flags;
new_request->flags.redirected = 1;
-
- if (old_request->auth_user_request) {
- new_request->auth_user_request = old_request->auth_user_request;
- AUTHUSERREQUESTLOCK(new_request->auth_user_request, "new request");
- }
+ new_request->auth_user_request = old_request->auth_user_request;
if (old_request->body_pipe != NULL) {
new_request->body_pipe = old_request->body_pipe;
/* FIXME PIPELINE: This is innacurate during pipelining */
- if (http->getConn() != NULL)
- fd_note(http->getConn()->fd, http->uri);
+ if (http->getConn() != NULL && Comm::IsConnOpen(http->getConn()->clientConn))
+ fd_note(http->getConn()->clientConn->fd, http->uri);
assert(http->uri);
if (request->method == METHOD_CONNECT && !redirect.status) {
logType = LOG_TCP_MISS;
+ getConn()->stopReading(); // tunnels read for themselves
tunnelStart(this, &out.size, &al.http.code);
return;
}
// called when comm_write has completed
static void
-SslBumpEstablish(int, char *, size_t, comm_err_t errflag, int, void *data)
+SslBumpEstablish(const Comm::ConnectionPointer &, char *, size_t, comm_err_t errflag, int, void *data)
{
ClientHttpRequest *r = static_cast<ClientHttpRequest*>(data);
debugs(85, 5, HERE << "responded to CONNECT: " << r << " ? " << errflag);
void
ClientHttpRequest::sslBumpStart()
{
- debugs(85, 5, HERE << "ClientHttpRequest::sslBumpStart");
-
+ debugs(85, 5, HERE << "Confirming CONNECT tunnel on FD " << getConn()->clientConn);
// send an HTTP 200 response to kick client SSL negotiation
- const int fd = getConn()->fd;
- debugs(33, 7, HERE << "Confirming CONNECT tunnel on FD " << fd);
+ debugs(33, 7, HERE << "Confirming CONNECT tunnel on FD " << getConn()->clientConn);
// TODO: Unify with tunnel.cc and add a Server(?) header
- static const char *const conn_established =
- "HTTP/1.0 200 Connection established\r\n\r\n";
- comm_write(fd, conn_established, strlen(conn_established),
- &SslBumpEstablish, this, NULL);
+ static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
+ comm_write(getConn()->clientConn, conn_established, strlen(conn_established), &SslBumpEstablish, this, NULL);
}
#endif
* the callout. This is strictly for convenience.
*/
-extern int aclMapTOS (acl_tos * head, ACLChecklist * ch);
+extern tos_t aclMapTOS (acl_tos * head, ACLChecklist * ch);
+extern nfmark_t aclMapNfmark (acl_nfmark * head, ACLChecklist * ch);
void
ClientHttpRequest::doCallouts()
{
assert(calloutContext);
+ /*Save the original request for logging purposes*/
+ if (!calloutContext->http->al.request)
+ calloutContext->http->al.request = HTTPMSGLOCK(request);
+
if (!calloutContext->http_access_done) {
debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()");
calloutContext->http_access_done = true;
}
}
+ if (!calloutContext->adapted_http_access_done) {
+ debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()");
+ calloutContext->adapted_http_access_done = true;
+ calloutContext->clientAccessCheck2();
+ return;
+ }
+
if (!calloutContext->interpreted_req_hdrs) {
debugs(83, 3, HERE << "Doing clientInterpretRequestHeaders()");
calloutContext->interpreted_req_hdrs = 1;
}
}
- if (!calloutContext->clientside_tos_done) {
- calloutContext->clientside_tos_done = true;
- if (getConn() != NULL) {
+ if (!calloutContext->tosToClientDone) {
+ calloutContext->tosToClientDone = true;
+ if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConn)) {
ACLFilledChecklist ch(NULL, request, NULL);
ch.src_addr = request->client_addr;
ch.my_addr = request->my_addr;
- int tos = aclMapTOS(Config.accessList.clientside_tos, &ch);
+ tos_t tos = aclMapTOS(Ip::Qos::TheConfig.tosToClient, &ch);
if (tos)
- comm_set_tos(getConn()->fd, tos);
+ Ip::Qos::setSockTos(getConn()->clientConn, tos);
+ }
+ }
+
+ if (!calloutContext->nfmarkToClientDone) {
+ calloutContext->nfmarkToClientDone = true;
+ if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConn)) {
+ ACLFilledChecklist ch(NULL, request, NULL);
+ ch.src_addr = request->client_addr;
+ ch.my_addr = request->my_addr;
+ nfmark_t mark = aclMapNfmark(Ip::Qos::TheConfig.nfmarkToClient, &ch);
+ if (mark)
+ Ip::Qos::setSockNfmark(getConn()->clientConn, mark);
}
}
#endif
}
-#ifndef _USE_INLINE_
+#if !_USE_INLINE_
#include "client_side_request.cci"
#endif
assert(!virginHeadSource);
assert(!adaptedBodySource);
virginHeadSource = initiateAdaptation(
- new Adaptation::Iterator(this, request, NULL, g));
+ new Adaptation::Iterator(request, NULL, g));
- // we could try to guess whether we can bypass this adaptation
+ // we could try to guess whether we can bypass this adaptation
// initiation failure, but it should not really happen
- assert(virginHeadSource != NULL); // Must, really
+ Must(initiated(virginHeadSource));
}
void
// subscribe to receive reply body
if (new_rep->body_pipe != NULL) {
adaptedBodySource = new_rep->body_pipe;
- assert(adaptedBodySource->setConsumerIfNotLate(this));
+ int consumer_ok = adaptedBodySource->setConsumerIfNotLate(this);
+ assert(consumer_ok);
}
clientStreamNode *node = (clientStreamNode *)client_stream.tail->prev->data;
request_satisfaction_mode = true;
request_satisfaction_offset = 0;
storeEntry()->replaceHttpReply(new_rep);
+ storeEntry()->timestampsSet();
if (!adaptedBodySource) // no body
storeEntry()->complete();
{
clearAdaptation(virginHeadSource);
assert(!adaptedBodySource);
- handleAdaptationFailure(!final);
+ handleAdaptationFailure(ERR_DETAIL_ICAP_REQMOD_ABORT, !final);
}
void
{
assert(!virginHeadSource);
stopConsumingFrom(adaptedBodySource);
- handleAdaptationFailure();
+ handleAdaptationFailure(ERR_DETAIL_ICAP_RESPMOD_CLT_SIDE_BODY);
}
void
-ClientHttpRequest::handleAdaptationFailure(bool bypassable)
+ClientHttpRequest::handleAdaptationFailure(int errDetail, bool bypassable)
{
debugs(85,3, HERE << "handleAdaptationFailure(" << bypassable << ")");
// The original author of the code also wanted to pass an errno to
// setReplyToError, but it seems unlikely that the errno reflects the
// true cause of the error at this point, so I did not pass it.
- IpAddress noAddr;
+ Ip::Address noAddr;
noAddr.SetNoAddr();
ConnStateData * c = getConn();
repContext->setReplyToError(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
request->method, NULL,
- (c != NULL ? c->peer : noAddr), request, NULL,
- (c != NULL && c->auth_user_request ?
+ (c != NULL ? c->clientConn->remote : noAddr), request, NULL,
+ (c != NULL && c->auth_user_request != NULL ?
c->auth_user_request : request->auth_user_request));
+ request->detailError(ERR_ICAP_FAILURE, errDetail);
+
node = (clientStreamNode *)client_stream.tail->data;
clientStreamRead(node, this, node->readBuffer);
}