]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Cleanup: replace urlCanonical() with HttpRequest::effectiveReuqestUri()
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 19 Jul 2015 13:23:01 +0000 (06:23 -0700)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 19 Jul 2015 13:23:01 +0000 (06:23 -0700)
We have previously been using the term "canonical URL" in Squid to mean
absolute-URI, but not in all cases and may sometimes mean authority-form.
RFC 7230 introduces a new term "Effective Request URI" which directly
matches our desired usage.

* make urlCanonical() global function a method of class HttpRequest
  since it depends on request method for its particular form syntax

* remove the now unnecessary canonical member and HttpRequest::SetHost()

* convert HttpRequest::storeId(), Ftp::UrlWith2f(), and ps_state::url()
  to SBuf usage to avoid performance regressions in their use.

* replace many uses of xstrdup() with xstrndup() for performance where
  the copy cannot be avoided entirely.

* avoid using urlParse() to do a simple URL data-copy in ICAP handling

* update stub_HttpRequest.cc to match full class HttpRequest API

29 files changed:
src/HttpRequest.cc
src/HttpRequest.h
src/PeerPoolMgr.cc
src/PeerSelectState.h
src/URL.h
src/acl/Url.cc
src/adaptation/ecap/MessageRep.cc
src/adaptation/icap/ModXact.cc
src/carp.cc
src/client_side.cc
src/client_side_reply.cc
src/client_side_request.cc
src/clients/Client.cc
src/clients/FtpGateway.cc
src/clients/forward.h
src/errorpage.cc
src/external_acl.cc
src/format/Format.cc
src/http.cc
src/icmp/net_db.cc
src/peer_select.cc
src/refresh.cc
src/ssl/PeerConnector.cc
src/ssl/ServerBump.cc
src/store_key_md5.cc
src/store_swapmeta.cc
src/tests/stub_HttpRequest.cc
src/tunnel.cc
src/url.cc

index 3a2b0f3d382703493bcd378b3c5a326578eacbb8..bc60ec3600e76df7ecdb5d8843b3c302f31bf384 100644 (file)
@@ -72,7 +72,6 @@ HttpRequest::init()
 #if USE_AUTH
     auth_user_request = NULL;
 #endif
-    canonical = NULL;
     memset(&flags, '\0', sizeof(flags));
     range = NULL;
     ims = -1;
@@ -120,8 +119,6 @@ HttpRequest::clean()
 #if USE_AUTH
     auth_user_request = NULL;
 #endif
-    safe_free(canonical);
-
     safe_free(vary_headers);
 
     url.clear();
@@ -187,9 +184,6 @@ HttpRequest::clone() const
     copy->url.port(url.port());
     copy->url.path(url.path());
 
-    // urlPath handled in ctor
-    copy->canonical = canonical ? xstrdup(canonical) : NULL;
-
     // range handled in hdrCacheInit()
     copy->ims = ims;
     copy->imslen = imslen;
@@ -495,11 +489,7 @@ HttpRequest::clearError()
 void
 HttpRequest::packFirstLineInto(Packable * p, bool full_uri) const
 {
-    SBuf tmp;
-    if (full_uri)
-        tmp = urlCanonical((HttpRequest*)this);
-    else
-        tmp = url.path();
+    const SBuf tmp(full_uri ? effectiveRequestUri() : url.path());
 
     // form HTTP request-line
     p->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " HTTP/%d.%d\r\n",
@@ -678,16 +668,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 SBuf(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)
+        return url.authority(true); // host:port
+    return url.absolute();
 }
 
index a0f11d68556e16cf4da7dcbde2e4abd1dcbf651f..2f26cb100d1b2e59aa9b8b486a5445400dabcd8a 100644 (file)
@@ -66,14 +66,6 @@ public:
     /// whether the client is likely to be able to handle a 1xx reply
     bool canHandle1xx() const;
 
-    /* HACK: This method is only inline to get around Makefile dependancies */
-    /*      caused by HttpRequest being used in places it really shouldn't. */
-    /*      ideally URL would be used directly instead.                     */
-    inline void SetHost(const char *src) {
-        url.host(src);
-        safe_free(canonical); // force its re-build
-    };
-
 #if USE_ADAPTATION
     /// Returns possibly nil history, creating it if adapt. logging is enabled
     Adaptation::History::Pointer adaptLogHistory() const;
@@ -116,7 +108,8 @@ public:
     Auth::UserRequest::Pointer auth_user_request;
 #endif
 
-    char *canonical;
+    /// RFC 7230 section 5.5 - Effective Request URI
+    const SBuf &effectiveRequestUri() const;
 
     /**
      * If defined, store_id_program mapped the request URL to this ID.
@@ -211,10 +204,9 @@ public:
     /**
      * Returns the current StoreID for the request as a nul-terminated char*.
      * Always returns the current id for the request
-     * (either the request canonical url or modified ID by the helper).
-     * Does not return NULL.
+     * (either the effective request URI or modified ID by the helper).
      */
