]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/HttpRequest.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / HttpRequest.cc
index edd113fbf3007c02a56428d1a5cb7168af3745b8..56d4570b5816a065bf4ff0dabcc36ef5f3b239cb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * 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.
 #include "acl/FilledChecklist.h"
 #include "client_side.h"
 #include "dns/LookupDetails.h"
+#include "Downloader.h"
 #include "err_detail_type.h"
 #include "globals.h"
 #include "gopher.h"
 #include "http.h"
 #include "http/one/RequestParser.h"
+#include "http/Stream.h"
 #include "HttpHdrCc.h"
 #include "HttpHeaderRange.h"
 #include "HttpRequest.h"
 #include "log/Config.h"
 #include "MemBuf.h"
+#include "sbuf/StringConvert.h"
 #include "SquidConfig.h"
 #include "Store.h"
 #include "URL.h"
@@ -41,13 +44,13 @@ HttpRequest::HttpRequest() :
     init();
 }
 
-HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) :
+HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath) :
     HttpMsg(hoRequest)
 {
     static unsigned int id = 1;
     debugs(93,7, HERE << "constructed, this=" << this << " id=" << ++id);
     init();
-    initHTTP(aMethod, aProtocol, aUrlpath);
+    initHTTP(aMethod, aProtocol, aSchemeImg, aUrlpath);
 }
 
 HttpRequest::~HttpRequest()
@@ -57,11 +60,11 @@ HttpRequest::~HttpRequest()
 }
 
 void
-HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath)
+HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath)
 {
     method = aMethod;
-    url.setScheme(aProtocol);
-    urlpath = aUrlpath;
+    url.setScheme(aProtocol, aSchemeImg);
+    url.path(aUrlpath);
 }
 
 void
@@ -69,14 +72,9 @@ HttpRequest::init()
 {
     method = Http::METHOD_NONE;
     url.clear();
-    urlpath = NULL;
-    host[0] = '\0';
-    host_is_numeric = -1;
 #if USE_AUTH
     auth_user_request = NULL;
 #endif
-    port = 0;
-    canonical = NULL;
     memset(&flags, '\0', sizeof(flags));
     range = NULL;
     ims = -1;
@@ -92,7 +90,7 @@ HttpRequest::init()
     peer_login = NULL;      // not allocated/deallocated by this class
     peer_domain = NULL;     // not allocated/deallocated by this class
     peer_host = NULL;
-    vary_headers = NULL;
+    vary_headers = SBuf();
     myportname = null_string;
     tag = null_string;
 #if USE_AUTH
@@ -124,12 +122,8 @@ HttpRequest::clean()
 #if USE_AUTH
     auth_user_request = NULL;
 #endif
-    safe_free(canonical);
-
-    safe_free(vary_headers);
-
+    vary_headers.clear();
     url.clear();
-    urlpath.clean();
 
     header.clean();
 
@@ -176,7 +170,8 @@ HttpRequest::reset()
 HttpRequest *
 HttpRequest::clone() const
 {
-    HttpRequest *copy = new HttpRequest(method, url.getScheme(), urlpath.termedBuf());
+    HttpRequest *copy = new HttpRequest();
+    copy->method = method;
     // TODO: move common cloning clone to Msg::copyTo() or copy ctor
     copy->header.append(&header);
     copy->hdrCacheInit();
@@ -185,13 +180,7 @@ HttpRequest::clone() const
     copy->pstate = pstate; // TODO: should we assert a specific state here?
     copy->body_pipe = body_pipe;
 
-    copy->url.userInfo(url.userInfo());
-    strncpy(copy->host, host, sizeof(host)); // SQUIDHOSTNAMELEN
-    copy->host_addr = host_addr;
-
-    copy->port = port;
-    // urlPath handled in ctor
-    copy->canonical = canonical ? xstrdup(canonical) : NULL;
+    copy->url = url;
 
     // range handled in hdrCacheInit()
     copy->ims = ims;
@@ -204,7 +193,7 @@ HttpRequest::clone() const
 
     copy->lastmod = lastmod;
     copy->etag = etag;
-    copy->vary_headers = vary_headers ? xstrdup(vary_headers) : NULL;
+    copy->vary_headers = vary_headers;
     // XXX: what to do with copy->peer_domain?
 
     copy->tag = tag;
@@ -258,7 +247,11 @@ HttpRequest::inheritProperties(const HttpMsg *aMsg)
     // main property is which connection the request was received on (if any)
     clientConnectionManager = aReq->clientConnectionManager;
 
+    downloader = aReq->downloader;
+
     notes = aReq->notes;
+
+    sources = aReq->sources;
     return true;
 }
 
@@ -344,42 +337,25 @@ HttpRequest::parseFirstLine(const char *start, const char *end)
     return true;
 }
 
-bool
-HttpRequest::parseHeader(Http1::RequestParser &hp)
-{
-    // HTTP/1 message contains "zero or more header fields"
-    // zero does not need parsing
-    if (!hp.headerBlockSize())
-        return true;
-
-    // XXX: c_str() reallocates. performance regression.
-    const bool result = header.parse(hp.mimeHeader().c_str(), hp.headerBlockSize());
-
-    if (result)
-        hdrCacheInit();
-
-    return result;
-}
-
 /* swaps out request using httpRequestPack */
 void
 HttpRequest::swapOut(StoreEntry * e)
 {
-    Packer p;
     assert(e);
-    packerToStoreInit(&p, e);
-    pack(&p);
+    e->buffer();
+    pack(e);
+    e->flush();
 }
 
 /* packs request-line and headers, appends <crlf> terminator */
 void
