/*
- * 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"
#include "adaptation/icap/icap_log.h"
#endif
-HttpRequest::HttpRequest() :
- HttpMsg(hoRequest)
+HttpRequest::HttpRequest(const MasterXaction::Pointer &mx) :
+ Http::Message(hoRequest),
+ masterXaction(mx)
{
+ assert(mx);
init();
}
-HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) :
- HttpMsg(hoRequest)
+HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath, const MasterXaction::Pointer &mx) :
+ Http::Message(hoRequest),
+ masterXaction(mx)
{
+ assert(mx);
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()
}
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
{
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;
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
#endif
extacl_log = null_string;
extacl_message = null_string;
- pstate = psReadyToParseStartLine;
+ pstate = Http::Message::psReadyToParseStartLine;
#if FOLLOW_X_FORWARDED_FOR
indirect_client_addr.setEmpty();
#endif /* FOLLOW_X_FORWARDED_FOR */
#if USE_AUTH
auth_user_request = NULL;
#endif
- safe_free(canonical);
-
- safe_free(vary_headers);
-
+ vary_headers.clear();
url.clear();
- urlpath.clean();
header.clean();
myportname.clean();
- notes = NULL;
+ theNotes = nullptr;
tag.clean();
#if USE_AUTH
HttpRequest *
HttpRequest::clone() const
{
- HttpRequest *copy = new HttpRequest(method, url.getScheme(), urlpath.termedBuf());
+ HttpRequest *copy = new HttpRequest(masterXaction);
+ copy->method = method;
// TODO: move common cloning clone to Msg::copyTo() or copy ctor
copy->header.append(&header);
copy->hdrCacheInit();
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;
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;
}
bool
-HttpRequest::inheritProperties(const HttpMsg *aMsg)
+HttpRequest::inheritProperties(const Http::Message *aMsg)
{
const HttpRequest* aReq = dynamic_cast<const HttpRequest*>(aMsg);
if (!aReq)
// main property is which connection the request was received on (if any)
clientConnectionManager = aReq->clientConnectionManager;
- notes = aReq->notes;
+ downloader = aReq->downloader;
+
+ theNotes = aReq->theNotes;
+
+ sources = aReq->sources;
return true;
}
* (char *) end = '\0'; // temp terminate URI, XXX dangerous?
- HttpRequest *tmp = urlParse(method, (char *) start, this);
+ const bool ret = urlParse(method, (char *) start, *this);
* (char *) end = save;
- if (NULL == tmp)
- return false;
-
- 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;
+ return ret;
}
/* swaps out request using httpRequestPack */
void
HttpRequest::swapOut(StoreEntry * e)
{
- Packer p;
assert(e);
- packerToStoreInit(&p, e);
- pack(&p);
- packerClean(&p);
+ e->buffer();
+ pack(e);
+ e->flush();
}
/* packs request-line and headers, appends <crlf> terminator */
void
-HttpRequest::pack(Packer * p)
+HttpRequest::pack(Packable * p) const
{
assert(p);
/* pack request-line */
- packerPrintf(p, 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 */
- packerAppend(p, "\r\n", 2);
+ p->append("\r\n", 2);
}
/*
* A wrapper for debugObj()
*/
void
-httpRequestPack(void *obj, Packer *p)
+httpRequestPack(void *obj, Packable *p)
{
HttpRequest *request = static_cast<HttpRequest*>(obj);
request->pack(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;
}
void
HttpRequest::hdrCacheInit()
{
- HttpMsg::hdrCacheInit();
+ Http::Message::hdrCacheInit();
assert(!range);
range = header.getRange();
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(Packer * p, bool full_uri) const
-{
// form HTTP request-line
- packerPrintf(p, 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);
}
/*
* If the request cannot be created cleanly, NULL is returned
*/
HttpRequest *
-HttpRequest::CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method)
+HttpRequest::FromUrl(char * url, const MasterXaction::Pointer &mx, 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);
+ std::unique_ptr<HttpRequest> req(new HttpRequest(mx));
+ if (urlParse(method, url, *req))
+ return req.release();
+ return nullptr;
}
/**
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->hasNoStore())
+ return false;
break;
case AnyP::PROTO_GOPHER:
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
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
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();
+}
+
+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();
+}
+
+NotePairs::Pointer
+HttpRequest::notes()
+{
+ if (!theNotes)
+ theNotes = new NotePairs;
+ return theNotes;
+}
- return urlCanonical(this);
+void
+UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
+{
+ // Tag client connection if the helper responded with clt_conn_tag=tag.
+ const char *cltTag = "clt_conn_tag";
+ if (const char *connTag = helperNotes.findFirst(cltTag)) {
+ if (csd) {
+ csd->notes()->remove(cltTag);
+ csd->notes()->add(cltTag, connTag);
+ }
+ }
+ request.notes()->replaceOrAdd(&helperNotes);
}