]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/http.cc
Supply AccessLogEntry (ALE) for more fast ACL checks. (#182)
[thirdparty/squid.git] / src / http.cc
index 1b0605fbc696914fee4b3e7c14cee936cf6830fd..1ccd70ffe554c9eb8e26c33c96253539efab7bd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -97,10 +97,6 @@ HttpStateData::HttpStateData(FwdState *theFwdState) :
     surrogateNoStore = false;
     serverConnection = fwd->serverConnection();
 
-    // reset peer response time stats for %<pt
-    request->hier.peer_http_request_sent.tv_sec = 0;
-    request->hier.peer_http_request_sent.tv_usec = 0;
-
     if (fwd->serverConnection() != NULL)
         _peer = cbdataReference(fwd->serverConnection()->getPeer());         /* might be NULL */
 
@@ -112,7 +108,7 @@ HttpStateData::HttpStateData(FwdState *theFwdState) :
          * for example, the request to this neighbor fails.
          */
         if (_peer->options.proxy_only)
-            entry->releaseRequest();
+            entry->releaseRequest(true);
 
 #if USE_DELAY_POOLS
         entry->setNoDelay(_peer->options.no_delay);
@@ -256,7 +252,7 @@ httpMaybeRemovePublic(StoreEntry * e, Http::StatusCode status)
 #if USE_HTCP
         neighborsHtcpClear(e, nullptr, e->mem_obj->request.getRaw(), e->mem_obj->method, HTCP_CLR_INVALIDATION);
 #endif
-        pe->release();
+        pe->release(true);
     }
 
     /** \par
@@ -273,7 +269,7 @@ httpMaybeRemovePublic(StoreEntry * e, Http::StatusCode status)
 #if USE_HTCP
         neighborsHtcpClear(e, nullptr, e->mem_obj->request.getRaw(), HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_INVALIDATION);
 #endif
-        pe->release();
+        pe->release(true);
     }
 }
 
@@ -338,7 +334,7 @@ HttpStateData::reusableReply(HttpStateData::ReuseDecision &decision)
 #endif
 
     if (EBIT_TEST(entry->flags, RELEASE_REQUEST))
-        return decision.make(ReuseDecision::reuseNot, "the entry has been released");
+        return decision.make(ReuseDecision::doNotCacheButShare, "the entry has been released");
 
     // RFC 7234 section 4: a cache MUST use the most recent response
     // (as determined by the Date header field)
@@ -805,9 +801,11 @@ HttpStateData::handle1xx(HttpReply *reply)
     // check whether the 1xx response forwarding is allowed by squid.conf
     if (Config.accessList.reply) {
         ACLFilledChecklist ch(Config.accessList.reply, originalRequest().getRaw());
+        ch.al = fwd->al;
         ch.reply = reply;
+        ch.syncAle(originalRequest().getRaw(), nullptr);
         HTTPMSGLOCK(ch.reply);
-        if (ch.fastCheck() != ACCESS_ALLOWED) { // TODO: support slow lookups?
+        if (!ch.fastCheck().allowed()) { // TODO: support slow lookups?
             debugs(11, 3, HERE << "ignoring denied 1xx");
             proceedAfter1xx();
             return;
@@ -909,8 +907,11 @@ HttpStateData::haveParsedReplyHeaders()
     /* Check if object is cacheable or not based on reply code */
     debugs(11, 3, "HTTP CODE: " << statusCode);
 
-    if (const StoreEntry *oldEntry = findPreviouslyCachedEntry(entry))
+    if (StoreEntry *oldEntry = findPreviouslyCachedEntry(entry)) {
+        oldEntry->lock("HttpStateData::haveParsedReplyHeaders");
         sawDateGoBack = rep->olderThan(oldEntry->getReply());
+        oldEntry->unlock("HttpStateData::haveParsedReplyHeaders");
+    }
 
     if (neighbors_do_private_keys && !sawDateGoBack)
         httpMaybeRemovePublic(entry, rep->sline.status());
@@ -958,11 +959,17 @@ HttpStateData::haveParsedReplyHeaders()
             break;
 
         case ReuseDecision::cachePositively:
-            entry->makePublic();
+            if (!entry->makePublic()) {
+                decision.make(ReuseDecision::doNotCacheButShare, "public key creation error");
+                entry->makePrivate(true);
+            }
             break;
 
         case ReuseDecision::cacheNegatively:
-            entry->cacheNegatively();
+            if (!entry->cacheNegatively()) {
+                decision.make(ReuseDecision::doNotCacheButShare, "public key creation error");
+                entry->makePrivate(true);
+            }
             break;
 
         case ReuseDecision::doNotCacheButShare:
@@ -1189,12 +1196,7 @@ HttpStateData::readReply(const CommIoCbParams &io)
 
         ++ IOStats.Http.read_hist[bin];
 
-        // update peer response time stats (%<pt)
-        const timeval &sent = request->hier.peer_http_request_sent;
-        if (sent.tv_sec)
-            tvSub(request->hier.peer_response_time, sent, current_time);
-        else
-            request->hier.peer_response_time.tv_sec = -1;
+        request->hier.notePeerRead();
     }
 
         /* Continue to process previously read data */