-    const char *storeId();
+    const SBuf storeId();
 
     /**
      * The client connection manager, if known;
index 49cf370aa77840302e9a8a06e8ede81c648368b9..ffd4c39509cb857a1b1b8c15808c691f4bed0f4d 100644 (file)
@@ -67,7 +67,7 @@ PeerPoolMgr::start()
     // ErrorState, getOutgoingAddress(), and other APIs may require a request.
     // We fake one. TODO: Optionally send this request to peers?
     request = new HttpRequest(Http::METHOD_OPTIONS, AnyP::PROTO_HTTP, "*");
-    request->SetHost(peer->host);
+    request->url.host(peer->host);
 
     checkpoint("peer initialized");
 }
index ad34fbec7ad914c473b8557c70cb81528860e2f6..7b94706e27a26166f6c9d6f3c424a7d4bed6c88f 100644 (file)
@@ -53,7 +53,7 @@ public:
 
     // Produce a URL for display identifying the transaction we are
     // trying to locate a peer for.
-    const char * url() const;
+    const SBuf url() const;
 
     HttpRequest *request;
     AccessLogEntry::Pointer al; ///< info for the future access.log entry
index 3ae18ead79819f5f4902773448a850c6e3ff7558..f13df3de3e48ccf3a615ad274a981660ca620955 100644 (file)
--- a/src/URL.h
+++ b/src/URL.h
@@ -143,7 +143,6 @@ class HttpRequestMethod;
 AnyP::ProtocolType urlParseProtocol(const char *, const char *e = NULL);
 void urlInitialize(void);
 HttpRequest *urlParse(const HttpRequestMethod&, char *, HttpRequest *request = NULL);
-const char *urlCanonical(HttpRequest *);
 char *urlCanonicalClean(const HttpRequest *);
 const char *urlCanonicalFakeHttps(const HttpRequest * request);
 bool urlIsRelative(const char *);
index e145e44ddf6250aac77d9d93bf1b693ee75064f7..5a83c8cfb365d13e0cd679aba8f5bc01f726e88c 100644 (file)
 #include "acl/Checklist.h"
 #include "acl/RegexData.h"
 #include "acl/Url.h"
+#include "HttpRequest.h"
 #include "rfc1738.h"
 #include "src/URL.h"
 
 int
 ACLUrlStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
 {
-    char *esc_buf = xstrdup(urlCanonical(checklist->request));
+    const SBuf &tmp = checklist->request->effectiveRequestUri();
+    char *esc_buf = xstrndup(tmp.rawContent(), tmp.length()+1);
     rfc1738_unescape(esc_buf);
     int result = data->match(esc_buf);
-    safe_free(esc_buf);
+    xfree(esc_buf);
     return result;
 }
 
index 0676ea545211b4b1452d87172d6efe517caad446..ade77fac9bb248738407b0c77d491d3c6c13035b 100644 (file)
@@ -212,10 +212,11 @@ Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
 Adaptation::Ecap::RequestLineRep::Area
 Adaptation::Ecap::RequestLineRep::uri() const
 {
-    const char *fullUrl = urlCanonical(&theMessage);
-    Must(fullUrl);
+    const SBuf &fullUrl = theMessage.effectiveRequestUri();
+    // XXX: effectiveRequestUri() cannot return NULL or even empty string, some other problem?
+    Must(!fullUrl.isEmpty());
     // optimize: avoid copying by having an Area::Detail that locks theMessage
-    return Area::FromTempBuffer(fullUrl, strlen(fullUrl));
+    return Area::FromTempBuffer(fullUrl.rawContent(), fullUrl.length());
 }
 
 void
index 310227048bc24637d96076f41c8131f7b823e013..8fb8f1109973ae65c303a0c5a463e82474dcf4de 100644 (file)
@@ -968,10 +968,6 @@ void Adaptation::Icap::ModXact::prepEchoing()
 
     httpBuf.terminate(); // HttpMsg::parse requires nil-terminated buffer
     Must(adapted.header->parse(httpBuf.content(), httpBuf.contentSize(), true, &error));
-
-    if (HttpRequest *r = dynamic_cast<HttpRequest*>(adapted.header))
-        urlCanonical(r); // parse does not set HttpRequest::canonical
-
     Must(adapted.header->hdr_sz == httpBuf.contentSize()); // no leftovers
 
     httpBuf.clean();
@@ -1090,9 +1086,6 @@ bool Adaptation::Icap::ModXact::parseHead(HttpMsg *head)
         return false;
     }
 
-    if (HttpRequest *r = dynamic_cast<HttpRequest*>(head))
-        urlCanonical(r); // parse does not set HttpRequest::canonical
-
     debugs(93, 5, HERE << "parse success, consume " << head->hdr_sz << " bytes, return true");
     readBuf.consume(head->hdr_sz);
     return true;
@@ -1539,8 +1532,9 @@ void Adaptation::Icap::ModXact::encapsulateHead(MemBuf &icapBuf, const char *sec
 
     if (const HttpRequest* old_request = dynamic_cast<const HttpRequest*>(head)) {
         HttpRequest::Pointer new_request(new HttpRequest);
-        Must(old_request->canonical);
-        urlParse(old_request->method, old_request->canonical, new_request.getRaw());
+        // copy the requst-line details
+        new_request->method = old_request->method;
+        new_request->url = old_request->url;
         new_request->http_ver = old_request->http_ver;
         headClone = new_request.getRaw();
     } else if (const HttpReply *old_reply = dynamic_cast<const HttpReply*>(head)) {
index dcc75c3e765f7a4f10104db8d42a0e4508a32cdd..957ddc47edf483e8fd9da0a8068105722deab19a 100644 (file)
@@ -157,15 +157,15 @@ carpSelectParent(HttpRequest * request)
         return NULL;
 
     /* calculate hash key */
