]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/client_side_request.cc
Merge form trunk
[thirdparty/squid.git] / src / client_side_request.cc
index a2b20f5f125e5c380a99f3e049840f72689d7e90..4608f180c052779e73bc7f4cb157503c225e9b2e 100644 (file)
 #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
@@ -159,6 +162,7 @@ ClientHttpRequest::ClientHttpRequest(ConnStateData * aConn) :
 {
     start_time = current_time;
     setConn(aConn);
+    clientConnection = aConn->clientConn;
     dlinkAdd(this, &active, &ClientActiveRequests);
 #if USE_ADAPTATION
     request_satisfaction_mode = false;
@@ -273,6 +277,8 @@ ClientHttpRequest::~ClientHttpRequest()
     if (calloutContext)
         delete calloutContext;
 
+    clientConnection = NULL;
+
     if (conn_)
         cbdataReferenceDone(conn_);
 
@@ -541,7 +547,7 @@ ClientRequestContext::clientAccessCheck2()
         acl_checklist = clientAclChecklistCreate(Config.accessList.adapted_http, http);
         acl_checklist->nonBlockingCheck(clientAccessCheckDoneWrapper, this);
     } else {
-        debugs(85, 2, HERE << "No adapted_http_access configuration.");
+        debugs(85, 2, HERE << "No adapted_http_access configuration. default: ALLOW");
         clientAccessCheckDone(ACCESS_ALLOWED);
     }
 }
@@ -620,7 +626,7 @@ ClientRequestContext::clientAccessCheckDone(int answer)
         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 != NULL ?
@@ -663,7 +669,8 @@ ClientRequestContext::adaptationAclCheckDone(Adaptation::ServiceGroupPointer g)
         if (http->getConn() != NULL) {
             ih->rfc931 = http->getConn()->rfc931;
 #if USE_SSL
-            ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->fd].ssl);
+            assert(http->getConn()->clientConn != NULL);
+            ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->clientConn->fd].ssl);
 #endif
         }
         ih->log_uri = http->log_uri;
@@ -888,7 +895,9 @@ clientInterpretRequestHeaders(ClientHttpRequest * http)
 
     /* 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;
@@ -912,6 +921,7 @@ clientInterpretRequestHeaders(ClientHttpRequest * http)
     else {
         req_hdr->delById(HDR_RANGE);
         req_hdr->delById(HDR_REQUEST_RANGE);
+        delete request->range;
         request->range = NULL;
     }
 
@@ -969,9 +979,6 @@ clientInterpretRequestHeaders(ClientHttpRequest * http)
     }
 
 #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();
 
@@ -1019,11 +1026,18 @@ ClientRequestContext::clientRedirectDone(char *result)
             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) {
@@ -1056,8 +1070,8 @@ ClientRequestContext::clientRedirectDone(char *result)
 
     /* 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);
 
@@ -1117,6 +1131,7 @@ ClientHttpRequest::processRequest()
 
     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;
     }
@@ -1158,7 +1173,7 @@ ClientHttpRequest::sslBumpNeeded() const
 
 // 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);
@@ -1185,17 +1200,13 @@ ClientHttpRequest::sslBumpEstablish(comm_err_t 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
@@ -1264,7 +1275,8 @@ ClientHttpRequest::loggingEntry(StoreEntry *newEntry)
  * 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()
@@ -1327,15 +1339,27 @@ ClientHttpRequest::doCallouts()
         }
     }
 
-    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);
         }
     }
 
@@ -1370,11 +1394,11 @@ ClientHttpRequest::startAdaptation(const Adaptation::ServiceGroupPointer &g)
     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
     // initiation failure, but it should not really happen
-    assert(virginHeadSource != NULL); // Must, really
+    Must(initiated(virginHeadSource));
 }
 
 void
@@ -1433,7 +1457,7 @@ ClientHttpRequest::noteAdaptationQueryAbort(bool final)
 {
     clearAdaptation(virginHeadSource);
     assert(!adaptedBodySource);
-    handleAdaptationFailure(!final);
+    handleAdaptationFailure(ERR_DETAIL_ICAP_REQMOD_ABORT, !final);
 }
 
 void
@@ -1486,11 +1510,11 @@ ClientHttpRequest::noteBodyProducerAborted(BodyPipe::Pointer)
 {
     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 << ")");
 
@@ -1519,10 +1543,12 @@ ClientHttpRequest::handleAdaptationFailure(bool bypassable)
     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->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);
 }