]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/http.cc
Bug #2818: Random unix_group crash at startup due to uninitialized pointer reference
[thirdparty/squid.git] / src / http.cc
index dca3be0c1326a0274e7ff88c4dacebfa321de90c..22d9014116bd6e238a9e4e0f370ae04f48169c48 100644 (file)
@@ -56,6 +56,7 @@
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "protos.h"
+#include "rfc1738.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "TextException.h"
@@ -542,7 +543,7 @@ HttpStateData::cacheableReply()
         return 0;
 
     default:                   /* Unknown status code */
-        debugs (11, 0, HERE << "HttpStateData::cacheableReply: unexpected http status code " << rep->sline.status);
+        debugs (11, DBG_IMPORTANT, "WARNING: Unexpected http status code " << rep->sline.status);
 
         return 0;
 
@@ -681,12 +682,10 @@ HttpStateData::processReplyHeader()
     HttpReply *newrep = new HttpReply;
     const bool parsed = newrep->parse(readBuf, eof, &error);
 
-    if (!parsed && readBuf->contentSize() > 5 && strncmp(readBuf->content(), "HTTP/", 5) != 0) {
+    if (!parsed && readBuf->contentSize() > 5 && strncmp(readBuf->content(), "HTTP/", 5) != 0 && strncmp(readBuf->content(), "ICY", 3) != 0) {
         MemBuf *mb;
         HttpReply *tmprep = new HttpReply;
-        tmprep->sline.version = HttpVersion(1, 0);
-        tmprep->sline.status = HTTP_OK;
-        tmprep->header.putTime(HDR_DATE, squid_curtime);
+        tmprep->setHeaders(HTTP_OK, "Gatewaying", NULL, -1, -1, -1);
         tmprep->header.putExt("X-Transformed-From", "HTTP/0.9");
         mb = tmprep->pack();
         newrep->parse(mb, eof, &error);
@@ -695,7 +694,7 @@ HttpStateData::processReplyHeader()
         if (!parsed && error > 0) { // unrecoverable parsing error
             debugs(11, 3, "processReplyHeader: Non-HTTP-compliant header: '" <<  readBuf->content() << "'");
             flags.headers_parsed = 1;
-            newrep->sline.version = HttpVersion(1, 0);
+            newrep->sline.version = HttpVersion(1,0);
             newrep->sline.status = error;
             HttpReply *vrep = setVirginReply(newrep);
             entry->replaceHttpReply(vrep);
@@ -718,7 +717,7 @@ HttpStateData::processReplyHeader()
     }
 
     flags.chunked = 0;
-    if (newrep->header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) {
+    if (newrep->sline.protocol == PROTO_HTTP && newrep->header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) {
         flags.chunked = 1;
         httpChunkDecoder = new ChunkedCodingParser;
     }
@@ -837,8 +836,9 @@ HttpStateData::haveParsedReplyHeaders()
 
         if (!vary) {
             entry->makePrivate();
+            if (!fwd->reforwardableStatus(rep->sline.status))
+                EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
             goto no_cache;
-
         }
 
         entry->mem_obj->vary_headers = xstrdup(vary);
@@ -1152,6 +1152,7 @@ HttpStateData::continueAfterParsingHeader()
             const http_status s = vrep->sline.status;
             const HttpVersion &v = vrep->sline.version;
             if (s == HTTP_INVALID_HEADER && v != HttpVersion(0,9)) {
+                debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Bad header encountered from " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
                 error = ERR_INVALID_RESP;
             } else if (s == HTTP_HEADER_TOO_LARGE) {
                 fwd->dontRetry(true);
@@ -1161,12 +1162,18 @@ HttpStateData::continueAfterParsingHeader()
             }
         } else {
             // parsed headers but got no reply
+            debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: No reply at all for " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
             error = ERR_INVALID_RESP;
         }
     } else {
         assert(eof);
-        error = readBuf->hasContent() ?
-                ERR_INVALID_RESP : ERR_ZERO_SIZE_OBJECT;
+        if (readBuf->hasContent()) {
+            error = ERR_INVALID_RESP;
+            debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Headers did not parse at all for " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
+        } else {
+            error = ERR_ZERO_SIZE_OBJECT;
+            debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: No object data received for " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
+        }
     }
 
     assert(error != ERR_NONE);
@@ -1223,22 +1230,22 @@ HttpStateData::decodeAndWriteReplyBody()
 {
     const char *data = NULL;
     int len;
-    bool status = false;
+    bool wasThereAnException = false;
     assert(flags.chunked);
     assert(httpChunkDecoder);
     SQUID_ENTER_THROWING_CODE();
     MemBuf decodedData;
     decodedData.init();
-    const bool done = httpChunkDecoder->parse(readBuf,&decodedData);
+    const bool doneParsing = httpChunkDecoder->parse(readBuf,&decodedData);
     len = decodedData.contentSize();
     data=decodedData.content();
     addVirginReplyBody(data, len);
-    if (done) {
+    if (doneParsing) {
         lastChunk = 1;
         flags.do_next_read = 0;
     }
-    SQUID_EXIT_THROWING_CODE(status);
-    return status;
+    SQUID_EXIT_THROWING_CODE(wasThereAnException);
+    return wasThereAnException;
 }
 
 /**
@@ -1350,10 +1357,12 @@ HttpStateData::processReplyBody()
 void
 HttpStateData::maybeReadVirginBody()
 {
-    int read_sz = replyBodySpace(readBuf->spaceSize());
+    // we may need to grow the buffer if headers do not fit
+    const int minRead = flags.headers_parsed ? 0 :1024;
+    const int read_size = replyBodySpace(*readBuf, minRead);
 
     debugs(11,9, HERE << (flags.do_next_read ? "may" : "wont") <<
-           " read up to " << read_sz << " bytes from FD " << fd);
+           " read up to " << read_size << " bytes from FD " << fd);
 
     /*
      * why <2? Because delayAwareRead() won't actually read if
@@ -1363,17 +1372,13 @@ HttpStateData::maybeReadVirginBody()
      * handler until we get a notification from someone that
      * its okay to read again.
      */
-    if (read_sz < 2) {
-        if (flags.headers_parsed)
-            return;
-        else
-            read_sz = 1024;
-    }
+    if (read_size < 2)
+        return;
 
     if (flags.do_next_read) {
         flags.do_next_read = 0;
         typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
-        entry->delayAwareRead(fd, readBuf->space(read_sz), read_sz,
+        entry->delayAwareRead(fd, readBuf->space(read_size), read_size,
                               asyncCall(11, 5, "HttpStateData::readReply",
                                         Dialer(this, &HttpStateData::readReply)));
     }
@@ -1460,58 +1465,58 @@ httpFixupAuthentication(HttpRequest * request, HttpRequest * orig_request, const
 
     /* Nothing to do unless we are forwarding to a peer */
     if (!request->flags.proxying)
-       return;
+        return;
 
     /* Needs to be explicitly enabled */
     if (!orig_request->peer_login)
-       return;
+        return;
 
     /* Maybe already dealt with? */
     if (hdr_out->has(header))
-       return;
+        return;
 
     /* Nothing to do here for PASSTHRU */
     if (strcmp(orig_request->peer_login, "PASSTHRU") == 0)
-       return;
+        return;
 
     /* PROXYPASS is a special case, single-signon to servers with the proxy password (basic only) */
     if (flags.originpeer && strcmp(orig_request->peer_login, "PROXYPASS") == 0 && hdr_in->has(HDR_PROXY_AUTHORIZATION)) {
-       const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION);
+        const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION);
 
-       if (auth && strncasecmp(auth, "basic ", 6) == 0) {
-           hdr_out->putStr(header, auth);
-           return;
-       }
+        if (auth && strncasecmp(auth, "basic ", 6) == 0) {
+            hdr_out->putStr(header, auth);
+            return;
+        }
     }
 
     /* Special mode to pass the username to the upstream cache */
     if (*orig_request->peer_login == '*') {
-       char loginbuf[256];
-       const char *username = "-";
+        char loginbuf[256];
+        const char *username = "-";
 
-       if (orig_request->extacl_user.size())
-           username = orig_request->extacl_user.termedBuf();
-       else if (orig_request->auth_user_request)
-           username = orig_request->auth_user_request->username();
+        if (orig_request->extacl_user.size())
+            username = orig_request->extacl_user.termedBuf();
+        else if (orig_request->auth_user_request)
+            username = orig_request->auth_user_request->username();
 
-       snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
+        snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
 
-       httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                         base64_encode(loginbuf));
-       return;
+        httpHeaderPutStrf(hdr_out, header, "Basic %s",
+                          base64_encode(loginbuf));
+        return;
     }
 
     /* external_acl provided credentials */
     if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size() &&
-           (strcmp(orig_request->peer_login, "PASS") == 0 ||
-            strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
-       char loginbuf[256];
-       snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
-                SQUIDSTRINGPRINT(orig_request->extacl_user),
-                SQUIDSTRINGPRINT(orig_request->extacl_passwd));
-       httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                         base64_encode(loginbuf));
-       return;
+            (strcmp(orig_request->peer_login, "PASS") == 0 ||
+             strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
+        char loginbuf[256];
+        snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
+                 SQUIDSTRINGPRINT(orig_request->extacl_user),
+                 SQUIDSTRINGPRINT(orig_request->extacl_passwd));
+        httpHeaderPutStrf(hdr_out, header, "Basic %s",
+                          base64_encode(loginbuf));
+        return;
     }
 
     /* Kerberos login to peer */