-HttpRequest::pack(Packable * p)
+HttpRequest::pack(Packable * p) const
 {
     assert(p);
     /* pack request-line */
-    p->Printf(SQUIDSBUFPH " " SQUIDSTRINGPH " HTTP/%d.%d\r\n",
-              SQUIDSBUFPRINT(method.image()), SQUIDSTRINGPRINT(urlpath),
-              http_ver.major, http_ver.minor);
+    p->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " HTTP/%d.%d\r\n",
+               SQUIDSBUFPRINT(method.image()), SQUIDSBUFPRINT(url.path()),
+               http_ver.major, http_ver.minor);
     /* headers */
     header.packInto(p);
     /* trailer */
@@ -398,10 +374,10 @@ httpRequestPack(void *obj, Packable *p)
 
 /* returns the length of request line + headers + crlf */
 int
-HttpRequest::prefixLen()
+HttpRequest::prefixLen() const
 {
     return method.image().length() + 1 +
-           urlpath.size() + 1 +
+           url.path().length() + 1 +
            4 + 1 + 3 + 2 +
            header.len + 2;
 }
@@ -496,24 +472,16 @@ HttpRequest::clearError()
     errDetail = ERR_DETAIL_NONE;
 }
 
-const char *HttpRequest::packableURI(bool full_uri) const
+void
+HttpRequest::packFirstLineInto(Packable * p, bool full_uri) const
 {
-    if (full_uri)
-        return urlCanonical((HttpRequest*)this);
-
-    if (urlpath.size())
-        return urlpath.termedBuf();
+    const SBuf tmp(full_uri ? effectiveRequestUri() : url.path());
 
-    return "/";
-}
-
-void HttpRequest::packFirstLineInto(Packable * p, bool full_uri) const
-{
     // form HTTP request-line
-    p->Printf(SQUIDSBUFPH " %s HTTP/%d.%d\r\n",
-              SQUIDSBUFPRINT(method.image()),
-              packableURI(full_uri),
-              http_ver.major, http_ver.minor);
+    p->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " HTTP/%d.%d\r\n",
+               SQUIDSBUFPRINT(method.image()),
+               SQUIDSBUFPRINT(tmp),
+               http_ver.major, http_ver.minor);
 }
 
 /*
@@ -550,22 +518,11 @@ HttpRequest::expectingBody(const HttpRequestMethod &, int64_t &theSize) const
  * If the request cannot be created cleanly, NULL is returned
  */
 HttpRequest *
-HttpRequest::CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method)
+HttpRequest::CreateFromUrl(char * url, const HttpRequestMethod& method)
 {
     return urlParse(method, url, NULL);
 }
 
-/*
- * Create a Request from a URL.
- *
- * If the request cannot be created cleanly, NULL is returned
- */
-HttpRequest *
-HttpRequest::CreateFromUrl(char * url)
-{
-    return urlParse(Http::METHOD_GET, url, NULL);
-}
-
 /**
  * Are responses to this request possible cacheable ?
  * If false then no matter what the response must not be cached.
@@ -586,8 +543,13 @@ HttpRequest::maybeCacheable()
         if (!method.respMaybeCacheable())
             return false;
 
-        // XXX: this would seem the correct place to detect request cache-controls
-        //      no-store, private and related which block cacheability
+        // RFC 7234 section 5.2.1.5:
+        // "cache MUST NOT store any part of either this request or any response to it"
+        //
+        // NP: refresh_pattern ignore-no-store only applies to response messages
+        //     this test is handling request message CC header.
+        if (!flags.ignoreCc && cache_control && cache_control->noStore())
+            return false;
         break;
 
     case AnyP::PROTO_GOPHER:
@@ -610,8 +572,8 @@ bool
 HttpRequest::conditional() const
 {
     return flags.ims ||
-           header.has(HDR_IF_MATCH) ||
-           header.has(HDR_IF_NONE_MATCH);
+           header.has(Http::HdrType::IF_MATCH) ||
+           header.has(Http::HdrType::IF_NONE_MATCH);
 }
 
 void
@@ -670,8 +632,8 @@ bool
 HttpRequest::canHandle1xx() const
 {
     // old clients do not support 1xx unless they sent Expect: 100-continue
-    // (we reject all other HDR_EXPECT values so just check for HDR_EXPECT)
-    if (http_ver <= Http::ProtocolVersion(1,0) && !header.has(HDR_EXPECT))
+    // (we reject all other Http::HdrType::EXPECT values so just check for Http::HdrType::EXPECT)
+    if (http_ver <= Http::ProtocolVersion(1,0) && !header.has(Http::HdrType::EXPECT))
         return false;
 
     // others must support 1xx control messages
@@ -686,16 +648,22 @@ HttpRequest::pinnedConnection()
     return NULL;
 }
 
-const char *
+const SBuf
 HttpRequest::storeId()
 {
     if (store_id.size() != 0) {
-        debugs(73, 3, "sent back store_id:" << store_id);
-
-        return store_id.termedBuf();
+        debugs(73, 3, "sent back store_id: " << store_id);
+        return StringToSBuf(store_id);
     }
-    debugs(73, 3, "sent back canonicalUrl:" << urlCanonical(this) );
+    debugs(73, 3, "sent back effectiveRequestUrl: " << effectiveRequestUri());
+    return effectiveRequestUri();
+}
 
-    return urlCanonical(this);
+const SBuf &
+HttpRequest::effectiveRequestUri() const
+{
+    if (method.id() == Http::METHOD_CONNECT || url.getScheme() == AnyP::PROTO_AUTHORITY_FORM)
+        return url.authority(true); // host:port
+    return url.absolute();
 }