]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/http.cc
Merge from trunk rev.13866
[thirdparty/squid.git] / src / http.cc
index bdbb271416c82d1651c5a9c60f831c839278bdbf..15debce102b87d5c6c9d4f4eaddecc09b482486f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -57,6 +57,7 @@
 #include "StrList.h"
 #include "tools.h"
 #include "URL.h"
+#include "util.h"
 
 #if USE_AUTH
 #include "auth/UserRequest.h"
 
 #define SQUID_ENTER_THROWING_CODE() try {
 #define SQUID_EXIT_THROWING_CODE(status) \
-       status = true; \
+    status = true; \
     } \
     catch (const std::exception &e) { \
-       debugs (11, 1, "Exception error:" << e.what()); \
-       status = false; \
+    debugs (11, 1, "Exception error:" << e.what()); \
+    status = false; \
     }
 
 CBDATA_CLASS_INIT(HttpStateData);
@@ -155,9 +156,9 @@ HttpStateData::httpStateConnClosed(const CommCloseCbParams &params)
 }
 
 void
-HttpStateData::httpTimeout(const CommTimeoutCbParams &params)
+HttpStateData::httpTimeout(const CommTimeoutCbParams &)
 {
-    debugs(11, 4, HERE << serverConnection << ": '" << entry->url() << "'" );
+    debugs(11, 4, serverConnection << ": '" << entry->url() << "'");
 
     if (entry->store_status == STORE_PENDING) {
         fwd->fail(new ErrorState(ERR_READ_TIMEOUT, Http::scGatewayTimeout, fwd->request));
@@ -445,7 +446,7 @@ HttpStateData::cacheableReply()
         }
 
     switch (rep->sline.status()) {
-        /* Responses that are cacheable */
+    /* Responses that are cacheable */
 
     case Http::scOkay:
 
@@ -472,7 +473,7 @@ HttpStateData::cacheableReply()
         /* NOTREACHED */
         break;
 
-        /* Responses that only are cacheable if the server says so */
+    /* Responses that only are cacheable if the server says so */
 
     case Http::scFound:
     case Http::scTemporaryRedirect:
@@ -490,7 +491,7 @@ HttpStateData::cacheableReply()
         /* NOTREACHED */
         break;
 
-        /* Errors can be negatively cached */
+    /* Errors can be negatively cached */
 
     case Http::scNoContent:
 
@@ -515,15 +516,17 @@ HttpStateData::cacheableReply()
     case Http::scServiceUnavailable:
 
     case Http::scGatewayTimeout:
+    case Http::scMisdirectedRequest:
+
         debugs(22, 3, "MAYBE because HTTP status " << rep->sline.status());
         return -1;
 
         /* NOTREACHED */
         break;
 
-        /* Some responses can never be cached */
+    /* Some responses can never be cached */
 
-    case Http::scPartialContent:       /* Not yet supported */
+    case Http::scPartialContent:    /* Not yet supported */
 
     case Http::scSeeOther:
 
@@ -533,7 +536,7 @@ HttpStateData::cacheableReply()
 
     case Http::scProxyAuthenticationRequired:
 
-    case Http::scInvalidHeader:        /* Squid header parsing error */
+    case Http::scInvalidHeader: /* Squid header parsing error */
 
     case Http::scHeaderTooLarge:
 
@@ -732,7 +735,7 @@ HttpStateData::processReplyHeader()
             // unrecoverable parsing error
             debugs(11, 3, "Non-HTTP-compliant header:\n---------\n" << inBuf << "\n----------");
             HttpReply *newrep = new HttpReply;
-            newrep->sline.set(Http::ProtocolVersion(1,1), hp->messageStatus());
+            newrep->sline.set(Http::ProtocolVersion(), hp->messageStatus());
             HttpReply *vrep = setVirginReply(newrep);
             entry->replaceHttpReply(vrep);
             // XXX: close the server connection ?
@@ -1211,8 +1214,10 @@ HttpStateData::readReply(const CommIoCbParams &io)
 
         // update peer response time stats (%<pt)
         const timeval &sent = request->hier.peer_http_request_sent;
-        request->hier.peer_response_time =
-            sent.tv_sec ? tvSubMsec(sent, current_time) : -1;
+        if (sent.tv_sec)
+            tvSub(request->hier.peer_response_time, sent, current_time);
+        else
+            request->hier.peer_response_time.tv_sec = -1;
     }
 
         /* Continue to process previously read data */
@@ -1305,7 +1310,7 @@ HttpStateData::continueAfterParsingHeader()
         // check for header parsing errors
         if (HttpReply *vrep = virginReply()) {
             const Http::StatusCode s = vrep->sline.status();
-            const Http::ProtocolVersion &v = vrep->sline.version;
+            const AnyP::ProtocolVersion &v = vrep->sline.version;
             if (s == Http::scInvalidHeader && v != Http::ProtocolVersion(0,9)) {
                 debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Bad header encountered from " << entry->url() << " AKA " << request->GetHost() << request->urlpath.termedBuf() );
                 error = ERR_INVALID_RESP;
@@ -1675,9 +1680,13 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
         }
     }
 
+    uint8_t loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
+    size_t blen;
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+
     /* Special mode to pass the username to the upstream cache */
     if (*request->peer_login == '*') {
-        char loginbuf[256];
         const char *username = "-";
 
         if (request->extacl_user.size())
@@ -1687,10 +1696,10 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
             username = request->auth_user_request->username();
 #endif
 
-        snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, request->peer_login + 1);
-
-        httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                          old_base64_encode(loginbuf));
+        blen = base64_encode_update(&ctx, loginbuf, strlen(username), reinterpret_cast<const uint8_t*>(username));
+        blen += base64_encode_update(&ctx, loginbuf+blen, strlen(request->peer_login +1), reinterpret_cast<const uint8_t*>(request->peer_login +1));
+        blen += base64_encode_final(&ctx, loginbuf+blen);
+        httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
         return;
     }
 
