]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/HttpMsg.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / HttpMsg.cc
index 3123321a511687dd1353f9e9ddcce5f09ca80873..f6f2f8d8196db216dcbfaa0404133cc5c6b45b8a 100644 (file)
@@ -1,38 +1,17 @@
-
 /*
- * DEBUG: section 74    HTTP Message
- * AUTHOR: Alex Rousskov
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 74    HTTP Message */
+
 #include "squid.h"
 #include "Debug.h"
+#include "http/one/Parser.h"
+#include "HttpHdrCc.h"
 #include "HttpHeaderTools.h"
 #include "HttpMsg.h"
 #include "MemBuf.h"
 #include "profiler/Profiler.h"
 #include "SquidConfig.h"
 
-HttpMsg::HttpMsg(http_hdr_owner_type owner): header(owner),
-        cache_control(NULL), hdr_sz(0), content_length(0),
-        pstate(psReadyToParseStartLine)
+HttpMsg::HttpMsg(http_hdr_owner_type owner):
+    http_ver(Http::ProtocolVersion()),
+    header(owner),
+    cache_control(NULL),
+    hdr_sz(0),
+    content_length(0),
+    pstate(psReadyToParseStartLine),
+    sources(0)
 {}
 
 HttpMsg::~HttpMsg()
@@ -50,70 +34,30 @@ HttpMsg::~HttpMsg()
     assert(!body_pipe);
 }
 