-    debugs(39, 2, "carpSelectParent: Calculating hash for " << urlCanonical(request));
+    debugs(39, 2, "carpSelectParent: Calculating hash for " << request->effectiveRequestUri());
 
     /* select CachePeer */
     for (k = 0; k < n_carp_peers; ++k) {
         SBuf key;
         tp = carp_peers[k];
         if (tp->options.carp_key.set) {
-            //this code follows urlCanonical's pattern.
-            //   corner cases should use the canonical URL
+            // this code follows URI syntax pattern.
+            // corner cases should use the full effective request URI
             if (tp->options.carp_key.scheme) {
                 key.append(request->url.getScheme().c_str());
                 if (key.length()) //if the scheme is not empty
@@ -190,10 +190,10 @@ carpSelectParent(HttpRequest * request)
         }
         // if the url-based key is empty, e.g. because the user is
         // asking to balance on the path but the request doesn't supply any,
-        // then fall back to canonical URL
+        // then fall back to the effective request URI
 
         if (key.isEmpty())
-            key=SBuf(urlCanonical(request));
+            key=request->effectiveRequestUri();
 
         for (const char *c = key.rawContent(), *e=key.rawContent()+key.length(); c < e; ++c)
             user_hash += ROTATE_LEFT(user_hash, 19) + *c;
index 338be92d59f09e6341e581bcde2e05015019a09e..22abf07d55ffa5ecbefc688430f603d9997d743c 100644 (file)
@@ -2564,7 +2564,7 @@ clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp,
         } else if (Config.onoff.global_internal_static && internalStaticCheck(request->url.path())) {
             debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
             request->url.setScheme(AnyP::PROTO_HTTP);
-            request->SetHost(internalHostname());
+            request->url.host(internalHostname());
             request->url.port(getMyPort());
             http->flags.internal = true;
         } else
@@ -3775,7 +3775,7 @@ ConnStateData::postHttpsAccept()
         HttpRequest *request = new HttpRequest();
         static char ip[MAX_IPSTRLEN];
         assert(clientConnection->flags & (COMM_TRANSPARENT | COMM_INTERCEPTION));
-        request->SetHost(clientConnection->local.toStr(ip, sizeof(ip)));
+        request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
         request->url.port(clientConnection->local.port());
         request->myportname = port->name;
 
index fcd73c85d9ade953f36b11e2d869be6bc24269fe..73ade1dc706f393dc44cc275a1067a7d0a227a41 100644 (file)
@@ -512,7 +512,7 @@ clientReplyContext::cacheHit(StoreIOBuffer result)
      */
     assert(http->logType.oldType == LOG_TCP_HIT);
 
-    if (strcmp(e->mem_obj->storeId(), http->request->storeId()) != 0) {
+    if (http->request->storeId().cmp(e->mem_obj->storeId()) != 0) {
         debugs(33, DBG_IMPORTANT, "clientProcessHit: URL mismatch, '" << e->mem_obj->storeId() << "' != '" << http->request->storeId() << "'");
         http->logType = LOG_TCP_MISS; // we lack a more precise LOG_*_MISS code
         processMiss();
@@ -867,8 +867,9 @@ purgeEntriesByUrl(HttpRequest * req, const char *url)
 void
 clientReplyContext::purgeAllCached()
 {
-    const char *url = urlCanonical(http->request);
-    purgeEntriesByUrl(http->request, url);
+    // XXX: performance regression, c_str() reallocates
+    SBuf url(http->request->effectiveRequestUri());
+    purgeEntriesByUrl(http->request, url.c_str());
 }
 
 void
@@ -997,7 +998,7 @@ void
 clientReplyContext::purgeDoPurgeHead(StoreEntry *newEntry)
 {
     if (newEntry && !newEntry->isNull()) {
-        debugs(88, 4, "clientPurgeRequest: HEAD '" << newEntry->url() << "'" );
+        debugs(88, 4, "HEAD " << newEntry->url());
 #if USE_HTCP
         neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE);
 #endif
@@ -1009,10 +1010,12 @@ clientReplyContext::purgeDoPurgeHead(StoreEntry *newEntry)
 
     if (http->request->vary_headers
             && !strstr(http->request->vary_headers, "=")) {
-        StoreEntry *entry = storeGetPublic(urlCanonical(http->request), Http::METHOD_GET);
+        // XXX: performance regression, c_str() reallocates
+        SBuf tmp(http->request->effectiveRequestUri());
+        StoreEntry *entry = storeGetPublic(tmp.c_str(), Http::METHOD_GET);
 
         if (entry) {
-            debugs(88, 4, "clientPurgeRequest: Vary GET '" << entry->url() << "'" );
+            debugs(88, 4, "Vary GET " << entry->url());
 #if USE_HTCP
             neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE);
 #endif
@@ -1020,10 +1023,10 @@ clientReplyContext::purgeDoPurgeHead(StoreEntry *newEntry)
             purgeStatus = Http::scOkay;
         }
 
-        entry = storeGetPublic(urlCanonical(http->request), Http::METHOD_HEAD);
+        entry = storeGetPublic(tmp.c_str(), Http::METHOD_HEAD);
 
         if (entry) {
-            debugs(88, 4, "clientPurgeRequest: Vary HEAD '" << entry->url() << "'" );
+            debugs(88, 4, "Vary HEAD " << entry->url());
 #if USE_HTCP
             neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE);
 #endif
index e726b4d0dac62c97c964aef21254ed84965e8922..ecb223d15dfa5a10f8edf83864788f8ab9a4c317 100644 (file)
@@ -559,7 +559,7 @@ ClientRequestContext::hostHeaderVerifyFailed(const char *A, const char *B)
     // NP: we do not yet handle CONNECT tunnels well, so ignore for them
     if (!Config.onoff.hostStrictVerify && http->request->method != Http::METHOD_CONNECT) {
         debugs(85, 3, "SECURITY ALERT: Host header forgery detected on " << http->getConn()->clientConnection <<
-               " (" << A << " does not match " << B << ") on URL: " << urlCanonical(http->request));
+               " (" << A << " does not match " << B << ") on URL: " << http->request->effectiveRequestUri());
 
         // NP: it is tempting to use 'flags.noCache' but that is all about READing cache data.
         // The problems here are about WRITE for new cache content, which means flags.cachable
@@ -574,7 +574,7 @@ ClientRequestContext::hostHeaderVerifyFailed(const char *A, const char *B)
     debugs(85, DBG_IMPORTANT, "SECURITY ALERT: Host header forgery detected on " <<
            http->getConn()->clientConnection << " (" << A << " does not match " << B << ")");
     debugs(85, DBG_IMPORTANT, "SECURITY ALERT: By user agent: " << http->request->header.getStr(HDR_USER_AGENT));
-    debugs(85, DBG_IMPORTANT, "SECURITY ALERT: on URL: " << urlCanonical(http->request));
+    debugs(85, DBG_IMPORTANT, "SECURITY ALERT: on URL: " << http->request->effectiveRequestUri());
 
     // IP address validation for Host: failed. reject the connection.
     clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
@@ -834,9 +834,8 @@ ClientRequestContext::clientAccessCheckDone(const allow_t &answer)
 
     /* ACCESS_ALLOWED continues here ... */
     safe_free(http->uri);
-
-    http->uri = xstrdup(urlCanonical(http->request));
-
+    const SBuf tmp(http->request->effectiveRequestUri());
+    http->uri = xstrndup(tmp.rawContent(), tmp.length()+1);
     http->doCallouts();
 }
 
@@ -1300,7 +1299,7 @@ ClientRequestContext::clientRedirectDone(const Helper::Reply &reply)
                 // XXX: the clone() should be done only AFTER we know the new URL is valid.
                 HttpRequest *new_request = old_request->clone();
                 if (urlParse(old_request->method, const_cast<char*>(urlNote), new_request)) {
-                    debugs(61,2, HERE << "URL-rewriter diverts URL from " << urlCanonical(old_request) << " to " << urlCanonical(new_request));
+                    debugs(61, 2, "URL-rewriter diverts URL from " << old_request->effectiveRequestUri() << " to " << new_request->effectiveRequestUri());
 
                     // update the new request to flag the re-writing was done on it
                     new_request->flags.redirected = true;
@@ -1314,7 +1313,8 @@ ClientRequestContext::clientRedirectDone(const Helper::Reply &reply)
 
                     // update the current working ClientHttpRequest fields
                     safe_free(http->uri);
-                    http->uri = xstrdup(urlCanonical(new_request));
+                    const SBuf tmp(new_request->effectiveRequestUri());
+                    http->uri = xstrndup(tmp.rawContent(), tmp.length()+1);
                     HTTPMSGUNLOCK(old_request);
                     http->request = new_request;
                     HTTPMSGLOCK(http->request);
@@ -1806,8 +1806,9 @@ ClientHttpRequest::doCallouts()
 #endif
 
     if (calloutContext->error) {
-        const char *storeUri = request->storeId();
-        StoreEntry *e= storeCreateEntry(storeUri, storeUri, request->flags, request->method);
+        // XXX: prformance regression. c_str() reallocates
+        SBuf storeUri(request->storeId());
+        StoreEntry *e = storeCreateEntry(storeUri.c_str(), storeUri.c_str(), request->flags, request->method);
 #if USE_OPENSSL
         if (sslBumpNeeded()) {
             // We have to serve an error, so bump the client first.
@@ -1911,14 +1912,15 @@ ClientHttpRequest::handleAdaptedHeader(HttpMsg *msg)
         HTTPMSGLOCK(request);
 
         // update the new message to flag whether URL re-writing was done on it
-        if (strcmp(urlCanonical(request),uri) != 0)
+        if (request->effectiveRequestUri().cmp(uri) != 0)
             request->flags.redirected = 1;
 
         /*
          * Store the new URI for logging
          */
         xfree(uri);
-        uri = xstrdup(urlCanonical(request));
+        const SBuf tmp(request->effectiveRequestUri());
+        uri = xstrndup(tmp.rawContent(), tmp.length());
         setLogUri(this, urlCanonicalClean(request));
         assert(request->method.id());
     } else if (HttpReply *new_rep = dynamic_cast<HttpReply*>(msg)) {
index 6754a0695a37ee2a74e5840cc9c75e1eeece2e80..4343fa04318502cf3a02da6be15a2215b3c03d0a 100644 (file)
@@ -493,8 +493,9 @@ Client::maybePurgeOthers()
         return;
 
     // XXX: should we use originalRequest() here?
-    const char *reqUrl = urlCanonical(request);
-    debugs(88, 5, "maybe purging due to " << request->method << ' ' << reqUrl);
+    SBuf tmp(request->effectiveRequestUri());
+    const char *reqUrl = tmp.c_str();
+    debugs(88, 5, "maybe purging due to " << request->method << ' ' << tmp);
     purgeEntriesByUrl(request, reqUrl);
     purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_LOCATION);
     purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_CONTENT_LOCATION);
index 8b6dbfbdcbdc8d80a2bca7f0058261c7c8daae2e..4addef7d2cb33dd21cd81b18e2a51dbd74a17322 100644 (file)
@@ -2642,25 +2642,25 @@ Ftp::Gateway::ftpAuthRequired(HttpRequest * request, const char *realm)
     return newrep;
 }
 
-const char *
+const SBuf &
 Ftp::UrlWith2f(HttpRequest * request)
 {
     SBuf newbuf("%2f");
 
-    if (request->url.getScheme() != AnyP::PROTO_FTP)
-        return NULL;
+    if (request->url.getScheme() != AnyP::PROTO_FTP) {
+        static const SBuf nil;
+        return nil;
+    }
 
     if (request->url.path()[0] == '/') {
         newbuf.append(request->url.path());
         request->url.path(newbuf);
-        safe_free(request->canonical);
     } else if (!request->url.path().startsWith(newbuf)) {
         newbuf.append(request->url.path().substr(1));
         request->url.path(newbuf);
-        safe_free(request->canonical);
     }
 
-    return urlCanonical(request);
+    return request->effectiveRequestUri();
 }
 
 void
index 4575bf66850646b9821354725c3599a35eb79036..8ad012eb3b3a31ac5dbb83c2a2e3b7789470f2f9 100644 (file)
@@ -11,6 +11,7 @@
 
 class FwdState;
 class HttpRequest;
+class SBuf;
 
 class AsyncJob;
 template <class Cbc> class CbcPointer;
@@ -35,7 +36,7 @@ AsyncJobPointer StartRelay(FwdState *const fwdState);
  *
  * \todo Should be a URL class API call.
  */
-const char *UrlWith2f(HttpRequest *);
+const SBuf &UrlWith2f(HttpRequest *);
 
 } // namespace Ftp
 
index 18b9c307781d8ec0e28b449ca61a31f08acb7520..abc89ea9f4071ee63c7287d0a85298e0fa486807 100644 (file)
@@ -792,7 +792,11 @@ ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion
 
     case 'B':
         if (building_deny_info_url) break;
-        p = request ? Ftp::UrlWith2f(request) : "[no URL]";
+        if (request) {
+            const SBuf &tmp = Ftp::UrlWith2f(request);
+            mb.append(tmp.rawContent(), tmp.length());
+        } else
+            p = "[no URL]";
         break;
 
     case 'c':
@@ -969,7 +973,11 @@ ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion
     case 's':
         /* for backward compat we make %s show the full URL. Drop this in some future release. */
         if (building_deny_info_url) {
-            p = request ? urlCanonical(request) : url;
+            if (request) {
+                const SBuf &tmp = request->effectiveRequestUri();
+                mb.append(tmp.rawContent(), tmp.length());
+            } else
+                p = url;
             debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
         } else
             p = visible_appname_string;
@@ -1005,7 +1013,7 @@ ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion
         break;
 
     case 'U':
-        /* Using the fake-https version of canonical so error pages see https:// */
+        /* Using the fake-https version of absolute-URI so error pages see https:// */
         /* even when the url-path cannot be shown as more than '*' */
         if (request)
             p = urlCanonicalFakeHttps(request);
@@ -1016,9 +1024,10 @@ ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion
         break;
 
     case 'u':
-        if (request)
-            p = urlCanonical(request);
-        else if (url)
+        if (request) {
+            const SBuf &tmp = request->effectiveRequestUri();
+            mb.append(tmp.rawContent(), tmp.length());
+        } else if (url)
             p = url;
         else if (!building_deny_info_url)
             p = "[no URL]";
index a2a2656ced61c45b083a24db2c405ba629fe3572..fe480cf88c777bd3baac93a61ec45f1280ebe349 100644 (file)
@@ -962,7 +962,8 @@ makeExternalAclKey(ACLFilledChecklist * ch, external_acl_data * acl_data)
             break;
 
         case Format::LFT_CLIENT_REQ_URI:
-            str = urlCanonical(request);
+            snprintf(buf, sizeof(buf), SQUIDSBUFPH, SQUIDSBUFPRINT(request->effectiveRequestUri()));
+            str = buf;
             break;
 
         case Format::LFT_CLIENT_REQ_URLDOMAIN:
index 55ba00d047eff5027514a5b8daae964440fbc244..b531835656917909406ada00edbb424ef42eb856 100644 (file)
@@ -935,7 +935,9 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
         case LFT_CLIENT_REQ_URI:
             // original client URI
             if (al->request) {
-                out = urlCanonical(al->request);
+                const SBuf &s = al->request->effectiveRequestUri();
+                sb.append(s.rawContent(), s.length());
+                out = sb.termedBuf();
                 quote = 1;
             }
             break;
@@ -1010,7 +1012,9 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS
         case LFT_SERVER_REQ_URI:
             // adapted request URI sent to server/peer
             if (al->adapted_request) {
-                out = urlCanonical(al->adapted_request);
+                const SBuf &s = al->adapted_request->effectiveRequestUri();
+                sb.append(s.rawContent(), s.length());
+                out = sb.termedBuf();
                 quote = 1;
             }
             break;
index 87bacf1085796e82cd8a875ea7c97d248fffac59..95ef0d036a4a0cbfb01af65f045a376d27b2104d 100644 (file)
@@ -1831,7 +1831,7 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
 
             static int warnedCount = 0;
             if (warnedCount++ < 100) {
-                const char *url = entry ? entry->url() : urlCanonical(request);
+                const SBuf url(entry ? SBuf(entry->url()) : request->effectiveRequestUri());
                 debugs(11, DBG_IMPORTANT, "Warning: likely forwarding loop with " << url);
             }
         }
@@ -1901,10 +1901,9 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
 
         /* Add max-age only without no-cache */
         if (!cc->hasMaxAge() && !cc->hasNoCache()) {
-            const char *url =
-                entry ? entry->url() : urlCanonical(request);
-            cc->maxAge(getMaxAge(url));
-
+            // XXX: performance regression. c_str() reallocates
+            SBuf tmp(request->effectiveRequestUri());
+            cc->maxAge(getMaxAge(entry ? entry->url() : tmp.c_str()));
         }
 
         /* Enforce sibling relations */
@@ -2163,8 +2162,7 @@ HttpStateData::buildRequestPrefix(MemBuf * mb)
      * not the one we are sending. Needs checking.
      */
     const AnyP::ProtocolVersion httpver = Http::ProtocolVersion();
-    const bool canonical = (_peer && !_peer->options.originserver);
-    const SBuf url = canonical ? SBuf(urlCanonical(request)) : request->url.path();
+    const SBuf url(_peer && !_peer->options.originserver ? request->effectiveRequestUri() : request->url.path());
     mb->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\r\n",
                 SQUIDSBUFPRINT(request->method.image()),
                 SQUIDSBUFPRINT(url),
index f7fc4a1bee75778a994b44b378cfd725f6859e85..298b2109ef27da3429b2d494bb462d2357bc5775 100644 (file)
@@ -1318,8 +1318,6 @@ netdbExchangeStart(void *data)
     if (p->login)
         ex->r->url.userInfo(SBuf(p->login));
 
-    urlCanonical(ex->r);
-
     FwdState::fwdStart(Comm::ConnectionPointer(), ex->e, ex->r);
 
 #endif
index c325cafd93cd8acb8a18e0eb82ddb6f867200a4d..211aff957371ba5987138e5d28f3f6cebd4e37af 100644 (file)
@@ -961,16 +961,17 @@ ps_state::ps_state() : request (NULL),
     ; // no local defaults.
 }
 
