=== modified file 'src/FwdState.cc' --- src/FwdState.cc 2014-04-25 13:38:22 +0000 +++ src/FwdState.cc 2014-04-26 05:20:29 +0000 @@ -304,87 +304,90 @@ serverDestinations.clear(); debugs(17, 3, HERE << "FwdState destructor done"); } /** * This is the entry point for client-side to start forwarding * a transaction. It is a static method that may or may not * allocate a FwdState. */ void FwdState::Start(const Comm::ConnectionPointer &clientConn, StoreEntry *entry, HttpRequest *request, const AccessLogEntryPointer &al) { /** \note * client_addr == no_addr indicates this is an "internal" request * from peer_digest.c, asn.c, netdb.c, etc and should always * be allowed. yuck, I know. */ if ( Config.accessList.miss && !request->client_addr.isNoAddr() && - request->protocol != AnyP::PROTO_INTERNAL && request->protocol != AnyP::PROTO_CACHE_OBJECT) { + !request->flags.internal && request->url.getScheme() != AnyP::PROTO_CACHE_OBJECT) { /** * Check if this host is allowed to fetch MISSES from us (miss_access). * Intentionally replace the src_addr automatically selected by the checklist code * we do NOT want the indirect client address to be tested here. */ ACLFilledChecklist ch(Config.accessList.miss, request, NULL); ch.src_addr = request->client_addr; if (ch.fastCheck() == ACCESS_DENIED) { err_type page_id; page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName, 1); if (page_id == ERR_NONE) page_id = ERR_FORWARDING_DENIED; ErrorState *anErr = new ErrorState(page_id, Http::scForbidden, request); errorAppendEntry(entry, anErr); // frees anErr return; } } debugs(17, 3, HERE << "'" << entry->url() << "'"); /* * This seems like an odd place to bind mem_obj and request. * Might want to assert that request is NULL at this point */ entry->mem_obj->request = request; HTTPMSGLOCK(entry->mem_obj->request); #if URL_CHECKSUM_DEBUG entry->mem_obj->checkUrlChecksum(); #endif if (shutting_down) { /* more yuck */ ErrorState *anErr = new ErrorState(ERR_SHUTTING_DOWN, Http::scServiceUnavailable, request); errorAppendEntry(entry, anErr); // frees anErr return; } - switch (request->protocol) { - - case AnyP::PROTO_INTERNAL: + if (request->flags.internal) { + debugs(17, 2, "calling internalStart() due to request flag"); internalStart(clientConn, request, entry); return; + } + + switch (request->url.getScheme()) { case AnyP::PROTO_CACHE_OBJECT: + debugs(17, 2, "calling CacheManager due to request scheme " << request->url.getScheme()); CacheManager::GetInstance()->Start(clientConn, request, entry); return; case AnyP::PROTO_URN: urnStart(request, entry); return; default: FwdState::Pointer fwd = new FwdState(clientConn, entry, request, al); fwd->start(fwd); return; } /* NOTREACHED */ } void FwdState::fwdStart(const Comm::ConnectionPointer &clientConn, StoreEntry *entry, HttpRequest *request) { // Hides AccessLogEntry.h from code that does not supply ALE anyway. @@ -675,41 +678,41 @@ conn->close(); } retryOrBail(); return; } serverConn = conn; flags.connected_okay = true; debugs(17, 3, HERE << serverConnection() << ": '" << entry->url() << "'" ); comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this); if (serverConnection()->getPeer()) peerConnectSucceded(serverConnection()->getPeer()); #if USE_OPENSSL if (!request->flags.pinned) { if ((serverConnection()->getPeer() && serverConnection()->getPeer()->use_ssl) || - (!serverConnection()->getPeer() && request->protocol == AnyP::PROTO_HTTPS) || + (!serverConnection()->getPeer() && request->url.getScheme() == AnyP::PROTO_HTTPS) || request->flags.sslPeek) { HttpRequest::Pointer requestPointer = request; AsyncCall::Pointer callback = asyncCall(17,4, "FwdState::ConnectedToPeer", FwdStatePeerAnswerDialer(&FwdState::connectedToPeer, this)); Ssl::PeerConnector *connector = new Ssl::PeerConnector(requestPointer, serverConnection(), callback); AsyncJob::Start(connector); // will call our callback return; } } #endif dispatch(); } #if USE_OPENSSL void FwdState::connectedToPeer(Ssl::PeerConnectorAnswer &answer) @@ -929,64 +932,62 @@ #if USE_OPENSSL if (request->flags.sslPeek) { CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData, ConnStateData::httpsPeeked, serverConnection()); unregister(serverConn); // async call owns it now complete(); // destroys us return; } #endif if (serverConnection()->getPeer() != NULL) { ++ serverConnection()->getPeer()->stats.fetches; request->peer_login = serverConnection()->getPeer()->login; request->peer_domain = serverConnection()->getPeer()->domain; httpStart(this); } else { assert(!request->flags.sslPeek); request->peer_login = NULL; request->peer_domain = NULL; - switch (request->protocol) { + switch (request->url.getScheme()) { #if USE_OPENSSL case AnyP::PROTO_HTTPS: httpStart(this); break; #endif case AnyP::PROTO_HTTP: httpStart(this); break; case AnyP::PROTO_GOPHER: gopherStart(this); break; case AnyP::PROTO_FTP: ftpStart(this); break; case AnyP::PROTO_CACHE_OBJECT: - case AnyP::PROTO_INTERNAL: - case AnyP::PROTO_URN: fatal_dump("Should never get here"); break; case AnyP::PROTO_WHOIS: whoisStart(this); break; case AnyP::PROTO_WAIS: /* Not implemented */ default: debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'."); ErrorState *anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request); fail(anErr); // Set the dont_retry flag because this is not a transient (network) error. flags.dont_retry = true; if (Comm::IsConnOpen(serverConn)) { serverConn->close(); } break; === modified file 'src/HttpMsg.cc' --- src/HttpMsg.cc 2013-03-17 12:19:16 +0000 +++ src/HttpMsg.cc 2014-04-25 14:16:28 +0000 @@ -24,41 +24,41 @@ * 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. * */ #include "squid.h" #include "Debug.h" #include "HttpHeaderTools.h" #include "HttpMsg.h" #include "MemBuf.h" #include "mime_header.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), protocol(AnyP::PROTO_NONE), + cache_control(NULL), hdr_sz(0), content_length(0), pstate(psReadyToParseStartLine) {} HttpMsg::~HttpMsg() { assert(!body_pipe); } HttpMsgParseState &operator++ (HttpMsgParseState &aState) { int tmp = (int)aState; aState = (HttpMsgParseState)(++tmp); return aState; } /* find end of headers */ int httpMsgIsolateHeaders(const char **parse_start, int l, const char **blk_start, const char **blk_end) { /* === modified file 'src/HttpMsg.h' --- src/HttpMsg.h 2013-10-25 00:13:46 +0000 +++ src/HttpMsg.h 2014-04-26 04:31:51 +0000 @@ -50,55 +50,56 @@ virtual void reset() = 0; // will have body when http*Clean()s are gone void packInto(Packer * p, bool full_uri) const; ///< produce a message copy, except for a few connection-specific settings virtual HttpMsg *clone() const = 0; ///< \todo rename: not a true copy? /// [re]sets Content-Length header and cached value void setContentLength(int64_t clen); /** * \retval true the message sender asks to keep the connection open. * \retval false the message sender will close the connection. * * Factors other than the headers may result in connection closure. */ bool persistent() const; public: + /** + * The HTTP-Version label of this message. + */ Http::ProtocolVersion http_ver; HttpHeader header; HttpHdrCc *cache_control; /* Unsupported, writable, may disappear/change in the future * For replies, sums _stored_ status-line, headers, and . * Also used to report parsed header size if parse() is successful */ int hdr_sz; int64_t content_length; - AnyP::ProtocolType protocol; - HttpMsgParseState pstate; /* the current parsing state */ BodyPipe::Pointer body_pipe; // optional pipeline to receive message body // returns true and sets hdr_sz on success // returns false and sets *error to zero when needs more data // returns false and sets *error to a positive Http::StatusCode on error bool parse(MemBuf *buf, bool eol, Http::StatusCode *error); bool parseCharBuf(const char *buf, ssize_t end); int httpMsgParseStep(const char *buf, int len, int atEnd); virtual int httpMsgParseError(); virtual bool expectingBody(const HttpRequestMethod&, int64_t&) const = 0; void firstLineBuf(MemBuf&); virtual bool inheritProperties(const HttpMsg *aMsg) = 0; === modified file 'src/HttpReply.cc' --- src/HttpReply.cc 2013-10-31 19:13:17 +0000 +++ src/HttpReply.cc 2014-04-25 14:23:01 +0000 @@ -587,41 +587,40 @@ debugs(58, 4, HERE << "bodySizeMax=" << bodySizeMax); bodySizeMax = l->size; // may be -1 break; } } } // XXX: check that this is sufficient for eCAP cloning HttpReply * HttpReply::clone() const { HttpReply *rep = new HttpReply(); rep->sline = sline; // used in hdrCacheInit() call below rep->header.append(&header); rep->hdrCacheInit(); rep->hdr_sz = hdr_sz; rep->http_ver = http_ver; rep->pstate = pstate; rep->body_pipe = body_pipe; - rep->protocol = protocol; // keep_alive is handled in hdrCacheInit() return rep; } bool HttpReply::inheritProperties(const HttpMsg *aMsg) { const HttpReply *aRep = dynamic_cast(aMsg); if (!aRep) return false; keep_alive = aRep->keep_alive; return true; } void HttpReply::removeStaleWarnings() { String warning; if (header.getList(HDR_WARNING, &warning)) { const String newWarning = removeStaleWarningValues(warning); if (warning.size() && warning.size() == newWarning.size()) return; // some warnings are there and none changed === modified file 'src/HttpRequest.cc' --- src/HttpRequest.cc 2014-04-22 02:47:09 +0000 +++ src/HttpRequest.cc 2014-04-26 05:14:55 +0000 @@ -65,49 +65,49 @@ HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) : HttpMsg(hoRequest) { static unsigned int id = 1; debugs(93,7, HERE << "constructed, this=" << this << " id=" << ++id); init(); initHTTP(aMethod, aProtocol, aUrlpath); } HttpRequest::~HttpRequest() { clean(); debugs(93,7, HERE << "destructed, this=" << this); } void HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) { method = aMethod; - protocol = aProtocol; + url.makeScheme(aProtocol); urlpath = aUrlpath; } void HttpRequest::init() { method = Http::METHOD_NONE; - protocol = AnyP::PROTO_NONE; + url.clear(); urlpath = NULL; login[0] = '\0'; 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; imslen = 0; lastmod = -1; client_addr.setEmpty(); my_addr.setEmpty(); body_pipe = NULL; // hier dnsWait = -1; errType = ERR_NONE; @@ -133,40 +133,41 @@ #endif #if ICAP_CLIENT icapHistory_ = NULL; #endif rangeOffsetLimit = -2; //a value of -2 means not checked yet } void HttpRequest::clean() { // we used to assert that the pipe is NULL, but now the request only // points to a pipe that is owned and initiated by another object. body_pipe = NULL; #if USE_AUTH auth_user_request = NULL; #endif safe_free(canonical); safe_free(vary_headers); + url.clear(); urlpath.clean(); header.clean(); if (cache_control) { delete cache_control; cache_control = NULL; } if (range) { delete range; range = NULL; } myportname.clean(); notes = NULL; tag.clean(); #if USE_AUTH @@ -180,41 +181,41 @@ etag.clean(); #if USE_ADAPTATION adaptHistory_ = NULL; #endif #if ICAP_CLIENT icapHistory_ = NULL; #endif } void HttpRequest::reset() { clean(); init(); } HttpRequest * HttpRequest::clone() const { - HttpRequest *copy = new HttpRequest(method, protocol, urlpath.termedBuf()); + HttpRequest *copy = new HttpRequest(method, url.getScheme(), urlpath.termedBuf()); // TODO: move common cloning clone to Msg::copyTo() or copy ctor copy->header.append(&header); copy->hdrCacheInit(); copy->hdr_sz = hdr_sz; copy->http_ver = http_ver; copy->pstate = pstate; // TODO: should we assert a specific state here? copy->body_pipe = body_pipe; strncpy(copy->login, login, sizeof(login)); // MAX_LOGIN_SZ 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; // range handled in hdrCacheInit() copy->ims = ims; copy->imslen = imslen; copy->hier = hier; // Is it safe to copy? Should we? @@ -577,41 +578,41 @@ 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. */ bool HttpRequest::maybeCacheable() { // Intercepted request with Host: header which cannot be trusted. // Because it failed verification, or someone bypassed the security tests // we cannot cache the reponse for sharing between clients. // TODO: update cache to store for particular clients only (going to same Host: and destination IP) if (!flags.hostVerified && (flags.intercepted || flags.interceptTproxy)) return false; - switch (protocol) { + switch (url.getScheme()) { case AnyP::PROTO_HTTP: case AnyP::PROTO_HTTPS: 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 break; case AnyP::PROTO_GOPHER: if (!gopherCachable(this)) return false; break; case AnyP::PROTO_CACHE_OBJECT: return false; //case AnyP::PROTO_FTP: default: break; === modified file 'src/HttpRequest.h' --- src/HttpRequest.h 2014-03-15 02:50:12 +0000 +++ src/HttpRequest.h 2014-04-25 10:35:02 +0000 @@ -22,40 +22,41 @@ * 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. * */ #ifndef SQUID_HTTPREQUEST_H #define SQUID_HTTPREQUEST_H #include "base/CbcPointer.h" #include "Debug.h" #include "err_type.h" #include "HierarchyLogEntry.h" #include "HttpMsg.h" #include "HttpRequestMethod.h" #include "Notes.h" #include "RequestFlags.h" +#include "URL.h" #if USE_AUTH #include "auth/UserRequest.h" #endif #if USE_ADAPTATION #include "adaptation/History.h" #endif #if ICAP_CLIENT #include "adaptation/icap/History.h" #endif #if USE_SQUID_EUI #include "eui/Eui48.h" #include "eui/Eui64.h" #endif class ConnStateData; /* Http Request */ void httpRequestPack(void *obj, Packer *p); @@ -119,40 +120,43 @@ #if ICAP_CLIENT /// Returns possibly nil history, creating it if icap logging is enabled Adaptation::Icap::History::Pointer icapHistory() const; #endif void recordLookup(const DnsLookupDetails &detail); /// sets error detail if no earlier detail was available void detailError(err_type aType, int aDetail); /// clear error details, useful for retries/repeats void clearError(); protected: void clean(); void init(); public: HttpRequestMethod method; + // TODO expand to include all URI parts + URL url; ///< the request URI (scheme only) + char login[MAX_LOGIN_SZ]; private: char host[SQUIDHOSTNAMELEN]; int host_is_numeric; #if USE_ADAPTATION mutable Adaptation::History::Pointer adaptHistory_; ///< per-HTTP transaction info #endif #if ICAP_CLIENT mutable Adaptation::Icap::History::Pointer icapHistory_; ///< per-HTTP transaction info #endif public: Ip::Address host_addr; #if USE_AUTH Auth::UserRequest::Pointer auth_user_request; #endif unsigned short port; === modified file 'src/URL.h' --- src/URL.h 2014-02-07 13:45:20 +0000 +++ src/URL.h 2014-04-26 05:17:43 +0000 @@ -28,64 +28,72 @@ * */ #ifndef SQUID_SRC_URL_H #define SQUID_SRC_URL_H #include "anyp/UriScheme.h" #include "MemPool.h" /** \ingroup POD * * The URL class represents a Uniform Resource Location */ class URL { public: MEMPROXY_CLASS(URL); URL() : scheme_() {} URL(AnyP::UriScheme const &aScheme) : scheme_(aScheme) {} + + void clear() { + scheme_=AnyP::PROTO_NONE; + } + AnyP::UriScheme const & getScheme() const {return scheme_;} + /// convert the URL scheme to that given + void makeScheme(const AnyP::ProtocolType &p) {scheme_=p;} + private: /** \par * The scheme of this URL. This has the 'type code' smell about it. * In future we may want to make the methods that dispatch based on * the scheme virtual and have a class per protocol. \par * On the other hand, having Protocol as an explicit concept is useful, * see for instance the ACLProtocol acl type. One way to represent this * is to have one prototype URL with no host etc for each scheme, * another is to have an explicit scheme class, and then each URL class * could be a subclass of the scheme. Another way is one instance of * a AnyP::UriScheme class instance for each URL scheme we support, and one URL * class for each manner of treating the scheme : a Hierarchical URL, a * non-hierarchical URL etc. \par * Deferring the decision, its a type code for now. RBC 20060507. \par * In order to make taking any of these routes easy, scheme is private * and immutable, only settable at construction time, */ - AnyP::UriScheme const scheme_; + AnyP::UriScheme scheme_; }; MEMPROXY_CLASS_INLINE(URL); class HttpRequest; 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 *); char *urlMakeAbsolute(const HttpRequest *, const char *); char *urlRInternal(const char *host, unsigned short port, const char *dir, const char *name); char *urlInternal(const char *dir, const char *name); int matchDomainName(const char *host, const char *domain); int urlCheckRequest(const HttpRequest *); int urlDefaultPort(AnyP::ProtocolType p); === modified file 'src/acl/Protocol.cc' --- src/acl/Protocol.cc 2013-10-25 00:13:46 +0000 +++ src/acl/Protocol.cc 2014-04-25 15:26:01 +0000 @@ -25,32 +25,32 @@ * * 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) 2003, Robert Collins */ #include "squid.h" #include "acl/Checklist.h" #include "acl/Protocol.h" #include "acl/ProtocolData.h" #include "HttpRequest.h" /* explicit template instantiation required for some systems */ template class ACLStrategised; int -ACLProtocolStrategy::match (ACLData * &data, ACLFilledChecklist *checklist, ACLFlags &) +ACLProtocolStrategy::match(ACLData * &data, ACLFilledChecklist *checklist, ACLFlags &) { - return data->match (checklist->request->protocol); + return data->match(checklist->request->url.getScheme()); } ACLProtocolStrategy * ACLProtocolStrategy::Instance() { return &Instance_; } ACLProtocolStrategy ACLProtocolStrategy::Instance_; === modified file 'src/adaptation/ecap/Host.cc' --- src/adaptation/ecap/Host.cc 2014-02-08 13:36:42 +0000 +++ src/adaptation/ecap/Host.cc 2014-04-26 05:21:34 +0000 @@ -28,41 +28,40 @@ Adaptation::Ecap::Host::Host() { // assign our host-specific IDs to well-known names // this code can run only once libecap::headerTransferEncoding.assignHostId(HDR_TRANSFER_ENCODING); libecap::headerReferer.assignHostId(HDR_REFERER); libecap::headerContentLength.assignHostId(HDR_CONTENT_LENGTH); libecap::headerVia.assignHostId(HDR_VIA); // TODO: libecap::headerXClientIp.assignHostId(HDR_X_CLIENT_IP); // TODO: libecap::headerXServerIp.assignHostId(HDR_X_SERVER_IP); libecap::protocolHttp.assignHostId(AnyP::PROTO_HTTP); libecap::protocolHttps.assignHostId(AnyP::PROTO_HTTPS); libecap::protocolFtp.assignHostId(AnyP::PROTO_FTP); libecap::protocolGopher.assignHostId(AnyP::PROTO_GOPHER); libecap::protocolWais.assignHostId(AnyP::PROTO_WAIS); libecap::protocolUrn.assignHostId(AnyP::PROTO_URN); libecap::protocolWhois.assignHostId(AnyP::PROTO_WHOIS); - protocolInternal.assignHostId(AnyP::PROTO_INTERNAL); protocolCacheObj.assignHostId(AnyP::PROTO_CACHE_OBJECT); protocolIcp.assignHostId(AnyP::PROTO_ICP); #if USE_HTCP protocolHtcp.assignHostId(AnyP::PROTO_HTCP); #endif protocolIcy.assignHostId(AnyP::PROTO_ICY); protocolUnknown.assignHostId(AnyP::PROTO_UNKNOWN); // allows adapter to safely ignore this in adapter::Service::configure() metaBypassable.assignHostId(1); } std::string Adaptation::Ecap::Host::uri() const { return "ecap://squid-cache.org/ecap/hosts/squid"; } void Adaptation::Ecap::Host::describe(std::ostream &os) const === modified file 'src/adaptation/ecap/MessageRep.cc' --- src/adaptation/ecap/MessageRep.cc 2014-04-25 13:37:10 +0000 +++ src/adaptation/ecap/MessageRep.cc 2014-04-26 05:21:39 +0000 @@ -141,42 +141,40 @@ case AnyP::PROTO_HTTPS: return libecap::protocolHttps; case AnyP::PROTO_FTP: return libecap::protocolFtp; case AnyP::PROTO_GOPHER: return libecap::protocolGopher; case AnyP::PROTO_WAIS: return libecap::protocolWais; case AnyP::PROTO_WHOIS: return libecap::protocolWhois; case AnyP::PROTO_URN: return libecap::protocolUrn; case AnyP::PROTO_ICP: return protocolIcp; #if USE_HTCP case AnyP::PROTO_HTCP: return protocolHtcp; #endif case AnyP::PROTO_CACHE_OBJECT: return protocolCacheObj; - case AnyP::PROTO_INTERNAL: - return protocolInternal; case AnyP::PROTO_ICY: return protocolIcy; case AnyP::PROTO_COAP: case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps:// case AnyP::PROTO_UNKNOWN: return protocolUnknown; // until we remember the protocol image case AnyP::PROTO_NONE: return Name(); case AnyP::PROTO_MAX: break; // should not happen // no default to catch AnyP::PROTO_ additions } Must(false); // not reached return Name(); } void Adaptation::Ecap::FirstLineRep::protocol(const Name &p) { === modified file 'src/anyp/ProtocolType.h' --- src/anyp/ProtocolType.h 2014-02-21 10:46:19 +0000 +++ src/anyp/ProtocolType.h 2014-04-26 05:22:14 +0000 @@ -10,41 +10,40 @@ * List of all protocols known and supported. * This is a combined list. It is used as type-codes where needed and * the AnyP::ProtocolType_Str array of strings may be used for display */ typedef enum { PROTO_NONE = 0, PROTO_HTTP, PROTO_FTP, PROTO_HTTPS, PROTO_COAP, PROTO_COAPS, PROTO_GOPHER, PROTO_WAIS, PROTO_CACHE_OBJECT, PROTO_ICP, #if USE_HTCP PROTO_HTCP, #endif PROTO_URN, PROTO_WHOIS, - PROTO_INTERNAL, PROTO_ICY, PROTO_UNKNOWN, PROTO_MAX } ProtocolType; extern const char *ProtocolType_str[]; /** Display the registered Protocol Type (in upper case). * If the protocol is not a registered AnyP::ProtocolType nothing will be displayed. * The caller is responsible for any alternative text. */ inline std::ostream & operator <<(std::ostream &os, ProtocolType const &p) { if (PROTO_NONE <= p && p < PROTO_MAX) os << ProtocolType_str[p]; else os << static_cast(p); return os; } === modified file 'src/carp.cc' --- src/carp.cc 2014-04-25 10:47:59 +0000 +++ src/carp.cc 2014-04-25 12:16:28 +0000 @@ -174,43 +174,41 @@ CachePeer *tp; unsigned int user_hash = 0; unsigned int combined_hash; double score; double high_score = 0; if (n_carp_peers == 0) return NULL; /* calculate hash key */ debugs(39, 2, "carpSelectParent: Calculating hash for " << urlCanonical(request)); /* 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 if (tp->options.carp_key.scheme) { - // temporary, until bug 1961 URL handling is fixed. - const AnyP::UriScheme sch(request->protocol); - key.append(sch.c_str()); + key.append(request->url.getScheme().c_str()); if (key.length()) //if the scheme is not empty key.append("://"); } if (tp->options.carp_key.host) { key.append(request->GetHost()); } if (tp->options.carp_key.port) { static char portbuf[7]; snprintf(portbuf,7,":%d", request->port); key.append(portbuf); } if (tp->options.carp_key.path) { String::size_type pos; if ((pos=request->urlpath.find('?'))!=String::npos) key.append(SBuf(request->urlpath.substr(0,pos))); else key.append(SBuf(request->urlpath)); } if (tp->options.carp_key.params) { String::size_type pos; === modified file 'src/cf.data.pre' --- src/cf.data.pre 2014-04-22 16:01:23 +0000 +++ src/cf.data.pre 2014-04-25 13:50:51 +0000 @@ -712,41 +712,41 @@ capable of processing more than one query at a time. cache=n limit the result cache size, default is unbounded. grace=n Percentage remaining of TTL where a refresh of a cached entry should be initiated without needing to wait for a new reply. (default is for no grace period) protocol=2.5 Compatibility mode for Squid-2.5 external acl helpers ipv4 / ipv6 IP protocol used to communicate with this helper. The default is to auto-detect IPv6 and use it when available. FORMAT specifications %LOGIN Authenticated user login name %EXT_USER Username from previous external acl %EXT_LOG Log details from previous external acl %EXT_TAG Tag from previous external acl %IDENT Ident user name %SRC Client IP %SRCPORT Client source port %URI Requested URI %DST Requested host - %PROTO Requested protocol + %PROTO Requested URL scheme (protocol) %PORT Requested port %PATH Requested URL path %METHOD Request method %MYADDR Squid interface address %MYPORT Squid http_port number %PATH Requested URL-path (including query-string if any) %USER_CERT SSL User certificate in PEM format %USER_CERTCHAIN SSL User certificate chain in PEM format %USER_CERT_xx SSL User certificate subject attribute xx %USER_CA_xx SSL User certificate issuer attribute xx %>{Header} HTTP request header "Header" %>{Hdr:member} HTTP request header "Hdr" list member "member" %>{Hdr:;member} HTTP request header list member using ; as list separator. ; can be any non-alphanumeric character. %<{Header} HTTP reply header "Header" === modified file 'src/client_side.cc' --- src/client_side.cc 2014-04-22 12:51:21 +0000 +++ src/client_side.cc 2014-04-26 05:35:21 +0000 @@ -2703,54 +2703,57 @@ /** \par * If transparent or interception mode is working clone the transparent and interception flags * from the port settings to the request. */ if (http->clientConnection != NULL) { request->flags.intercepted = ((http->clientConnection->flags & COMM_INTERCEPTION) != 0); request->flags.interceptTproxy = ((http->clientConnection->flags & COMM_TRANSPARENT) != 0 ) ; if (request->flags.interceptTproxy) { if (Config.accessList.spoof_client_ip) { ACLFilledChecklist *checklist = clientAclChecklistCreate(Config.accessList.spoof_client_ip, http); request->flags.spoofClientIp = (checklist->fastCheck() == ACCESS_ALLOWED); delete checklist; } else request->flags.spoofClientIp = true; } else request->flags.spoofClientIp = false; } if (internalCheck(request->urlpath.termedBuf())) { - if (internalHostnameIs(request->GetHost()) && - request->port == getMyPort()) { + if (internalHostnameIs(request->GetHost()) && request->port == getMyPort()) { + debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->GetHost() << + ':' << request->port); http->flags.internal = true; } else if (Config.onoff.global_internal_static && internalStaticCheck(request->urlpath.termedBuf())) { + debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->GetHost() << + ':' << request->port << " (global_internal_static on)"); request->SetHost(internalHostname()); request->port = getMyPort(); http->flags.internal = true; - } + } else + debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->GetHost() << + ':' << request->port << " (not this proxy)"); } - if (http->flags.internal) { - request->protocol = AnyP::PROTO_HTTP; + if (http->flags.internal) request->login[0] = '\0'; - } request->flags.internal = http->flags.internal; setLogUri (http, urlCanonicalClean(request.getRaw())); request->client_addr = conn->clientConnection->remote; // XXX: remove reuest->client_addr member. #if FOLLOW_X_FORWARDED_FOR // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:) // not a details about teh TCP connection itself request->indirect_client_addr = conn->clientConnection->remote; #endif /* FOLLOW_X_FORWARDED_FOR */ request->my_addr = conn->clientConnection->local; request->myportname = conn->port->name; request->http_ver = http_ver; // Link this HttpRequest to ConnStateData relatively early so the following complex handling can use it // TODO: this effectively obsoletes a lot of conn->FOO copying. That needs cleaning up later. request->clientConnectionManager = conn; if (request->header.chunked()) { chunked = true; } else if (request->header.has(HDR_TRANSFER_ENCODING)) { === modified file 'src/client_side_reply.cc' --- src/client_side_reply.cc 2014-04-22 02:47:09 +0000 +++ src/client_side_reply.cc 2014-04-25 14:07:52 +0000 @@ -566,41 +566,41 @@ * both have a stale version of the object. */ r->flags.needValidation = true; if (e->lastmod < 0) { debugs(88, 3, "validate HIT object? NO. Missing Last-Modified header. Do MISS."); /* * Previous reply didn't have a Last-Modified header, * we cannot revalidate it. */ http->logType = LOG_TCP_MISS; processMiss(); } else if (r->flags.noCache) { debugs(88, 3, "validate HIT object? NO. Client sent CC:no-cache. Do CLIENT_REFRESH_MISS"); /* * This did not match a refresh pattern that overrides no-cache * we should honour the client no-cache header. */ http->logType = LOG_TCP_CLIENT_REFRESH_MISS; processMiss(); - } else if (r->protocol == AnyP::PROTO_HTTP) { + } else if (r->url.getScheme() == AnyP::PROTO_HTTP) { debugs(88, 3, "validate HIT object? YES."); /* * Object needs to be revalidated * XXX This could apply to FTP as well, if Last-Modified is known. */ processExpired(); } else { debugs(88, 3, "validate HIT object? NO. Client protocol non-HTTP. Do MISS."); /* * We don't know how to re-validate other protocols. Handle * them as if the object has expired. */ http->logType = LOG_TCP_MISS; processMiss(); } } else if (r->conditional()) { debugs(88, 5, "conditional HIT"); processConditional(result); } else { /* @@ -670,44 +670,40 @@ err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL, http->getConn()->clientConnection->remote, http->request); createStoreEntry(r->method, RequestFlags()); errorAppendEntry(http->storeEntry(), err); triggerInitialStoreRead(); return; } else { assert(http->out.offset == 0); createStoreEntry(r->method, r->flags); triggerInitialStoreRead(); if (http->redirect.status) { HttpReply *rep = new HttpReply; http->logType = LOG_TCP_REDIRECT; http->storeEntry()->releaseRequest(); rep->redirect(http->redirect.status, http->redirect.location); http->storeEntry()->replaceHttpReply(rep); http->storeEntry()->complete(); return; } - /** Check for internal requests. Update Protocol info if so. */ - if (http->flags.internal) - r->protocol = AnyP::PROTO_INTERNAL; - assert(r->clientConnectionManager == http->getConn()); /** Start forwarding to get the new object from network */ Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL; FwdState::Start(conn, http->storeEntry(), r, http->al); } } /** * client issued a request with an only-if-cached cache-control directive; * we did not find a cached object that can be returned without * contacting other servers; * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068] */ void clientReplyContext::processOnlyIfCachedMiss() { debugs(88, 4, http->request->method << ' ' << http->uri); http->al->http.code = Http::scGatewayTimeout; ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, Http::scGatewayTimeout, NULL, === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2014-04-22 02:47:09 +0000 +++ src/client_side_request.cc 2014-04-26 05:35:57 +0000 @@ -661,44 +661,44 @@ // XXX: match the scheme default port against the apparent destination // verify the destination DNS is one of the Host: headers IPs ipcache_nbgethostbyname(host, hostHeaderIpVerifyWrapper, this); } } else if (!Config.onoff.hostStrictVerify) { debugs(85, 3, HERE << "validate skipped."); http->doCallouts(); } else if (strlen(host) != strlen(http->request->GetHost())) { // Verify forward-proxy requested URL domain matches the Host: header debugs(85, 3, HERE << "FAIL on validate URL domain length " << http->request->GetHost() << " matches Host: " << host); hostHeaderVerifyFailed(host, http->request->GetHost()); } else if (matchDomainName(host, http->request->GetHost()) != 0) { // Verify forward-proxy requested URL domain matches the Host: header debugs(85, 3, HERE << "FAIL on validate URL domain " << http->request->GetHost() << " matches Host: " << host); hostHeaderVerifyFailed(host, http->request->GetHost()); } else if (portStr && port != http->request->port) { // Verify forward-proxy requested URL domain matches the Host: header debugs(85, 3, HERE << "FAIL on validate URL port " << http->request->port << " matches Host: port " << portStr); hostHeaderVerifyFailed("URL port", portStr); - } else if (!portStr && http->request->method != Http::METHOD_CONNECT && http->request->port != urlDefaultPort(http->request->protocol)) { + } else if (!portStr && http->request->method != Http::METHOD_CONNECT && http->request->port != urlDefaultPort(http->request->url.getScheme())) { // Verify forward-proxy requested URL domain matches the Host: header // Special case: we don't have a default-port to check for CONNECT. Assume URL is correct. - debugs(85, 3, HERE << "FAIL on validate URL port " << http->request->port << " matches Host: default port " << urlDefaultPort(http->request->protocol)); + debugs(85, 3, "FAIL on validate URL port " << http->request->port << " matches Host: default port " << urlDefaultPort(http->request->url.getScheme())); hostHeaderVerifyFailed("URL port", "default port"); } else { // Okay no problem. debugs(85, 3, HERE << "validate passed."); http->request->flags.hostVerified = true; http->doCallouts(); } safe_free(hostB); } /* This is the entry point for external users of the client_side routines */ void ClientRequestContext::clientAccessCheck() { #if FOLLOW_X_FORWARDED_FOR if (!http->request->flags.doneFollowXff() && Config.accessList.followXFF && http->request->header.has(HDR_X_FORWARDED_FOR)) { /* we always trust the direct client address for actual use */ @@ -966,47 +966,47 @@ * This is incorrect: authenticating requests can be sent via a hierarchy * (they can even be cached if the correct headers are set on the reply) */ if (request->flags.auth) return 0; if (method == Http::METHOD_TRACE) return 1; if (method != Http::METHOD_GET) return 0; /* scan hierarchy_stoplist */ for (p = Config.hierarchy_stoplist; p; p = p->next) if (strstr(url, p->key)) return 0; if (request->flags.loopDetected) return 0; - if (request->protocol == AnyP::PROTO_HTTP) + if (request->url.getScheme() == AnyP::PROTO_HTTP) return method.respMaybeCacheable(); - if (request->protocol == AnyP::PROTO_GOPHER) + if (request->url.getScheme() == AnyP::PROTO_GOPHER) return gopherCachable(request); - if (request->protocol == AnyP::PROTO_CACHE_OBJECT) + if (request->url.getScheme() == AnyP::PROTO_CACHE_OBJECT) return 0; return 1; } static void clientCheckPinning(ClientHttpRequest * http) { HttpRequest *request = http->request; HttpHeader *req_hdr = &request->header; ConnStateData *http_conn = http->getConn(); /* Internal requests such as those from ESI includes may be without * a client connection */ if (!http_conn) return; request->flags.connectionAuthDisabled = http_conn->port->connection_auth_disabled; if (!request->flags.connectionAuthDisabled) { === modified file 'src/errorpage.cc' --- src/errorpage.cc 2014-04-25 13:38:22 +0000 +++ src/errorpage.cc 2014-04-25 15:36:19 +0000 @@ -955,41 +955,41 @@ } else if (!building_deny_info_url) p = "[unknown method]"; break; case 'o': p = request ? request->extacl_message.termedBuf() : external_acl_message; if (!p && !building_deny_info_url) p = "[not available]"; break; case 'p': if (request) { mb.Printf("%d", (int) request->port); } else if (!building_deny_info_url) { p = "[unknown port]"; } break; case 'P': if (request) { - p = AnyP::ProtocolType_str[request->protocol]; + p = request->url.getScheme().c_str(); } else if (!building_deny_info_url) { p = "[unknown protocol]"; } break; case 'R': if (building_deny_info_url) { p = (request->urlpath.size() != 0 ? request->urlpath.termedBuf() : "/"); no_urlescape = 1; break; } if (NULL != request) { Packer pck; String urlpath_or_slash; if (request->urlpath.size() != 0) urlpath_or_slash = request->urlpath; else urlpath_or_slash = "/"; === modified file 'src/external_acl.cc' --- src/external_acl.cc 2014-04-22 02:47:09 +0000 +++ src/external_acl.cc 2014-04-25 13:53:28 +0000 @@ -1028,41 +1028,41 @@ #endif case _external_acl_format::EXT_ACL_MYADDR: str = request->my_addr.toStr(buf, sizeof(buf)); break; case _external_acl_format::EXT_ACL_MYPORT: snprintf(buf, sizeof(buf), "%d", request->my_addr.port()); str = buf; break; case _external_acl_format::EXT_ACL_URI: str = urlCanonical(request); break; case _external_acl_format::EXT_ACL_DST: str = request->GetHost(); break; case _external_acl_format::EXT_ACL_PROTO: - str = AnyP::ProtocolType_str[request->protocol]; + str = request->url.getScheme().c_str(); break; case _external_acl_format::EXT_ACL_PORT: snprintf(buf, sizeof(buf), "%d", request->port); str = buf; break; case _external_acl_format::EXT_ACL_PATH: str = request->urlpath.termedBuf(); break; case _external_acl_format::EXT_ACL_METHOD: { const SBuf &s = request->method.image(); sb.append(s.rawContent(), s.length()); } str = sb.termedBuf(); break; case _external_acl_format::EXT_ACL_HEADER_REQUEST: === modified file 'src/ftp.cc' --- src/ftp.cc 2014-04-04 16:36:47 +0000 +++ src/ftp.cc 2014-04-25 13:55:20 +0000 @@ -3715,41 +3715,41 @@ return newrep; } /** \ingroup ServerProtocolFTPAPI \todo Should be a URL class API call. * * Construct an URI with leading / in PATH portion for use by CWD command * possibly others. FTP encodes absolute paths as beginning with '/' * after the initial URI path delimiter, which happens to be / itself. * This makes FTP absolute URI appear as: ftp:host:port//root/path * To encompass older software which compacts multiple // to / in transit * We use standard URI-encoding on the second / making it * ftp:host:port/%2froot/path AKA 'the FTP %2f hack'. */ const char * ftpUrlWith2f(HttpRequest * request) { String newbuf = "%2f"; - if (request->protocol != AnyP::PROTO_FTP) + if (request->url.getScheme() != AnyP::PROTO_FTP) return NULL; if ( request->urlpath[0]=='/' ) { newbuf.append(request->urlpath); request->urlpath.absorb(newbuf); safe_free(request->canonical); } else if ( !strncmp(request->urlpath.termedBuf(), "%2f", 3) ) { newbuf.append(request->urlpath.substr(1,request->urlpath.size())); request->urlpath.absorb(newbuf); safe_free(request->canonical); } return urlCanonical(request); } void FtpStateData::printfReplyBody(const char *fmt, ...) { va_list args; va_start (args, fmt); === modified file 'src/http.cc' --- src/http.cc 2014-04-22 02:47:09 +0000 +++ src/http.cc 2014-04-25 14:15:43 +0000 @@ -1790,41 +1790,41 @@ /** If set to OFF - append 'unknown'. */ strListAdd(&strFwd, "unknown", ','); } else if (strcmp(opt_forwarded_for, "transparent") == 0) { /** If set to TRANSPARENT - pass through unchanged. */ } else if (strcmp(opt_forwarded_for, "truncate") == 0) { /** If set to TRUNCATE - drop existing list and replace with client IP or 'unknown'. */ if ( request->client_addr.isNoAddr() ) strFwd = "unknown"; else strFwd = request->client_addr.toStr(ntoabuf, MAX_IPSTRLEN); } if (strFwd.size() > 0) hdr_out->putStr(HDR_X_FORWARDED_FOR, strFwd.termedBuf()); } /** If set to DELETE - do not copy through. */ /* append Host if not there already */ if (!hdr_out->has(HDR_HOST)) { if (request->peer_domain) { hdr_out->putStr(HDR_HOST, request->peer_domain); - } else if (request->port == urlDefaultPort(request->protocol)) { + } else if (request->port == urlDefaultPort(request->url.getScheme())) { /* use port# only if not default */ hdr_out->putStr(HDR_HOST, request->GetHost()); } else { httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d", request->GetHost(), (int) request->port); } } /* append Authorization if known in URL, not in header and going direct */ if (!hdr_out->has(HDR_AUTHORIZATION)) { if (!request->flags.proxying && request->login[0] != '\0') { httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", old_base64_encode(request->login)); } } /* Fixup (Proxy-)Authorization special cases. Plain relaying dealt with above */ httpFixupAuthentication(request, hdr_in, hdr_out, flags); @@ -1848,41 +1848,41 @@ cc->maxAge(getMaxAge(url)); } /* Enforce sibling relations */ if (flags.only_if_cached) cc->onlyIfCached(true); hdr_out->putCc(cc); delete cc; } /* maybe append Connection: keep-alive */ if (flags.keepalive) { hdr_out->putStr(HDR_CONNECTION, "keep-alive"); } /* append Front-End-Https */ if (flags.front_end_https) { - if (flags.front_end_https == 1 || request->protocol == AnyP::PROTO_HTTPS) + if (flags.front_end_https == 1 || request->url.getScheme() == AnyP::PROTO_HTTPS) hdr_out->putStr(HDR_FRONT_END_HTTPS, "On"); } if (flags.chunked_request) { // Do not just copy the original value so that if the client-side // starts decode other encodings, this code may remain valid. hdr_out->putStr(HDR_TRANSFER_ENCODING, "chunked"); } /* Now mangle the headers. */ if (Config2.onoff.mangle_request_headers) httpHdrMangleList(hdr_out, request, ROR_REQUEST); if (Config.request_header_add && !Config.request_header_add->empty()) httpHdrAdd(hdr_out, request, al, *Config.request_header_add); strConnection.clean(); } /** @@ -1941,41 +1941,41 @@ hdr_out->addEntry(e->clone()); } } break; case HDR_HOST: /** \par Host: * Normally Squid rewrites the Host: header. * However, there is one case when we don't: If the URL * went through our redirector and the admin configured * 'redir_rewrites_host' to be off. */ if (request->peer_domain) hdr_out->putStr(HDR_HOST, request->peer_domain); else if (request->flags.redirected && !Config.onoff.redir_rewrites_host) hdr_out->addEntry(e->clone()); else { /* use port# only if not default */ - if (request->port == urlDefaultPort(request->protocol)) { + if (request->port == urlDefaultPort(request->url.getScheme())) { hdr_out->putStr(HDR_HOST, request->GetHost()); } else { httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d", request->GetHost(), (int) request->port); } } break; case HDR_IF_MODIFIED_SINCE: /** \par If-Modified-Since: * append unless we added our own, * but only if cache_miss_revalidate is enabled, or * the request is not cacheable, or * the request contains authentication credentials. * \note at most one client's If-Modified-Since header can pass through */ // XXX: need to check and cleanup the auth case so cacheable auth requests get cached. if (hdr_out->has(HDR_IF_MODIFIED_SINCE)) === modified file 'src/internal.cc' --- src/internal.cc 2013-10-25 00:13:46 +0000 +++ src/internal.cc 2014-04-26 04:02:35 +0000 @@ -56,40 +56,41 @@ ErrorState *err; const char *upath = request->urlpath.termedBuf(); debugs(76, 3, HERE << clientConn << " requesting '" << upath << "'"); if (0 == strcmp(upath, "/squid-internal-dynamic/netdb")) { netdbBinaryExchange(entry); } else if (0 == strcmp(upath, "/squid-internal-periodic/store_digest")) { #if USE_CACHE_DIGESTS const char *msgbuf = "This cache is currently building its digest.\n"; #else const char *msgbuf = "This cache does not support Cache Digests.\n"; #endif HttpReply *reply = new HttpReply; reply->setHeaders(Http::scNotFound, "Not Found", "text/plain", strlen(msgbuf), squid_curtime, -2); entry->replaceHttpReply(reply); entry->append(msgbuf, strlen(msgbuf)); entry->complete(); } else if (0 == strncmp(upath, "/squid-internal-mgr/", 20)) { + debugs(17, 2, "calling CacheManager due to URL-path /squid-internal-mgr/"); CacheManager::GetInstance()->Start(clientConn, request, entry); } else { debugObj(76, 1, "internalStart: unknown request:\n", request, (ObjPackMethod) & httpRequestPack); err = new ErrorState(ERR_INVALID_REQ, Http::scNotFound, request); errorAppendEntry(entry, err); } } int internalCheck(const char *urlpath) { return (0 == strncmp(urlpath, "/squid-internal-", 16)); } int internalStaticCheck(const char *urlpath) { return (0 == strncmp(urlpath, "/squid-internal-static", 22)); } === modified file 'src/peer_select.cc' --- src/peer_select.cc 2014-04-22 02:47:09 +0000 +++ src/peer_select.cc 2014-04-25 15:28:46 +0000 @@ -674,41 +674,41 @@ } if (p && code != HIER_NONE) { debugs(44, 3, "peerSelect: " << hier_code_str[code] << "/" << p->host); peerAddFwdServer(&ps->servers, p, code); } } /* * peerGetSomeDirect * * Simply adds a 'direct' entry to the FwdServers list if this * request can be forwarded directly to the origin server */ static void peerGetSomeDirect(ps_state * ps) { if (ps->direct == DIRECT_NO) return; /* WAIS is not implemented natively */ - if (ps->request->protocol == AnyP::PROTO_WAIS) + if (ps->request->url.getScheme() == AnyP::PROTO_WAIS) return; peerAddFwdServer(&ps->servers, NULL, HIER_DIRECT); } static void peerGetSomeParent(ps_state * ps) { CachePeer *p; HttpRequest *request = ps->request; hier_code code = HIER_NONE; debugs(44, 3, request->method << ' ' << request->GetHost()); if (ps->direct == DIRECT_YES) return; if ((p = peerSourceHashSelectParent(request))) { code = SOURCEHASH_PARENT; #if USE_AUTH } else if ((p = peerUserHashSelectParent(request))) { === modified file 'src/tests/testHttpRequest.cc' --- src/tests/testHttpRequest.cc 2013-10-25 00:13:46 +0000 +++ src/tests/testHttpRequest.cc 2014-04-25 23:37:04 +0000 @@ -26,138 +26,138 @@ Mem::Init(); httpHeaderInitModule(); } /* * Test creating an HttpRequest object from a Url and method */ void testHttpRequest::testCreateFromUrlAndMethod() { /* vanilla url */ unsigned short expected_port; char * url = xstrdup("http://foo:90/bar"); HttpRequest *aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET); expected_port = 90; HttpRequest *nullRequest = NULL; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("http://foo:90/bar"), String(url)); xfree(url); /* vanilla url, different method */ url = xstrdup("http://foo/bar"); aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_PUT); expected_port = 80; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_PUT); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("http://foo/bar"), String(url)); xfree(url); /* a connect url with non-CONNECT data */ url = xstrdup(":foo/bar"); aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_CONNECT); xfree(url); CPPUNIT_ASSERT_EQUAL(nullRequest, aRequest); /* a CONNECT url with CONNECT data */ url = xstrdup("foo:45"); aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_CONNECT); expected_port = 45; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_CONNECT); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String(""), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_NONE, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_NONE, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("foo:45"), String(url)); xfree(url); } /* * Test creating an HttpRequest object from a Url alone. */ void testHttpRequest::testCreateFromUrl() { /* vanilla url */ unsigned short expected_port; char * url = xstrdup("http://foo:90/bar"); HttpRequest *aRequest = HttpRequest::CreateFromUrl(url); expected_port = 90; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("http://foo:90/bar"), String(url)); xfree(url); } /* * Test BUG: URL '2000:800:45' opens host 2000 port 800 !! */ void testHttpRequest::testIPv6HostColonBug() { unsigned short expected_port; char * url = NULL; HttpRequest *aRequest = NULL; /* valid IPv6 address without port */ url = xstrdup("http://[2000:800::45]/foo"); aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET); expected_port = 80; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String("/foo"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("http://[2000:800::45]/foo"), String(url)); xfree(url); /* valid IPv6 address with port */ url = xstrdup("http://[2000:800::45]:90/foo"); aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET); expected_port = 90; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String("/foo"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("http://[2000:800::45]:90/foo"), String(url)); xfree(url); /* IPv6 address as invalid (bug trigger) */ url = xstrdup("http://2000:800::45/foo"); aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET); expected_port = 80; CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port); CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->GetHost())); CPPUNIT_ASSERT_EQUAL(String("/foo"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast(aRequest->url.getScheme())); CPPUNIT_ASSERT_EQUAL(String("http://2000:800::45/foo"), String(url)); xfree(url); } void testHttpRequest::testSanityCheckStartLine() { MemBuf input; PrivateHttpRequest engine; Http::StatusCode error = Http::scNone; size_t hdr_len; input.init(); // a valid request line input.append("GET / HTTP/1.1\n\n", 16); hdr_len = headersEnd(input.content(), input.contentSize()); CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) ); CPPUNIT_ASSERT_EQUAL(error, Http::scNone); input.reset(); error = Http::scNone; === modified file 'src/url.cc' --- src/url.cc 2014-04-23 15:36:13 +0000 +++ src/url.cc 2014-04-26 05:21:10 +0000 @@ -129,75 +129,70 @@ return AnyP::PROTO_COAP; if (strncasecmp(b, "coaps", len) == 0) return AnyP::PROTO_COAPS; if (strncasecmp(b, "gopher", len) == 0) return AnyP::PROTO_GOPHER; if (strncasecmp(b, "wais", len) == 0) return AnyP::PROTO_WAIS; if (strncasecmp(b, "cache_object", len) == 0) return AnyP::PROTO_CACHE_OBJECT; if (strncasecmp(b, "urn", len) == 0) return AnyP::PROTO_URN; if (strncasecmp(b, "whois", len) == 0) return AnyP::PROTO_WHOIS; - if (strncasecmp(b, "internal", len) == 0) - return AnyP::PROTO_INTERNAL; - return AnyP::PROTO_NONE; } int urlDefaultPort(AnyP::ProtocolType p) { switch (p) { case AnyP::PROTO_HTTP: return 80; case AnyP::PROTO_HTTPS: return 443; case AnyP::PROTO_FTP: return 21; case AnyP::PROTO_COAP: case AnyP::PROTO_COAPS: // coaps:// default is TBA as of draft-ietf-core-coap-08. // Assuming IANA policy of allocating same port for base and TLS protocol versions will occur. return 5683; case AnyP::PROTO_GOPHER: return 70; case AnyP::PROTO_WAIS: return 210; case AnyP::PROTO_CACHE_OBJECT: - - case AnyP::PROTO_INTERNAL: return CACHE_HTTP_PORT; case AnyP::PROTO_WHOIS: return 43; default: return 0; } } /* * Parse a URI/URL. * * If the 'request' arg is non-NULL, put parsed values there instead * of allocating a new HttpRequest. * * This abuses HttpRequest as a way of representing the parsed url * and its components. * method is used to switch parsers and to init the HttpRequest. * If method is Http::METHOD_CONNECT, then rather than a URL a hostname:port is @@ -486,115 +481,113 @@ { debugs(50, 5, "urnParse: " << urn); if (request) { request->initHTTP(method, AnyP::PROTO_URN, urn + 4); safe_free(request->canonical); return request; } return new HttpRequest(method, AnyP::PROTO_URN, urn + 4); } const char * urlCanonical(HttpRequest * request) { LOCAL_ARRAY(char, portbuf, 32); LOCAL_ARRAY(char, urlbuf, MAX_URL); if (request->canonical) return request->canonical; - if (request->protocol == AnyP::PROTO_URN) { + if (request->url.getScheme() == AnyP::PROTO_URN) { snprintf(urlbuf, MAX_URL, "urn:" SQUIDSTRINGPH, SQUIDSTRINGPRINT(request->urlpath)); } else { switch (request->method.id()) { case Http::METHOD_CONNECT: snprintf(urlbuf, MAX_URL, "%s:%d", request->GetHost(), request->port); break; default: { portbuf[0] = '\0'; - if (request->port != urlDefaultPort(request->protocol)) + if (request->port != urlDefaultPort(request->url.getScheme())) snprintf(portbuf, 32, ":%d", request->port); - const AnyP::UriScheme sch = request->protocol; // temporary, until bug 1961 URL handling is fixed. snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s" SQUIDSTRINGPH, - sch.c_str(), + request->url.getScheme().c_str(), request->login, *request->login ? "@" : null_string, request->GetHost(), portbuf, SQUIDSTRINGPRINT(request->urlpath)); } } } return (request->canonical = xstrdup(urlbuf)); } /** \todo AYJ: Performance: This is an *almost* duplicate of urlCanonical. 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 */ char * urlCanonicalClean(const HttpRequest * request) { LOCAL_ARRAY(char, buf, MAX_URL); LOCAL_ARRAY(char, portbuf, 32); LOCAL_ARRAY(char, loginbuf, MAX_LOGIN_SZ + 1); char *t; - if (request->protocol == AnyP::PROTO_URN) { + if (request->url.getScheme() == AnyP::PROTO_URN) { snprintf(buf, MAX_URL, "urn:" SQUIDSTRINGPH, SQUIDSTRINGPRINT(request->urlpath)); } else { switch (request->method.id()) { case Http::METHOD_CONNECT: snprintf(buf, MAX_URL, "%s:%d", request->GetHost(), request->port); break; default: { portbuf[0] = '\0'; - if (request->port != urlDefaultPort(request->protocol)) + if (request->port != urlDefaultPort(request->url.getScheme())) snprintf(portbuf, 32, ":%d", request->port); loginbuf[0] = '\0'; if ((int) strlen(request->login) > 0) { strcpy(loginbuf, request->login); if ((t = strchr(loginbuf, ':'))) *t = '\0'; strcat(loginbuf, "@"); } - const AnyP::UriScheme sch = request->protocol; // temporary, until bug 1961 URL handling is fixed. snprintf(buf, MAX_URL, "%s://%s%s%s" SQUIDSTRINGPH, - sch.c_str(), + request->url.getScheme().c_str(), loginbuf, request->GetHost(), portbuf, SQUIDSTRINGPRINT(request->urlpath)); // strip arguments AFTER a question-mark if (Config.onoff.strip_query_terms) if ((t = strchr(buf, '?'))) *(++t) = '\0'; } } } if (stringHasCntl(buf)) xstrncpy(buf, rfc1738_escape_unescaped(buf), MAX_URL); return buf; } /** @@ -650,60 +643,59 @@ * * It is assumed that you have already ensured that the URL is relative. * * If NULL is returned it is an indication that the method in use in the * request does not distinguish between relative and absolute and you should * use the url unchanged. * * If non-NULL is returned, it is up to the caller to free the resulting * memory using safe_free(). */ char * urlMakeAbsolute(const HttpRequest * req, const char *relUrl) { if (req->method.id() == Http::METHOD_CONNECT) { return (NULL); } char *urlbuf = (char *)xmalloc(MAX_URL * sizeof(char)); - if (req->protocol == AnyP::PROTO_URN) { + if (req->url.getScheme() == AnyP::PROTO_URN) { snprintf(urlbuf, MAX_URL, "urn:" SQUIDSTRINGPH, SQUIDSTRINGPRINT(req->urlpath)); return (urlbuf); } size_t urllen; - const AnyP::UriScheme sch = req->protocol; // temporary, until bug 1961 URL handling is fixed. - if (req->port != urlDefaultPort(req->protocol)) { + if (req->port != urlDefaultPort(req->url.getScheme())) { urllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s:%d", - sch.c_str(), + req->url.getScheme().c_str(), req->login, *req->login ? "@" : null_string, req->GetHost(), req->port ); } else { urllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s", - sch.c_str(), + req->url.getScheme().c_str(), req->login, *req->login ? "@" : null_string, req->GetHost() ); } if (relUrl[0] == '/') { strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); } else { const char *path = req->urlpath.termedBuf(); const char *last_slash = strrchr(path, '/'); if (last_slash == NULL) { urlbuf[urllen] = '/'; ++urllen; strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); } else { ++last_slash; size_t pathlen = last_slash - path; if (pathlen > MAX_URL - urllen - 1) { @@ -827,41 +819,41 @@ * they are methods we recieve on our HTTP port, * and if we had a FTP listener would not be relevant * there. * * So, we should delegate them to HTTP. The problem is that we * do not have a default protocol from the client side of HTTP. */ if (r->method == Http::METHOD_CONNECT) return 1; // we support OPTIONS and TRACE directed at us (with a 501 reply, for now) // we also support forwarding OPTIONS and TRACE, except for the *-URI ones if (r->method == Http::METHOD_OPTIONS || r->method == Http::METHOD_TRACE) return (r->header.getInt64(HDR_MAX_FORWARDS) == 0 || r->urlpath != "*"); if (r->method == Http::METHOD_PURGE) return 1; /* does method match the protocol? */ - switch (r->protocol) { + switch (r->url.getScheme()) { case AnyP::PROTO_URN: case AnyP::PROTO_HTTP: case AnyP::PROTO_CACHE_OBJECT: rc = 1; break; case AnyP::PROTO_FTP: if (r->method == Http::METHOD_PUT) rc = 1; case AnyP::PROTO_GOPHER: case AnyP::PROTO_WAIS: case AnyP::PROTO_WHOIS: if (r->method == Http::METHOD_GET)