-HttpMsgParseState &operator++ (HttpMsgParseState &aState)
-{
-    int tmp = (int)aState;
-    aState = (HttpMsgParseState)(++tmp);
-    return aState;
-}
-
-/* find end of headers */
-static int
-httpMsgIsolateHeaders(const char **parse_start, int l, const char **blk_start, const char **blk_end)
+void
+HttpMsg::putCc(const HttpHdrCc *otherCc)
 {
-    /*
-     * parse_start points to the first line of HTTP message *headers*,
-     * not including the request or status lines
-     */
-    size_t end = headersEnd(*parse_start, l);
-    int nnl;
-
-    if (end) {
-        *blk_start = *parse_start;
-        *blk_end = *parse_start + end - 1;
-        /*
-         * leave blk_end pointing to the first character after the
-         * first newline which terminates the headers
-         */
-        assert(**blk_end == '\n');
-
-        while (*(*blk_end - 1) == '\r')
-            --(*blk_end);
-
-        assert(*(*blk_end - 1) == '\n');
-
-        *parse_start += end;
-
-        return 1;
+    // get rid of the old CC, if any
+    if (cache_control) {
+        delete cache_control;
+        cache_control = nullptr;
+        if (!otherCc)
+            header.delById(Http::HdrType::CACHE_CONTROL);
+        // else it will be deleted inside putCc() below
     }
 
-    /*
-     * If we didn't find the end of headers, and parse_start does
-     * NOT point to a CR or NL character, then return failure
-     */
-    if (**parse_start != '\r' && **parse_start != '\n')
-        return 0;              /* failure */
-
-    /*
-     * If we didn't find the end of headers, and parse_start does point
-     * to an empty line, then we have empty headers.  Skip all CR and
-     * NL characters up to the first NL.  Leave parse_start pointing at
-     * the first character after the first NL.
-     */
-    *blk_start = *parse_start;
-
-    *blk_end = *blk_start;
-
-    for (nnl = 0; nnl == 0; ++(*parse_start)) {
-        if (**parse_start == '\r')
-            (void) 0;
-        else if (**parse_start == '\n')
-            ++nnl;
-        else
-            break;
+    // add new CC, if any
+    if (otherCc) {
+        cache_control = new HttpHdrCc(*otherCc);
+        header.putCc(cache_control);
     }
+}
 
-    return 1;
+HttpMsgParseState &operator++ (HttpMsgParseState &aState)
+{
+    int tmp = (int)aState;
+    aState = (HttpMsgParseState)(++tmp);
+    return aState;
 }
 
 /* find first CRLF */
@@ -144,16 +88,13 @@ httpMsgIsolateStart(const char **parse_start, const char **blk_start, const char
 // zero return means need more data
 // positive return is the size of parsed headers
 bool
-HttpMsg::parse(MemBuf *buf, bool eof, Http::StatusCode *error)
+HttpMsg::parse(const char *buf, const size_t sz, bool eof, Http::StatusCode *error)
 {
     assert(error);
     *error = Http::scNone;
 
-    // httpMsgParseStep() and debugging require 0-termination, unfortunately
-    buf->terminate(); // does not affect content size
-
     // find the end of headers
-    const size_t hdr_len = headersEnd(buf->content(), buf->contentSize());
+    const size_t hdr_len = headersEnd(buf, sz);
 
     // sanity check the start line to see if this is in fact an HTTP message
     if (!sanityCheckStartLine(buf, hdr_len, error)) {
@@ -165,15 +106,14 @@ HttpMsg::parse(MemBuf *buf, bool eof, Http::StatusCode *error)
         return false;
     }
 
-    // TODO: move to httpReplyParseStep()
-    if (hdr_len > Config.maxReplyHeaderSize || (hdr_len <= 0 && (size_t)buf->contentSize() > Config.maxReplyHeaderSize)) {
+    if (hdr_len > Config.maxReplyHeaderSize || (hdr_len <= 0 && sz > Config.maxReplyHeaderSize)) {
         debugs(58, DBG_IMPORTANT, "HttpMsg::parse: Too large reply header (" << hdr_len << " > " << Config.maxReplyHeaderSize);
         *error = Http::scHeaderTooLarge;
         return false;
     }
 
     if (hdr_len <= 0) {
-        debugs(58, 3, "HttpMsg::parse: failed to find end of headers (eof: " << eof << ") in '" << buf->content() << "'");
+        debugs(58, 3, "HttpMsg::parse: failed to find end of headers (eof: " << eof << ") in '" << buf << "'");
 
         if (eof) // iff we have seen the end, this is an error
             *error = Http::scInvalidHeader;
@@ -181,22 +121,22 @@ HttpMsg::parse(MemBuf *buf, bool eof, Http::StatusCode *error)
         return false;
     }
 
-    const int res = httpMsgParseStep(buf->content(), buf->contentSize(), eof);
+    const int res = httpMsgParseStep(buf, sz, eof);
 
     if (res < 0) { // error
-        debugs(58, 3, "HttpMsg::parse: cannot parse isolated headers in '" << buf->content() << "'");
+        debugs(58, 3, "HttpMsg::parse: cannot parse isolated headers in '" << buf << "'");
         *error = Http::scInvalidHeader;
         return false;
     }
 
     if (res == 0) {
-        debugs(58, 2, "HttpMsg::parse: strange, need more data near '" << buf->content() << "'");
+        debugs(58, 2, "HttpMsg::parse: strange, need more data near '" << buf << "'");
         *error = Http::scInvalidHeader;
         return false; // but this should not happen due to headersEnd() above
     }
 
     assert(res > 0);
-    debugs(58, 9, "HttpMsg::parse success (" << hdr_len << " bytes) near '" << buf->content() << "'");
+    debugs(58, 9, "HttpMsg::parse success (" << hdr_len << " bytes) near '" << buf << "'");
 
     if (hdr_sz != (int)hdr_len) {
         debugs(58, DBG_IMPORTANT, "internal HttpMsg::parse vs. headersEnd error: " <<
@@ -276,27 +216,14 @@ HttpMsg::httpMsgParseStep(const char *buf, int len, int atEnd)
      * after headers.) Grr.
      */
     if (pstate == psReadyToParseHeaders) {
-        if (!httpMsgIsolateHeaders(&parse_start, parse_len, &blk_start, &blk_end)) {
-            if (atEnd) {
-                blk_start = parse_start;
-                blk_end = blk_start + strlen(blk_start);
-            } else {
-                PROF_stop(HttpMsg_httpMsgParseStep);
-                return 0;
-            }
-        }
-
-        if (!header.parse(blk_start, blk_end-blk_start)) {
+        size_t hsize = 0;
+        const int parsed = header.parse(parse_start, parse_len, atEnd, hsize);
+        if (parsed <= 0) {
             PROF_stop(HttpMsg_httpMsgParseStep);
-            return httpMsgParseError();
+            return !parsed ? 0 : httpMsgParseError();
         }
-
+        hdr_sz += hsize;
         hdrCacheInit();
-
-        *parse_end_ptr = parse_start;
-
-        hdr_sz = *parse_end_ptr - buf;
-
         ++pstate;
     }
 
@@ -304,6 +231,24 @@ HttpMsg::httpMsgParseStep(const char *buf, int len, int atEnd)
     return 1;
 }
 
+bool
+HttpMsg::parseHeader(Http1::Parser &hp)
+{
+    // HTTP/1 message contains "zero or more header fields"
+    // zero does not need parsing
+    // XXX: c_str() reallocates. performance regression.
+    if (hp.headerBlockSize() && !header.parse(hp.mimeHeader().c_str(), hp.headerBlockSize())) {
+        pstate = psError;
+        return false;
+    }
+
+    // XXX: we are just parsing HTTP headers, not the whole message prefix here
+    hdr_sz = hp.messageHeaderSize();
+    pstate = psParsed;
+    hdrCacheInit();
+    return true;
+}
+
 /* handy: resets and returns -1 */
 int
 HttpMsg::httpMsgParseError()
@@ -315,15 +260,15 @@ HttpMsg::httpMsgParseError()
 void
 HttpMsg::setContentLength(int64_t clen)
 {
-    header.delById(HDR_CONTENT_LENGTH); // if any
-    header.putInt64(HDR_CONTENT_LENGTH, clen);
+    header.delById(Http::HdrType::CONTENT_LENGTH); // if any
+    header.putInt64(Http::HdrType::CONTENT_LENGTH, clen);
     content_length = clen;
 }
 
 bool
 HttpMsg::persistent() const
 {
-    if (http_ver > Http::ProtocolVersion(1, 0)) {
+    if (http_ver > Http::ProtocolVersion(1,0)) {
         /*
          * for modern versions of HTTP: persistent unless there is
          * a "Connection: close" header.
@@ -335,16 +280,16 @@ HttpMsg::persistent() const
     }
 }
 
-void HttpMsg::packInto(Packer *p, bool full_uri) const
+void HttpMsg::packInto(Packable *p, bool full_uri) const
 {
     packFirstLineInto(p, full_uri);
     header.packInto(p);
-    packerAppend(p, "\r\n", 2);
+    p->append("\r\n", 2);
 }
 
 void HttpMsg::hdrCacheInit()
 {
-    content_length = header.getInt64(HDR_CONTENT_LENGTH);
+    content_length = header.getInt64(Http::HdrType::CONTENT_LENGTH);
     assert(NULL == cache_control);
     cache_control = header.getCc();
 }
@@ -354,8 +299,6 @@ void HttpMsg::hdrCacheInit()
  */
 void HttpMsg::firstLineBuf(MemBuf& mb)
 {
-    Packer p;
-    packerToMemInit(&p, &mb);
-    packFirstLineInto(&p, true);
-    packerClean(&p);
+    packFirstLineInto(&mb, true);
 }
+