]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/HttpReply.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / HttpReply.cc
index 3c12fcb08d7b4ba4d57e504dabd3d62ae45adf97..d3fe7bf04c945f836296ee7df0905a4b2105b80c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2015 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.
@@ -11,6 +11,7 @@
 #include "squid.h"
 #include "acl/AclSizeLimit.h"
 #include "acl/FilledChecklist.h"
+#include "base/EnumIterator.h"
 #include "globals.h"
 #include "HttpBody.h"
 #include "HttpHdrCc.h"
 #include "Store.h"
 #include "StrList.h"
 
-/* local constants */
-
-/* If we receive a 304 from the origin during a cache revalidation, we must
- * update the headers of the existing entry. Specifically, we need to update all
- * end-to-end headers and not any hop-by-hop headers (rfc2616 13.5.3).
- *
- * This is not the whole story though: since it is possible for a faulty/malicious
- * origin server to set headers it should not in a 304, we must explicitly ignore
- * these too. Specifically all entity-headers except those permitted in a 304
- * (rfc2616 10.3.5) must be ignored.
- *
- * The list of headers we don't update is made up of:
- *     all hop-by-hop headers
- *     all entity-headers except Expires and Content-Location
- */
-static HttpHeaderMask Denied304HeadersMask;
-static http_hdr_type Denied304HeadersArr[] = {
-    // hop-by-hop headers
-    HDR_CONNECTION, HDR_KEEP_ALIVE, HDR_PROXY_AUTHENTICATE, HDR_PROXY_AUTHORIZATION,
-    HDR_TE, HDR_TRAILER, HDR_TRANSFER_ENCODING, HDR_UPGRADE,
-    // entity headers
-    HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
-    HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_LAST_MODIFIED
-};
-
-/* module initialization */
-void
-httpReplyInitModule(void)
-{
-    assert(Http::scNone == 0); // HttpReply::parse() interface assumes that
-    httpHeaderMaskInit(&Denied304HeadersMask, 0);
-    httpHeaderCalcMask(&Denied304HeadersMask, Denied304HeadersArr, countof(Denied304HeadersArr));
-}
-
-HttpReply::HttpReply() : HttpMsg(hoReply), date (0), last_modified (0),
-    expires (0), surrogate_control (NULL), content_range (NULL), keep_alive (0),
-    protoPrefix("HTTP/"), bodySizeMax(-2)
+HttpReply::HttpReply():
+    Http::Message(hoReply),
+    date(0),
+    last_modified(0),
+    expires(0),
+    surrogate_control(nullptr),
+    keep_alive(0),
+    protoPrefix("HTTP/"),
+    bodySizeMax(-2),
+    content_range(nullptr)
 {
     init();
 }
@@ -76,7 +50,7 @@ HttpReply::init()
 {
     hdrCacheInit();
     sline.init();
-    pstate = psReadyToParseStartLine;
+    pstate = Http::Message::psReadyToParseStartLine;
     do_clean = true;
 }
 
@@ -108,15 +82,15 @@ HttpReply::clean()
 }
 
 void
-HttpReply::packHeadersInto(Packer * p) const
+HttpReply::packHeadersInto(Packable * p) const
 {
     sline.packInto(p);
     header.packInto(p);
-    packerAppend(p, "\r\n", 2);
+    p->append("\r\n", 2);
 }
 
 void