-const char *
+const SBuf
 ps_state::url() const
 {
     if (entry)
-        return entry->url();
+        return SBuf(entry->url());
 
     if (request)
-        return urlCanonical(request);
+        return request->effectiveRequestUri();
 
-    return "[no URL]";
+    static const SBuf noUrl("[no URL]");
+    return noUrl;
 }
 
 ping_data::ping_data() :
index 6e222f89571243b023df745b7314e1970eca0034..2dcbff8b58e609dac06157c4ee4e14923367e67f 100644 (file)
@@ -285,19 +285,20 @@ refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age,
 static int
 refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
 {
-    const char *uri = NULL;
     time_t age = 0;
     time_t check_time = squid_curtime + delta;
     int staleness;
     stale_flags sf;
 
     // get the URL of this entry, if there is one
+    static const SBuf nilUri("<none>");
+    SBuf uri = nilUri;
     if (entry->mem_obj)
         uri = entry->mem_obj->storeId();
     else if (request)
-        uri = urlCanonical(request);
+        uri = request->effectiveRequestUri();
 
-    debugs(22, 3, "checking freshness of '" << (uri ? uri : "<none>") << "'");
+    debugs(22, 3, "checking freshness of URI: " << uri);
 
     // age is not necessarily the age now, but the age at the given check_time
     if (check_time > entry->timestamp)
@@ -312,7 +313,8 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
      *   2. the "." rule from the config file
      *   3. the default "." rule
      */
-    const RefreshPattern *R = uri ? refreshLimits(uri) : refreshUncompiledPattern(".");
+    // XXX: performance regression. c_str() reallocates
+    const RefreshPattern *R = (uri != nilUri) ? refreshLimits(uri.c_str()) : refreshUncompiledPattern(".");
     if (NULL == R)
         R = &DefaultRefresh;
 
index faac1a2c96d58680e23072f3aca3f2178b24caa4..c4d53fabbe423e2a7871f24ffa56887128535118 100644 (file)
@@ -731,7 +731,7 @@ Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
             if (request->flags.sslPeek && !isConnectRequest) {
                 if (X509 *srvX509 = serverBump->serverCert.get()) {
                     if (const char *name = Ssl::CommonHostName(srvX509)) {
-                        request->SetHost(name);
+                        request->url.host(name);
                         debugs(83, 3, "reset request host: " << name);
                     }
                 }
index 1350b25c2e349392eaed8f4105bae4a182417676..12aa644b2c180775effbd91e4e22f730f1d3dc10 100644 (file)
@@ -28,12 +28,14 @@ Ssl::ServerBump::ServerBump(HttpRequest *fakeRequest, StoreEntry *e, Ssl::BumpMo
     act.step1 = md;
     act.step2 = act.step3 = Ssl::bumpNone;
 
-    const char *uri = urlCanonical(request.getRaw());
     if (e) {
         entry = e;
         entry->lock("Ssl::ServerBump");
-    } else
-        entry = storeCreateEntry(uri, uri, request->flags, request->method);
+    } else {
+        // XXX: Performance regression. c_str() reallocates
+        SBuf uri(request->effectiveRequestUri());
+        entry = storeCreateEntry(uri.c_str(), uri.c_str(), request->flags, request->method);
+    }
     // We do not need to be a client because the error contents will be used
     // later, but an entry without any client will trim all its contents away.
     sc = storeClientListAdd(entry, this);
index 4d306e489732eb6625d624e75a4cb4d644fdb611..f4d97955bc7bb57dfd9f6cdaa589e9d4a59c74eb 100644 (file)
@@ -118,11 +118,11 @@ storeKeyPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& me
 {
     static cache_key digest[SQUID_MD5_DIGEST_LENGTH];
     unsigned char m = (unsigned char) method.id();
-    const char *url = request->storeId(); /* storeId returns the right storeID\canonical URL for the md5 calc */
+    const SBuf url = request->storeId(); /* returns the right storeID\URL for the MD5 calc */
     SquidMD5_CTX M;
     SquidMD5Init(&M);
     SquidMD5Update(&M, &m, sizeof(m));
-    SquidMD5Update(&M, (unsigned char *) url, strlen(url));
+    SquidMD5Update(&M, (unsigned char *) url.rawContent(), url.length());
 
     if (request->vary_headers) {
         SquidMD5Update(&M, (unsigned char *) request->vary_headers, strlen(request->vary_headers));
index 095c6cde8d4f1e9c6d5f0efe97fec882174fc957..4360c02bc0ec98a76c412139feec758ed26756e0 100644 (file)
@@ -39,13 +39,13 @@ storeSwapMetaBuild(StoreEntry * e)
 {
     tlv *TLV = NULL;        /* we'll return this */
     tlv **T = &TLV;
-    const char *url;
     const char *vary;
     assert(e->mem_obj != NULL);
     const int64_t objsize = e->mem_obj->expectedReplySize();
     assert(e->swap_status == SWAPOUT_WRITING);
 
     // e->mem_obj->request may be nil in this context
+    SBuf url;
     if (e->mem_obj->request)
         url = e->mem_obj->request->storeId();
     else
@@ -68,8 +68,9 @@ storeSwapMetaBuild(StoreEntry * e)
         return NULL;
     }
 
+    // XXX: do TLV without the c_str() termination. check readers first though
     T = StoreMeta::Add(T, t);
-    t = StoreMeta::Factory(STORE_META_URL, strlen(url) + 1, url);
+    t = StoreMeta::Factory(STORE_META_URL, url.length()+1, url.c_str());
 
     if (!t) {
         storeSwapTLVFree(TLV);
index 765769aaddb7e5625880940879c831c5cf4d0a22..55f19695fb15612006b9f462c6a26976d21d3dfd 100644 (file)
 #define STUB_API "HttpRequest.cc"
 #include "tests/STUB.h"
 
-HttpRequest::HttpRequest() : HttpMsg(hoRequest) STUB
-    HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) : HttpMsg(hoRequest) STUB
+// void httpRequestPack(void *obj, Packable *p);
+
+HttpRequest::HttpRequest() : HttpMsg(hoRequest) {STUB}
+    HttpRequest::HttpRequest(const HttpRequestMethod &, AnyP::ProtocolType, const char *) : HttpMsg(hoRequest) {STUB}
     HttpRequest::~HttpRequest() STUB
-    void HttpRequest::packFirstLineInto(Packable *, bool) const STUB
-    bool HttpRequest::sanityCheckStartLine(const char*buf, const size_t hdr_len, Http::StatusCode *error) STUB_RETVAL(false)
-    void HttpRequest::hdrCacheInit() STUB
     void HttpRequest::reset() STUB
-    bool HttpRequest::expectingBody(const HttpRequestMethod& unused, int64_t&) const STUB_RETVAL(false)
-    void HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) STUB
-    bool HttpRequest::parseFirstLine(const char *start, const char *end) STUB_RETVAL(false)
+    void HttpRequest::initHTTP(const HttpRequestMethod &, AnyP::ProtocolType, const char *) STUB
     HttpRequest * HttpRequest::clone() const STUB_RETVAL(NULL)
-    bool HttpRequest::inheritProperties(const HttpMsg *aMsg) STUB_RETVAL(false)
+    bool HttpRequest::maybeCacheable() STUB_RETVAL(false)
+    bool HttpRequest::conditional() const STUB_RETVAL(false)
+    bool HttpRequest::canHandle1xx() const STUB_RETVAL(false)
+#if USE_ADAPTATION
+    Adaptation::History::Pointer HttpRequest::adaptLogHistory() const STUB_RETVAL(Adaptation::History::Pointer())
+    Adaptation::History::Pointer HttpRequest::adaptHistory(bool) const STUB_RETVAL(Adaptation::History::Pointer())
+    void HttpRequest::adaptHistoryImport(const HttpRequest &) STUB
+#endif
+#if ICAP_CLIENT
+    Adaptation::Icap::History::Pointer HttpRequest::icapHistory() const STUB_RETVAL(Adaptation::Icap::History::Pointer())
+#endif
+    void HttpRequest::recordLookup(const Dns::LookupDetails &) STUB
+    void HttpRequest::detailError(err_type, int) STUB
+    void HttpRequest::clearError() STUB
+    void HttpRequest::clean() STUB
+    void HttpRequest::init() STUB
+    static const SBuf nilSBuf;
+    const SBuf &HttpRequest::effectiveRequestUri() const STUB_RETVAL(nilSBuf)
+    bool HttpRequest::multipartRangeRequest() const STUB_RETVAL(false)
+    bool HttpRequest::parseFirstLine(const char *, const char *) STUB_RETVAL(false)
+    bool HttpRequest::parseHeader(Http1::RequestParser &) STUB_RETVAL(false)
+    bool HttpRequest::expectingBody(const HttpRequestMethod &, int64_t &) const STUB_RETVAL(false)
+    bool HttpRequest::bodyNibbled() const STUB_RETVAL(false)
+    int HttpRequest::prefixLen() const STUB_RETVAL(0)
+    void HttpRequest::swapOut(StoreEntry *) STUB
+    void HttpRequest::pack(Packable *) STUB
+    void HttpRequest::httpRequestPack(void *, Packable *) STUB
+    HttpRequest * HttpRequest::CreateFromUrlAndMethod(char *, const HttpRequestMethod &) STUB_RETVAL(NULL)
+    HttpRequest * HttpRequest::CreateFromUrl(char *) STUB_RETVAL(NULL)
+    ConnStateData *HttpRequest::pinnedConnection() STUB_RETVAL(NULL)
+    const SBuf HttpRequest::storeId() STUB_RETVAL(SBuf("."))
+    void HttpRequest::ignoreRange(const char *) STUB
     int64_t HttpRequest::getRangeOffsetLimit() STUB_RETVAL(0)
-    const char *HttpRequest::storeId() STUB_RETVAL(".")
-
+    void HttpRequest::packFirstLineInto(Packable *, bool) const STUB
+    bool HttpRequest::sanityCheckStartLine(const char *, const size_t, Http::StatusCode *) STUB_RETVAL(false)
+    void HttpRequest::hdrCacheInit() STUB
+    bool HttpRequest::inheritProperties(const HttpMsg *) STUB_RETVAL(false)
index 9746b9f03b5e89cfee8eef16df34c12bbdc3ae8d..3aef1437301b94626a58b3406bab21bc3004c9d4 100644 (file)
@@ -1190,14 +1190,14 @@ switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::
     debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
     /* Create state structure. */
     TunnelStateData *tunnelState = NULL;
-    const char *url = urlCanonical(request);
+    const SBuf url(request->effectiveRequestUri());
 
     debugs(26, 3, request->method << " " << url << " " << request->http_ver);
     ++statCounter.server.all.requests;
     ++statCounter.server.other.requests;
 
     tunnelState = new TunnelStateData;
-    tunnelState->url = xstrdup(url);
+    tunnelState->url = xstrndup(url.rawContent(), url.length()+1);
     tunnelState->request = request;
     tunnelState->server.size_ptr = NULL; //Set later if ClientSocketContext is available
 
index 52399915264a0032aed94c15a453905bb836f8d2..3812e0c9b75847015d2df3f98abdee3fe31ec897 100644 (file)
@@ -449,10 +449,9 @@ urlParseFinish(const HttpRequestMethod& method,
         request = new HttpRequest(method, protocol, urlpath);
     else {
         request->initHTTP(method, protocol, urlpath);
-        safe_free(request->canonical);
     }
 
-    request->SetHost(host);
+    request->url.host(host);
     request->url.userInfo(login);
     request->url.port(port);
     return request;
@@ -464,7 +463,6 @@ urnParse(const HttpRequestMethod& method, char *urn, HttpRequest *request)
     debugs(50, 5, "urnParse: " << urn);
     if (request) {
         request->initHTTP(method, AnyP::PROTO_URN, urn + 4);
-        safe_free(request->canonical);
         return request;
     }
 
@@ -522,22 +520,7 @@ URL::absolute() const
     return absolute_;
 }
 
-const char *
-urlCanonical(HttpRequest * request)
-{
-    if (request->canonical)
-        return request->canonical;
-
-    SBuf url;
-    if (request->method.id() == Http::METHOD_CONNECT)
-        url = request->url.authority(true); // host:port
-    else
-        url = request->url.absolute();
-
-    return (request->canonical = xstrndup(url.rawContent(), url.length()+1));
-}
-
-/** \todo AYJ: Performance: This is an *almost* duplicate of urlCanonical. But elides the query-string.
+/** \todo AYJ: Performance: This is an *almost* duplicate of HttpRequest::effectiveRequestUri(). But elides the query-string.
  *        After copying it on in the first place! Would be less code to merge the two with a flag parameter.
  *        and never copy the query-string part in the first place
  */
@@ -546,15 +529,11 @@ urlCanonicalClean(const HttpRequest * request)
 {
     LOCAL_ARRAY(char, buf, MAX_URL);
 
-    snprintf(buf, sizeof(buf), "%s", urlCanonical(const_cast<HttpRequest *>(request)));
+    snprintf(buf, sizeof(buf), SQUIDSBUFPH, SQUIDSBUFPRINT(request->effectiveRequestUri()));
     buf[sizeof(buf)-1] = '\0';
 
     // URN, CONNECT method, and non-stripped URIs can go straight out
-    if (!(request->url.getScheme() == AnyP::PROTO_URN ||
-            !Config.onoff.strip_query_terms ||
-            request->method == Http::METHOD_CONNECT
-         )) {
-
+    if (Config.onoff.strip_query_terms && !(request->method == Http::METHOD_CONNECT || request->url.getScheme() == AnyP::PROTO_URN)) {
         // strip anything AFTER a question-mark
         // leaving the '?' in place
         if (auto t = strchr(buf, '?')) {