@@ -1531,7 +1536,7 @@ httpFixupAuthentication(HttpRequest * request, HttpRequest * orig_request, const
 #endif /* HAVE_KRB5 && HAVE_GSSAPI */
 
     httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                     base64_encode(orig_request->peer_login));
+                      base64_encode(orig_request->peer_login));
     return;
 }
 
@@ -1592,7 +1597,7 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
     }
 
 #if USE_SQUID_ESI
-    {
+    if (orig_request->flags.accelerated) {
         /* Append Surrogate-Capabilities */
         String strSurrogate (hdr_in->getList(HDR_SURROGATE_CAPABILITY));
         snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0 ESI/1.0\"",
@@ -1741,9 +1746,9 @@ copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, co
          * authentication forwarding is explicitly enabled
          */
         if (!flags.originpeer && flags.proxying && orig_request->peer_login &&
-               (strcmp(orig_request->peer_login, "PASS") == 0 ||
-                strcmp(orig_request->peer_login, "PROXYPASS") == 0 ||
-                strcmp(orig_request->peer_login, "PASSTHRU") == 0)) {
+                (strcmp(orig_request->peer_login, "PASS") == 0 ||
+                 strcmp(orig_request->peer_login, "PROXYPASS") == 0 ||
+                 strcmp(orig_request->peer_login, "PASSTHRU") == 0)) {
             hdr_out->addEntry(e->clone());
         }
         break;
@@ -1912,28 +1917,28 @@ HttpStateData::decideIfWeDoRanges (HttpRequest * orig_request)
 /* build request prefix and append it to a given MemBuf;
  * return the length of the prefix */
 mb_size_t
-HttpStateData::buildRequestPrefix(HttpRequest * request,
-                                  HttpRequest * orig_request,
-                                  StoreEntry * entry,
+HttpStateData::buildRequestPrefix(HttpRequest * aRequest,
+                                  HttpRequest * original_request,
+                                  StoreEntry * sentry,
                                   MemBuf * mb,
-                                  http_state_flags flags)
+                                  http_state_flags stateFlags)
 {
     const int offset = mb->size;
-    HttpVersion httpver(1, 0);
+    HttpVersion httpver(1,0);
     mb->Printf("%s %s HTTP/%d.%d\r\n",
-               RequestMethodStr(request->method),
-               request->urlpath.size() ? request->urlpath.termedBuf() : "/",
+               RequestMethodStr(aRequest->method),
+               aRequest->urlpath.size() ? aRequest->urlpath.termedBuf() : "/",
                httpver.major,httpver.minor);
     /* build and pack headers */
     {
         HttpHeader hdr(hoRequest);
         Packer p;
-        httpBuildRequestHeader(request, orig_request, entry, &hdr, flags);
+        httpBuildRequestHeader(aRequest, original_request, sentry, &hdr, stateFlags);
 
-        if (request->flags.pinned && request->flags.connection_auth)
-            request->flags.auth_sent = 1;
+        if (aRequest->flags.pinned && aRequest->flags.connection_auth)
+            aRequest->flags.auth_sent = 1;
         else if (hdr.has(HDR_AUTHORIZATION))
-            request->flags.auth_sent = 1;
+            aRequest->flags.auth_sent = 1;
 
         packerToMemInit(&p, mb);
         hdr.packInto(&p);