-HttpReply::packInto(Packer * p)
+HttpReply::packInto(Packable * p) const
 {
     packHeadersInto(p);
     body.packInto(p);
@@ -124,22 +98,18 @@ HttpReply::packInto(Packer * p)
 
 /* create memBuf, create mem-based packer, pack, destroy packer, return MemBuf */
 MemBuf *
-HttpReply::pack()
+HttpReply::pack() const
 {
     MemBuf *mb = new MemBuf;
-    Packer p;
-
     mb->init();
-    packerToMemInit(&p, mb);
-    packInto(&p);
-    packerClean(&p);
+    packInto(mb);
     return mb;
 }
 
 HttpReply *
 HttpReply::make304() const
 {
-    static const http_hdr_type ImsEntries[] = {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER};
+    static const Http::HdrType ImsEntries[] = {Http::HdrType::DATE, Http::HdrType::CONTENT_TYPE, Http::HdrType::EXPIRES, Http::HdrType::LAST_MODIFIED, /* eof */ Http::HdrType::OTHER};
 
     HttpReply *rv = new HttpReply;
     int t;
@@ -150,21 +120,23 @@ HttpReply::make304() const
     rv->last_modified = last_modified;
     rv->expires = expires;
     rv->content_type = content_type;
-    /* rv->cache_control */
     /* rv->content_range */
     /* rv->keep_alive */
     rv->sline.set(Http::ProtocolVersion(), Http::scNotModified, NULL);
 
-    for (t = 0; ImsEntries[t] != HDR_OTHER; ++t)
+    for (t = 0; ImsEntries[t] != Http::HdrType::OTHER; ++t) {
         if ((e = header.findEntry(ImsEntries[t])))
             rv->header.addEntry(e->clone());
+    }
+
+    rv->putCc(cache_control);
 
     /* rv->body */
     return rv;
 }
 
 MemBuf *
-HttpReply::packed304Reply()
+HttpReply::packed304Reply() const
 {
     /* Not as efficient as skipping the header duplication,
      * but easier to maintain
@@ -182,24 +154,24 @@ HttpReply::setHeaders(Http::StatusCode status, const char *reason,
     HttpHeader *hdr;
     sline.set(Http::ProtocolVersion(), status, reason);
     hdr = &header;
-    hdr->putStr(HDR_SERVER, visible_appname_string);
-    hdr->putStr(HDR_MIME_VERSION, "1.0");
-    hdr->putTime(HDR_DATE, squid_curtime);
+    hdr->putStr(Http::HdrType::SERVER, visible_appname_string);
+    hdr->putStr(Http::HdrType::MIME_VERSION, "1.0");
+    hdr->putTime(Http::HdrType::DATE, squid_curtime);
 
     if (ctype) {
-        hdr->putStr(HDR_CONTENT_TYPE, ctype);
+        hdr->putStr(Http::HdrType::CONTENT_TYPE, ctype);
         content_type = ctype;
     } else
         content_type = String();
 
     if (clen >= 0)
-        hdr->putInt64(HDR_CONTENT_LENGTH, clen);
+        hdr->putInt64(Http::HdrType::CONTENT_LENGTH, clen);
 
     if (expiresTime >= 0)
-        hdr->putTime(HDR_EXPIRES, expiresTime);
+        hdr->putTime(Http::HdrType::EXPIRES, expiresTime);
 
     if (lmt > 0)        /* this used to be lmt != 0 @?@ */
-        hdr->putTime(HDR_LAST_MODIFIED, lmt);
+        hdr->putTime(Http::HdrType::LAST_MODIFIED, lmt);
 
     date = squid_curtime;
 
@@ -216,10 +188,10 @@ HttpReply::redirect(Http::StatusCode status, const char *loc)
     HttpHeader *hdr;
     sline.set(Http::ProtocolVersion(), status, NULL);
     hdr = &header;
-    hdr->putStr(HDR_SERVER, APP_FULLNAME);
-    hdr->putTime(HDR_DATE, squid_curtime);
-    hdr->putInt64(HDR_CONTENT_LENGTH, 0);
-    hdr->putStr(HDR_LOCATION, loc);
+    hdr->putStr(Http::HdrType::SERVER, APP_FULLNAME);
+    hdr->putTime(Http::HdrType::DATE, squid_curtime);
+    hdr->putInt64(Http::HdrType::CONTENT_LENGTH, 0);
+    hdr->putStr(Http::HdrType::LOCATION, loc);
     date = squid_curtime;
     content_length = 0;
 }
@@ -243,9 +215,9 @@ HttpReply::validatorsMatch(HttpReply const * otherRep) const
         return 0;
 
     /* ETag */
-    one = header.getStrOrList(HDR_ETAG);
+    one = header.getStrOrList(Http::HdrType::ETAG);
 
-    two = otherRep->header.getStrOrList(HDR_ETAG);
+    two = otherRep->header.getStrOrList(Http::HdrType::ETAG);
 
     if (one.size()==0 || two.size()==0 || one.caseCmp(two)!=0 ) {
         one.clean();
@@ -257,9 +229,9 @@ HttpReply::validatorsMatch(HttpReply const * otherRep) const
         return 0;
 
     /* MD5 */
-    one = header.getStrOrList(HDR_CONTENT_MD5);
+    one = header.getStrOrList(Http::HdrType::CONTENT_MD5);
 
-    two = otherRep->header.getStrOrList(HDR_CONTENT_MD5);
+    two = otherRep->header.getStrOrList(Http::HdrType::CONTENT_MD5);
 
     if (one.size()==0 || two.size()==0 || one.caseCmp(two)!=0 ) {
         one.clean();
@@ -270,20 +242,23 @@ HttpReply::validatorsMatch(HttpReply const * otherRep) const
     return 1;
 }
 
-void
+bool
 HttpReply::updateOnNotModified(HttpReply const * freshRep)
 {
     assert(freshRep);
 
+    /* update raw headers */
+    if (!header.update(&freshRep->header))
+        return false;
+
     /* clean cache */
     hdrCacheClean();
-    /* update raw headers */
-    header.update(&freshRep->header,
-                  (const HttpHeaderMask *) &Denied304HeadersMask);
 
     header.compact();
     /* init cache */
     hdrCacheInit();
+
+    return true;
 }
 
 /* internal routines */
@@ -294,37 +269,26 @@ HttpReply::hdrExpirationTime()
     /* The s-maxage and max-age directive takes priority over Expires */
 
     if (cache_control) {
-        if (date >= 0) {
-            if (cache_control->hasSMaxAge())
-                return date + cache_control->sMaxAge();
-
-            if (cache_control->hasMaxAge())
-                return date + cache_control->maxAge();
-        } else {
-            /*
-             * Conservatively handle the case when we have a max-age
-             * header, but no Date for reference?
-             */
-
-            if (cache_control->hasSMaxAge())
-                return squid_curtime;
-
-            if (cache_control->hasMaxAge())
-                return squid_curtime;
-        }
+        int maxAge = -1;
+        /*
+         * Conservatively handle the case when we have a max-age
+         * header, but no Date for reference?
+         */
+        if (cache_control->hasSMaxAge(&maxAge) || cache_control->hasMaxAge(&maxAge))
+            return (date >= 0) ? date + maxAge : squid_curtime;
     }
 
     if (Config.onoff.vary_ignore_expire &&
-            header.has(HDR_VARY)) {
-        const time_t d = header.getTime(HDR_DATE);
-        const time_t e = header.getTime(HDR_EXPIRES);
+            header.has(Http::HdrType::VARY)) {
+        const time_t d = header.getTime(Http::HdrType::DATE);
+        const time_t e = header.getTime(Http::HdrType::EXPIRES);
 
         if (d == e)
             return -1;
     }
 
-    if (header.has(HDR_EXPIRES)) {
-        const time_t e = header.getTime(HDR_EXPIRES);
+    if (header.has(Http::HdrType::EXPIRES)) {
+        const time_t e = header.getTime(Http::HdrType::EXPIRES);
         /*
          * HTTP/1.0 says that robust implementations should consider
          * bad or malformed Expires header as equivalent to "expires
@@ -340,16 +304,17 @@ HttpReply::hdrExpirationTime()
 void
 HttpReply::hdrCacheInit()
 {
-    HttpMsg::hdrCacheInit();
+    Http::Message::hdrCacheInit();
 
     http_ver = sline.version;
-    content_length = header.getInt64(HDR_CONTENT_LENGTH);
-    date = header.getTime(HDR_DATE);
-    last_modified = header.getTime(HDR_LAST_MODIFIED);
+    content_length = header.getInt64(Http::HdrType::CONTENT_LENGTH);
+    date = header.getTime(Http::HdrType::DATE);
+    last_modified = header.getTime(Http::HdrType::LAST_MODIFIED);
     surrogate_control = header.getSc();
-    content_range = header.getContRange();
+    content_range = (sline.status() == Http::scPartialContent) ?
+                    header.getContRange() : nullptr;
     keep_alive = persistent() ? 1 : 0;
-    const char *str = header.getStr(HDR_CONTENT_TYPE);
+    const char *str = header.getStr(Http::HdrType::CONTENT_TYPE);
 
     if (str)
         content_type.limitInit(str, strcspn(str, ";\t "));
@@ -360,6 +325,13 @@ HttpReply::hdrCacheInit()
     expires = hdrExpirationTime();
 }
 
+const HttpHdrContRange *
+HttpReply::contentRange() const
+{
+    assert(!content_range || sline.status() == Http::scPartialContent);
+    return content_range;
+}
+
 /* sync this routine when you update HttpReply struct */
 void
 HttpReply::hdrCacheClean()
@@ -377,7 +349,7 @@ HttpReply::hdrCacheClean()
     }
 
     if (content_range) {
-        httpHdrContRangeDestroy(content_range);
+        delete content_range;
         content_range = NULL;
     }
 }
@@ -475,7 +447,7 @@ HttpReply::parseFirstLine(const char *blk_start, const char *blk_end)
 int
 HttpReply::httpMsgParseError()
 {
-    int result(HttpMsg::httpMsgParseError());
+    int result(Http::Message::httpMsgParseError());
     /* indicate an error in the status line */
     sline.set(Http::ProtocolVersion(), Http::scInvalidHeader);
     return result;
@@ -560,7 +532,7 @@ HttpReply::calcMaxBodySize(HttpRequest& request) const
     HTTPMSGLOCK(ch.reply);
     for (AclSizeLimit *l = Config.ReplyBodySize; l; l = l -> next) {
         /* if there is no ACL list or if the ACLs listed match use this size value */
-        if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
+        if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
             debugs(58, 4, HERE << "bodySizeMax=" << bodySizeMax);
             bodySizeMax = l->size; // may be -1
             break;
@@ -585,26 +557,28 @@ HttpReply::clone() const
     return rep;
 }
 
-bool HttpReply::inheritProperties(const HttpMsg *aMsg)
+bool
+HttpReply::inheritProperties(const Http::Message *aMsg)
 {
     const HttpReply *aRep = dynamic_cast<const HttpReply*>(aMsg);
     if (!aRep)
         return false;
     keep_alive = aRep->keep_alive;
+    sources = aRep->sources;
     return true;
 }
 
 void HttpReply::removeStaleWarnings()
 {
     String warning;
-    if (header.getList(HDR_WARNING, &warning)) {
+    if (header.getList(Http::HdrType::WARNING, &warning)) {
         const String newWarning = removeStaleWarningValues(warning);
         if (warning.size() && warning.size() == newWarning.size())
             return; // some warnings are there and none changed
-        header.delById(HDR_WARNING);
+        header.delById(Http::HdrType::WARNING);
         if (newWarning.size()) { // some warnings left
             HttpHeaderEntry *const e =
-                new HttpHeaderEntry(HDR_WARNING, NULL, newWarning.termedBuf());
+                new HttpHeaderEntry(Http::HdrType::WARNING, SBuf(), newWarning.termedBuf());
             header.addEntry(e);
         }
     }
@@ -658,3 +632,11 @@ String HttpReply::removeStaleWarningValues(const String &value)
     return newValue;
 }
 
+bool
+HttpReply::olderThan(const HttpReply *them) const
+{
+    if (!them || !them->date || !date)
+        return false;
+    return date < them->date;
+}
+