=== modified file 'src/client_side.cc' --- src/client_side.cc 2014-04-28 10:28:00 +0000 +++ src/client_side.cc 2014-04-28 10:28:59 +0000 @@ -2099,94 +2099,92 @@ const bool switchedToHttps = conn->switchedToHttps(); const bool tryHostHeader = vhost || switchedToHttps; if (tryHostHeader && (host = mime_get_header(req_hdr, "Host")) != NULL) { debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport); char thost[256]; if (vport > 0) { thost[0] = '\0'; char *t = NULL; if (host[strlen(host)] != ']' && (t = strrchr(host,':')) != NULL) { strncpy(thost, host, (t-host)); snprintf(thost+(t-host), sizeof(thost)-(t-host), ":%d", vport); host = thost; } else if (!t) { snprintf(thost, sizeof(thost), "%s:%d",host, vport); host = thost; } } // else nothing to alter port-wise. int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - const char *protocol = switchedToHttps ? - "https" : AnyP::UriScheme(conn->port->transport.protocol).c_str(); - snprintf(http->uri, url_sz, "%s://%s%s", protocol, host, url); + snprintf(http->uri, url_sz, "%s://%s%s", AnyP::UriScheme(conn->transportVersion.protocol).c_str(), host, url); debugs(33, 5, "ACCEL VHOST REWRITE: '" << http->uri << "'"); } else if (conn->port->defaultsite /* && !vhost */) { debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport); int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(conn->port->defaultsite); http->uri = (char *)xcalloc(url_sz, 1); char vportStr[32]; vportStr[0] = '\0'; if (vport > 0) { snprintf(vportStr, sizeof(vportStr),":%d",vport); } snprintf(http->uri, url_sz, "%s://%s%s%s", - AnyP::UriScheme(conn->port->transport.protocol).c_str(), conn->port->defaultsite, vportStr, url); + AnyP::UriScheme(conn->transportVersion.protocol).c_str(), conn->port->defaultsite, vportStr, url); debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: '" << http->uri <<"'"); } else if (vport > 0 /* && (!vhost || no Host:) */) { debugs(33, 5, "ACCEL VPORT REWRITE: http_port IP + vport=" << vport); /* Put the local socket IP address as the hostname, with whatever vport we found */ int url_sz = strlen(url) + 32 + Config.appendDomainLen; http->uri = (char *)xcalloc(url_sz, 1); http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN); snprintf(http->uri, url_sz, "%s://%s:%d%s", - AnyP::UriScheme(conn->port->transport.protocol).c_str(), + AnyP::UriScheme(conn->transportVersion.protocol).c_str(), ipbuf, vport, url); debugs(33, 5, "ACCEL VPORT REWRITE: '" << http->uri << "'"); } } static void prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr) { char *host; char ipbuf[MAX_IPSTRLEN]; if (*url != '/') return; /* already in good shape */ /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */ if ((host = mime_get_header(req_hdr, "Host")) != NULL) { int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "%s://%s%s", AnyP::UriScheme(conn->port->transport.protocol).c_str(), host, url); + snprintf(http->uri, url_sz, "%s://%s%s", AnyP::UriScheme(conn->transportVersion.protocol).c_str(), host, url); debugs(33, 5, "TRANSPARENT HOST REWRITE: '" << http->uri <<"'"); } else { /* Put the local socket IP address as the hostname. */ int url_sz = strlen(url) + 32 + Config.appendDomainLen; http->uri = (char *)xcalloc(url_sz, 1); http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN); snprintf(http->uri, url_sz, "%s://%s:%d%s", - AnyP::UriScheme(http->getConn()->port->transport.protocol).c_str(), + AnyP::UriScheme(http->getConn()->transportVersion.protocol).c_str(), ipbuf, http->getConn()->clientConnection->local.port(), url); debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'"); } } /** Parse an HTTP request * * \note Sets result->flags.parsed_ok to 0 if failed to parse the request, * to 1 if the request was correctly parsed. * \param[in] csd a ConnStateData. The caller must make sure it is not null * \param[in] hp an HttpParser * \param[out] mehtod_p will be set as a side-effect of the parsing. * Pointed-to value will be set to Http::METHOD_NONE in case of * parsing failure * \param[out] http_ver will be set as a side-effect of the parsing * \return NULL on incomplete requests, * a ClientSocketContext structure on success or failure. */ static ClientSocketContext * parseHttpRequest(ConnStateData *csd, HttpParser *hp, HttpRequestMethod * method_p, Http::ProtocolVersion *http_ver) @@ -2246,41 +2244,41 @@ /* Will the following be true with HTTP/0.9 requests? probably not .. */ /* So the rest of the code will need to deal with '0'-byte headers (ie, none, so don't try parsing em) */ assert(req_sz > 0); hp->hdr_end = req_sz - 1; hp->hdr_start = hp->req.end + 1; /* Enforce max_request_size */ if (req_sz >= Config.maxRequestHeaderSize) { debugs(33, 5, "parseHttpRequest: Too large request"); hp->request_parse_status = Http::scHeaderTooLarge; return parseHttpRequestAbort(csd, "error:request-too-large"); } /* Set method_p */ *method_p = HttpRequestMethod(&hp->buf[hp->req.m_start], &hp->buf[hp->req.m_end]+1); /* deny CONNECT via accelerated ports */ if (*method_p == Http::METHOD_CONNECT && csd->port && csd->port->flags.accelSurrogate) { - debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->transport.protocol << " Accelerator port " << csd->port->s.port()); + debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->transportVersion << " Accelerator port " << csd->port->s.port()); /* XXX need a way to say "this many character length string" */ debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->buf); hp->request_parse_status = Http::scMethodNotAllowed; return parseHttpRequestAbort(csd, "error:method-not-allowed"); } if (*method_p == Http::METHOD_NONE) { /* XXX need a way to say "this many character length string" */ debugs(33, DBG_IMPORTANT, "clientParseRequestMethod: Unsupported method in request '" << hp->buf << "'"); hp->request_parse_status = Http::scMethodNotAllowed; return parseHttpRequestAbort(csd, "error:unsupported-request-method"); } /* * Process headers after request line * TODO: Use httpRequestParse here. */ /* XXX this code should be modified to take a const char * later! */ req_hdr = (char *) hp->buf + hp->req.end + 1; @@ -3250,58 +3248,60 @@ * the open has already been completed on another * connection) */ debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired."); io.conn->close(); } static void clientLifetimeTimeout(const CommTimeoutCbParams &io) { ClientHttpRequest *http = static_cast(io.data); debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout"); debugs(33, DBG_IMPORTANT, "\t" << http->uri); http->al->http.timedout = true; if (Comm::IsConnOpen(io.conn)) io.conn->close(); } ConnStateData::ConnStateData(const MasterXaction::Pointer &xact) : AsyncJob("ConnStateData"), + transportVersion(), #if USE_OPENSSL sslBumpMode(Ssl::bumpEnd), switchedToHttps_(false), sslServerBump(NULL), #endif stoppedSending_(NULL), stoppedReceiving_(NULL) { pinning.host = NULL; pinning.port = -1; pinning.pinned = false; pinning.auth = false; pinning.zeroReply = false; pinning.peer = NULL; // store the details required for creating more MasterXaction objects as new requests come in clientConnection = xact->tcpClient; port = cbdataReference(xact->squidPort.get()); + transportVersion = port->transport; // default to the http(s)_port protocol= setting. may change later. log_addr = xact->tcpClient->remote; log_addr.applyMask(Config.Addrs.client_netmask); in.buf.reserveCapacity(CLIENT_REQ_BUF_SZ); if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF && (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) { #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) int i = IP_PMTUDISC_DONT; if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerror()); #else static bool reported = false; if (!reported) { debugs(33, DBG_IMPORTANT, "NOTICE: Path MTU discovery disabling is not supported on your platform."); reported = true; } #endif } @@ -3927,41 +3927,49 @@ return; // commSetConnTimeout() was called for this request before we switched. // Disable the client read handler until CachePeer selection is complete Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0); Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, clientNegotiateSSL, this, 0); switchedToHttps_ = true; } void ConnStateData::switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode) { assert(!switchedToHttps_); sslConnectHostOrIp = request->GetHost(); sslCommonName = request->GetHost(); // We are going to read new request flags.readMore = true; - debugs(33, 5, HERE << "converting " << clientConnection << " to SSL"); + debugs(33, 5, "converting " << clientConnection << " to SSL"); + + // keep version major.minor details the same. + // but we are now moving 'inside' the HTTPS traffic + transportVersion.protocol = AnyP::PROTO_HTTPS; + + // ssl-bumped native HTTPS connection already has intercept/tproxy flag set. + // otherwise we need to flag this as ssl-bumped CONNECT tunnel. + port->flags.tunnelSslBumping = !port->flags.isIntercepted(); // If sslServerBump is set, then we have decided to deny CONNECT // and now want to switch to SSL to send the error to the client // without even peeking at the origin server certificate. if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) { request->flags.sslPeek = true; sslServerBump = new Ssl::ServerBump(request); // will call httpsPeeked() with certificate and connection, eventually FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw()); return; } // otherwise, use sslConnectHostOrIp getSslContextStart(); } void ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection) { === modified file 'src/client_side.h' --- src/client_side.h 2014-04-22 13:10:49 +0000 +++ src/client_side.h 2014-04-28 10:28:59 +0000 @@ -191,40 +191,43 @@ void readSomeData(); bool areAllContextsForThisConnection() const; void freeAllContexts(); void notifyAllContexts(const int xerrno); ///< tell everybody about the err /// Traffic parsing bool clientParseRequests(); void readNextRequest(); ClientSocketContext::Pointer getCurrentContext() const; void addContextToQueue(ClientSocketContext * context); int getConcurrentRequestCount() const; bool isOpen() const; void checkHeaderLimits(); // HttpControlMsgSink API virtual void sendControlMsg(HttpControlMsg msg); // Client TCP connection details from comm layer. Comm::ConnectionPointer clientConnection; + /// the transport protocol currently being spoken on this connection + AnyP::ProtocolVersion transportVersion; + struct In { In(); ~In(); bool maybeMakeSpaceAvailable(); ChunkedCodingParser *bodyParser; ///< parses chunked request body SBuf buf; } in; /** number of body bytes we need to comm_read for the "current" request * * \retval 0 We do not need to read any [more] body bytes * \retval negative May need more but do not know how many; could be zero! * \retval positive Need to read exactly that many more body bytes */ int64_t mayNeedToReadMoreBody() const; #if USE_AUTH /** * Fetch the user details for connection based authentication