@@ -1698,12 +1707,12 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
     if (request->extacl_user.size() && request->extacl_passwd.size() &&
             (strcmp(request->peer_login, "PASS") == 0 ||
              strcmp(request->peer_login, "PROXYPASS") == 0)) {
-        char loginbuf[256];
-        snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
-                 SQUIDSTRINGPRINT(request->extacl_user),
-                 SQUIDSTRINGPRINT(request->extacl_passwd));
-        httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                          old_base64_encode(loginbuf));
+
+        blen = base64_encode_update(&ctx, loginbuf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
+        blen += base64_encode_update(&ctx, loginbuf+blen, 1, reinterpret_cast<const uint8_t*>(":"));
+        blen += base64_encode_update(&ctx, loginbuf+blen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
+        blen += base64_encode_final(&ctx, loginbuf+blen);
+        httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
         return;
     }
     // if no external user credentials are available to fake authentication with PASS acts like PASSTHRU
@@ -1726,8 +1735,9 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
     }
 #endif /* HAVE_KRB5 && HAVE_GSSAPI */
 
-    httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                      old_base64_encode(request->peer_login));
+    blen = base64_encode_update(&ctx, loginbuf, strlen(request->peer_login), reinterpret_cast<const uint8_t*>(request->peer_login));
+    blen += base64_encode_final(&ctx, loginbuf+blen);
+    httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
     return;
 }
 
@@ -1863,9 +1873,14 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
     /* append Authorization if known in URL, not in header and going direct */
     if (!hdr_out->has(HDR_AUTHORIZATION)) {
         if (!request->flags.proxying && !request->url.userInfo().isEmpty()) {
-            static char result[MAX_URL*2]; // should be big enough for a single URI segment
-            if (base64_encode_str(result, sizeof(result)-1, request->url.userInfo().rawContent(), request->url.userInfo().length()) < static_cast<int>(sizeof(result)-1))
-                httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", result);
+            static uint8_t result[base64_encode_len(MAX_URL*2)]; // should be big enough for a single URI segment
+            struct base64_encode_ctx ctx;
+            base64_encode_init(&ctx);
+            size_t blen = base64_encode_update(&ctx, result, request->url.userInfo().length(), reinterpret_cast<const uint8_t*>(request->url.userInfo().rawContent()));
+            blen += base64_encode_final(&ctx, result+blen);
+            result[blen] = '\0';
+            if (blen)
+                httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %.*s", (int)blen, result);
         }
     }
 
@@ -1940,7 +1955,7 @@ copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, co
 
     switch (e->id) {
 
-        /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid should not pass on. */
+    /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid should not pass on. */
 
     case HDR_PROXY_AUTHORIZATION:
         /** \par Proxy-Authorization:
@@ -1955,7 +1970,7 @@ copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, co
         }
         break;
 
-        /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid does not pass on. */
+    /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid does not pass on. */
 
     case HDR_CONNECTION:          /** \par Connection: */
     case HDR_TE:                  /** \par TE: */
@@ -1966,7 +1981,7 @@ copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, co
     case HDR_TRANSFER_ENCODING:   /** \par Transfer-Encoding: */
         break;
 
-        /** \par OTHER headers I haven't bothered to track down yet. */
+    /** \par OTHER headers I haven't bothered to track down yet. */
 
     case HDR_AUTHORIZATION:
         /** \par WWW-Authorization:
@@ -2149,13 +2164,13 @@ mb_size_t
 HttpStateData::buildRequestPrefix(MemBuf * mb)
 {
     const int offset = mb->size;
-    /* Uses a local httpver variable to print the HTTP/1.1 label
+    /* Uses a local httpver variable to print the HTTP label
      * since the HttpRequest may have an older version label.
      * XXX: This could create protocol bugs as the headers sent and
      * flow control should all be based on the HttpRequest version
      * not the one we are sending. Needs checking.
      */
-    Http::ProtocolVersion httpver(1,1);
+    const AnyP::ProtocolVersion httpver = Http::ProtocolVersion();
     const char * url;
     if (_peer && !_peer->options.originserver)
         url = urlCanonical(request);
@@ -2479,3 +2494,4 @@ HttpStateData::abortTransaction(const char *reason)
     fwd->handleUnregisteredServerEnd();
     mustStop("HttpStateData::abortTransaction");
 }
+