@@ -1395,9 +1397,6 @@ HttpStateData::decodeAndWriteReplyBody()
 void
 HttpStateData::processReplyBody()
 {
-    Ip::Address client_addr;
-    bool ispinned = false;
-
     if (!flags.headers_parsed) {
         flags.do_next_read = true;
         maybeReadVirginBody();
@@ -1450,35 +1449,49 @@ HttpStateData::processReplyBody()
         }
         break;
 
-        case COMPLETE_PERSISTENT_MSG:
+        case COMPLETE_PERSISTENT_MSG: {
             debugs(11, 5, "processReplyBody: COMPLETE_PERSISTENT_MSG from " << serverConnection);
-            /* yes we have to clear all these! */
+
+            // TODO: Remove serverConnectionSaved but preserve exception safety.
+
             commUnsetConnTimeout(serverConnection);
             flags.do_next_read = false;
 
             comm_remove_close_handler(serverConnection->fd, closeHandler);
             closeHandler = NULL;
-            fwd->unregister(serverConnection);
 
+            Ip::Address client_addr; // XXX: Remove as unused. Why was it added?
             if (request->flags.spoofClientIp)
                 client_addr = request->client_addr;
 
+            auto serverConnectionSaved = serverConnection;
+            fwd->unregister(serverConnection);
+            serverConnection = nullptr;
+
+            bool ispinned = false; // TODO: Rename to isOrShouldBePinned
             if (request->flags.pinned) {
                 ispinned = true;
             } else if (request->flags.connectionAuth && request->flags.authSent) {
                 ispinned = true;
             }
 
-            if (ispinned && request->clientConnectionManager.valid()) {
-                request->clientConnectionManager->pinConnection(serverConnection, request.getRaw(), _peer,
-                        (request->flags.connectionAuth));
+            if (ispinned) {
+                if (request->clientConnectionManager.valid()) {
+                    CallJobHere1(11, 4, request->clientConnectionManager,
+                                 ConnStateData,
+                                 notePinnedConnectionBecameIdle,
+                                 ConnStateData::PinnedIdleContext(serverConnectionSaved, request));
+                } else {
+                    // must not pool/share ispinned connections, even orphaned ones
+                    serverConnectionSaved->close();
+                }
             } else {
-                fwd->pconnPush(serverConnection, request->url.host());
+                fwd->pconnPush(serverConnectionSaved, request->url.host());
             }
 
-            serverConnection = NULL;
             serverComplete();
             return;
+        }
 
         case COMPLETE_NONPERSISTENT_MSG:
             debugs(11, 5, "processReplyBody: COMPLETE_NONPERSISTENT_MSG from " << serverConnection);
@@ -1570,6 +1583,9 @@ HttpStateData::wroteLast(const CommIoCbParams &io)
     entry->mem_obj->checkUrlChecksum();
 #endif
 
+    // XXX: Keep in sync with Client::sentRequestBody().
+    // TODO: Extract common parts.
+
     if (io.size > 0) {
         fd_bytes(io.fd, io.size, FD_WRITE);
         statCounter.server.all.kbytes_out += io.size;
@@ -1579,6 +1595,9 @@ HttpStateData::wroteLast(const CommIoCbParams &io)
     if (io.flag == Comm::ERR_CLOSING)
         return;
 
+    // both successful and failed writes affect response times
+    request->hier.notePeerWrite();
+
     if (io.flag) {
         ErrorState *err = new ErrorState(ERR_WRITE_ERROR, Http::scBadGateway, fwd->request);
         err->xerrno = io.xerrno;
@@ -1609,7 +1628,6 @@ HttpStateData::sendComplete()
 
     commSetConnTimeout(serverConnection, Config.Timeout.read, timeoutCall);
     flags.request_sent = true;
-    request->hier.peer_http_request_sent = current_time;
 }
 
 void
@@ -1665,7 +1683,7 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
         }
     }
 
-    uint8_t loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
+    char loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
     size_t blen;
     struct base64_encode_ctx ctx;
     base64_encode_init(&ctx);
@@ -1850,7 +1868,7 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
     /* append Authorization if known in URL, not in header and going direct */
     if (!hdr_out->has(Http::HdrType::AUTHORIZATION)) {
         if (!request->flags.proxying && !request->url.userInfo().isEmpty()) {
-            static uint8_t result[base64_encode_len(MAX_URL*2)]; // should be big enough for a single URI segment
+            static char 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()));
@@ -2318,7 +2336,9 @@ HttpStateData::finishingBrokenPost()
     }
 
     ACLFilledChecklist ch(Config.accessList.brokenPosts, originalRequest().getRaw());
-    if (ch.fastCheck() != ACCESS_ALLOWED) {
+    ch.al = fwd->al;
+    ch.syncAle(originalRequest().getRaw(), nullptr);
+    if (!ch.fastCheck().allowed()) {
         debugs(11, 5, HERE << "didn't match brokenPosts");
         return false;
     }