=== modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2012-06-19 16:08:52 +0000 +++ src/cache_cf.cc 2012-07-16 14:52:13 +0000 @@ -38,40 +38,41 @@ #include "acl/Gadgets.h" #include "acl/MethodData.h" #if USE_ADAPTATION #include "adaptation/Config.h" #endif #if ICAP_CLIENT #include "adaptation/icap/Config.h" #endif #if USE_ECAP #include "adaptation/ecap/Config.h" #endif #include "anyp/PortCfg.h" #if USE_SSL #include "ssl/support.h" #include "ssl/Config.h" #endif #if USE_AUTH #include "auth/Config.h" #include "auth/Scheme.h" #endif +#include "base/RunnersRegistry.h" #include "ConfigParser.h" #include "CpuAffinityMap.h" #include "DiskIO/DiskIOModule.h" #include "eui/Config.h" #if USE_SQUID_ESI #include "esi/Parser.h" #endif #include "format/Format.h" #include "HttpRequestMethod.h" #include "ident/Config.h" #include "ip/Intercept.h" #include "ip/QosConfig.h" #include "ip/tools.h" #include "log/Config.h" #include "MemBuf.h" #include "mgr/Registration.h" #include "Parsing.h" #include "rfc1738.h" #if SQUID_SNMP #include "snmp.h" @@ -3791,48 +3792,48 @@ return; } char *token = strtok(NULL, w_space); if (!token) { self_destruct(); return; } AnyP::PortCfg *s = new AnyP::PortCfg(protocol); parsePortSpecification(s, token); /* parse options ... */ while ((token = strtok(NULL, w_space))) { parse_port_option(s, token); } #if USE_SSL if (strcasecmp(protocol, "https") == 0) { - /* ssl-bump on https_port configuration requires either tproxy or intercepted, and vice versa */ + /* ssl-bump on https_port configuration requires either tproxy or intercept, and vice versa */ const bool hijacked = s->spoof_client_ip || s->intercepted; if (s->sslBump && !hijacked) { - debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercepted which is missing."); + debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing."); self_destruct(); } if (hijacked && !s->sslBump) { - debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercepted on https_port requires ssl-bump which is missing."); + debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing."); self_destruct(); } } #endif if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.IsAnyAddr()) { // clone the port options from *s to *(s->next) s->next = cbdataReference(s->clone()); s->next->s.SetIPv4(); debugs(3, 3, protocol << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s); } while (*head) head = &(*head)->next; *head = cbdataReference(s); } static void dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfg * s) @@ -4520,70 +4521,137 @@ storeAppendPrintf(entry, "%s ", Ssl::certSignAlgorithm(cs->alg)); if (cs->aclList) dump_acl_list(entry, cs->aclList); storeAppendPrintf(entry, "\n"); } } static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign) { while(*cert_sign) { sslproxy_cert_sign *cs = *cert_sign; *cert_sign = cs->next; if (cs->aclList) aclDestroyAclList(&cs->aclList); safe_free(cs); } } +class sslBumpCfgRr: public ::RegisteredRunner +{ +public: + static Ssl::BumpMode lastDeprecatedRule; + /* RegisteredRunner API */ + virtual void run(const RunnerRegistry &); +}; + +Ssl::BumpMode sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd; + +RunnerRegistrationEntry(rrFinalizeConfig, sslBumpCfgRr); + +void sslBumpCfgRr::run(const RunnerRegistry &r) +{ + if (lastDeprecatedRule != Ssl::bumpEnd) { + assert( lastDeprecatedRule == Ssl::bumpClientFirst || lastDeprecatedRule == Ssl::bumpNone); + static char buf[1024]; + if (lastDeprecatedRule == Ssl::bumpClientFirst) { + strcpy(buf, "ssl_bump deny all"); + debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated implicit " + "\"ssl_bump deny all\" to \"ssl_bump none all\". New ssl_bump configurations " + "must not use implicit rules. Update your ssl_bump rules."); + } else { + strcpy(buf, "ssl_bump allow all"); + debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated implicit " + "\"ssl_bump allow all\" to \"ssl_bump client-first all\" which is usually " + "inferior to the newer server-first bumping mode. New ssl_bump" + " configurations must not use implicit rules. Update your ssl_bump rules."); + } + parse_line(buf); + } +} + static void parse_sslproxy_ssl_bump(acl_access **ssl_bump) { + typedef const char *BumpCfgStyle; + BumpCfgStyle bcsNone = NULL; + BumpCfgStyle bcsNew = "new client/server-first/none"; + BumpCfgStyle bcsOld = "deprecated allow/deny"; + static BumpCfgStyle bumpCfgStyleLast = bcsNone; + BumpCfgStyle bumpCfgStyleNow = bcsNone; char *bm; if ((bm = strtok(NULL, w_space)) == NULL) { self_destruct(); return; } + // if this is the first rule proccessed + if (*ssl_bump == NULL) { + bumpCfgStyleLast = bcsNone; + sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd; + } + acl_access *A = new acl_access; A->allow = allow_t(ACCESS_ALLOWED); - if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) + if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) { A->allow.kind = Ssl::bumpClientFirst; - else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) + bumpCfgStyleNow = bcsNew; + } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) { A->allow.kind = Ssl::bumpServerFirst; - else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0) + bumpCfgStyleNow = bcsNew; + } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0) { A->allow.kind = Ssl::bumpNone; - else if (strcmp(bm, "allow") == 0 || strcmp(bm, "deny") == 0) { - // allow/deny rule sets may rely on an implicit "negate the last one" - // rule which we cannot support due to multuple "allow" keywords - debugs(3, DBG_CRITICAL, "FATAL: ssl_bump allow/deny rule(s) " << - "must be CAREFULLY converted to specify bump mode(s)."); - self_destruct(); - return; + bumpCfgStyleNow = bcsNew; + } else if (strcmp(bm, "allow") == 0) { + if (sslBumpCfgRr::lastDeprecatedRule == Ssl::bumpEnd) + debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated " + "\"ssl_bump allow \" to \"ssl_bump client-first \" which " + "is usually inferior to the newer server-first " + "bumping mode. Update your ssl_bump rules."); + A->allow.kind = Ssl::bumpClientFirst; + bumpCfgStyleNow = bcsOld; + sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpClientFirst; + } else if (strcmp(bm, "deny") == 0) { + if (sslBumpCfgRr::lastDeprecatedRule == Ssl::bumpEnd) + debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated " + "\"ssl_bump deny \" to \"ssl_bump none \". Update " + "your ssl_bump rules."); + A->allow.kind = Ssl::bumpNone; + bumpCfgStyleNow = bcsOld; + sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpNone; } else { debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump mode: " << bm); self_destruct(); return; } + if (bumpCfgStyleLast != bcsNone && bumpCfgStyleNow != bumpCfgStyleLast) { + debugs(3, DBG_CRITICAL, "FATAL: do not mix " << bumpCfgStyleNow << " actions with " << + bumpCfgStyleLast << " actions. Update your ssl_bump rules."); + self_destruct(); + return; + } + + bumpCfgStyleLast = bumpCfgStyleNow; + aclParseAclList(LegacyParser, &A->aclList); acl_access *B, **T; for (B = *ssl_bump, T = ssl_bump; B; T = &B->next, B = B->next); *T = A; } static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump) { acl_access *sb; for (sb = ssl_bump; sb != NULL; sb = sb->next) { storeAppendPrintf(entry, "%s ", name); storeAppendPrintf(entry, "%s ", Ssl::bumpMode(sb->allow.kind)); if (sb->aclList) dump_acl_list(entry, sb->aclList); storeAppendPrintf(entry, "\n"); } } static void free_sslproxy_ssl_bump(acl_access **ssl_bump) === modified file 'src/cf.data.pre' --- src/cf.data.pre 2012-07-01 03:55:21 +0000 +++ src/cf.data.pre 2012-07-12 13:35:52 +0000 @@ -630,41 +630,41 @@ tag= Apply a tag to a request (for both ERR and OK results) Only sets a tag, does not alter existing tags. log= String to be logged in access.log. Available as %ea in logformat specifications If protocol=3.0 (the default) then URL escaping is used to protect each value in both requests and responses. If using protocol=2.5 then all values need to be enclosed in quotes if they may contain whitespace, or the whitespace escaped using \. And quotes or \ characters within the keyword value must be \ escaped. When using the concurrency= option the protocol is changed by introducing a query channel tag infront of the request/response. The query channel tag is a number between 0 and concurrency-1. DOC_END NAME: acl TYPE: acl LOC: Config.aclList -IFDEF USE_SSL +IF USE_SSL DEFAULT: ssl::certHasExpired ssl_error X509_V_ERR_CERT_HAS_EXPIRED DEFAULT: ssl::certNotYetValid ssl_error X509_V_ERR_CERT_NOT_YET_VALID DEFAULT: ssl::certDomainMismatch ssl_error SQUID_X509_V_ERR_DOMAIN_MISMATCH DEFAULT: ssl::certUntrusted ssl_error X509_V_ERR_INVALID_CA X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY X509_V_ERR_CERT_UNTRUSTED DEFAULT: ssl::certSelfSigned ssl_error X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ENDIF DEFAULT: all src all DEFAULT: manager url_regex -i ^cache_object:// +i ^https?://[^/]+/squid-internal-mgr/ DEFAULT: localhost src 127.0.0.1/32 ::1 DEFAULT: to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1 DEFAULT_DOC: ACLs all, manager, localhost, and to_localhost are predefined. DOC_START Defining an Access List Every access list definition must begin with an aclname and acltype, followed by either type-specific arguments or a quoted filename that they are read from. acl aclname acltype argument ... acl aclname acltype "file" ... @@ -861,41 +861,41 @@ acl aclname ca_cert attribute values... # match against attributes a users issuing CA SSL certificate # attribute is one of DN/C/O/CN/L/ST [fast] acl aclname ext_user username ... acl aclname ext_user_regex [-i] pattern ... # string match on username returned by external acl helper [slow] # use REQUIRED to accept any non-null user name. acl aclname tag tagvalue ... # string match on tag returned by external acl helper [slow] acl aclname hier_code codename ... # string match against squid hierarchy code(s); [fast] # e.g., DIRECT, PARENT_HIT, NONE, etc. # # NOTE: This has no effect in http_access rules. It only has # effect in rules that affect the reply data stream such as # http_reply_access. -IFDEF USE_SSL +IF USE_SSL acl aclname ssl_error errorname # match against SSL certificate validation error [fast] # # For valid error names see in @DEFAULT_ERROR_DIR@/templates/error-details.txt # template file. # # The following can be used as shortcuts for certificate properties: # [ssl::]certHasExpired: the "not after" field is in the past # [ssl::]certNotYetValid: the "not before" field is in the future # [ssl::]certUntrusted: The certificate issuer is not to be trusted. # [ssl::]certSelfSigned: The certificate is self signed. # [ssl::]certDomainMismatch: The certificate CN domain does not # match the name the name of the host we are connecting to. # # The ssl::certHasExpired, ssl::certNotYetValid, ssl::certDomainMismatch, # ssl::certUntrusted, and ssl::certSelfSigned can also be used as # predefined ACLs, just like the 'all' ACL. # # NOTE: The ssl_error ACL is only supported with sslproxy_cert_error, # sslproxy_cert_sign, and sslproxy_cert_adapt options. @@ -1545,54 +1545,58 @@ IFDEF: USE_SSL TYPE: PortCfg DEFAULT: none LOC: Config.Sockaddr.https DOC_START Usage: [ip:]port cert=certificate.pem [key=key.pem] [mode] [options...] The socket address where Squid will listen for client requests made over TLS or SSL connections. Commonly referred to as HTTPS. This is most useful for situations where you are running squid in accelerator mode and you want to do the SSL work at the accelerator level. You may specify multiple socket addresses on multiple lines, each with their own SSL certificate and/or options. Modes: accel Accelerator / reverse proxy mode + intercept Support for IP-Layer interception of + outgoing requests without browser settings. + NP: disables authentication and IPv6 on the port. + tproxy Support Linux TPROXY for spoofing outgoing connections using the client IP address. NP: disables authentication and maybe IPv6 on the port. ssl-bump For each intercepted connection allowed by ssl_bump ACLs, establish a secure connection with the client and with the server, decrypt HTTPS messages as they pass through Squid, and treat them as unencrypted HTTP messages, becoming the man-in-the-middle. An "ssl_bump server-first" match is required to fully enable bumping of intercepted SSL connections. - Requires tproxy. + Requires tproxy or intercept. Omitting the mode flag causes default forward proxy mode to be used. See http_port for a list of generic options SSL Options: cert= Path to SSL certificate (PEM format). key= Path to SSL private key file (PEM format) if not specified, the certificate file is assumed to be a combined certificate and key file. version= The version of SSL/TLS supported 1 automatic (default) 2 SSLv2 only 3 SSLv3 only === modified file 'src/cf_gen.cc' --- src/cf_gen.cc 2012-02-24 18:47:57 +0000 +++ src/cf_gen.cc 2012-07-12 13:30:59 +0000 @@ -242,50 +242,50 @@ *-------------------------------------------------------------------*/ /* Open input file */ fp.open(input_filename, std::ifstream::in); if (fp.fail()) { std::cerr << "error while opening input file '" << input_filename << "': " << strerror(errno) << std::endl; exit(1); } state = sSTART; while (fp.getline(buff,MAX_LINE), fp.good() && state != sEXIT) { char *t; linenum++; if ((t = strchr(buff, '\n'))) *t = '\0'; - if(strncmp(buff, "IFDEF ", 6) == 0) { - if ((ptr = strtok(buff + 6, WS)) == NULL) { - std::cerr << "Missing IFDEF parameter on line" << linenum << std::endl; + if(strncmp(buff, "IF ", 3) == 0) { + if ((ptr = strtok(buff + 3, WS)) == NULL) { + std::cerr << "Missing IF parameter on line" << linenum << std::endl; exit(1); } IFDEFS.push(ptr); continue; } else if (strcmp(buff, "ENDIF") == 0) { if (IFDEFS.size() == 0) { - std::cerr << "ENDIF without IFDEF before on line " << linenum << std::endl; + std::cerr << "ENDIF without IF before on line " << linenum << std::endl; exit(1); } IFDEFS.pop(); } else if (!IFDEFS.size() || isDefined(IFDEFS.top())) switch (state) { case sSTART: if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) { /* ignore empty and comment lines */ (void) 0; } else if (!strncmp(buff, "NAME:", 5)) { char *name, *aliasname; if ((name = strtok(buff + 5, WS)) == NULL) { std::cerr << "Error in input file\n"; exit(1); } === modified file 'src/client_side.cc' --- src/client_side.cc 2012-07-01 03:55:21 +0000 +++ src/client_side.cc 2012-07-12 13:37:54 +0000 @@ -3631,41 +3631,41 @@ fd_note(params.conn->fd, "client https connect"); if (s->tcp_keepalive.enabled) { commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout); } incoming_sockets_accepted++; // Socket is ready, setup the connection manager to start using it ConnStateData *connState = connStateCreate(params.conn, s); if (s->sslBump) { debugs(33, 5, "httpsAccept: accept transparent connection: " << params.conn); if (!Config.accessList.ssl_bump) { httpsSslBumpAccessCheckDone(ACCESS_DENIED, connState); return; } // Create a fake HTTP request for ssl_bump ACL check, - // using tproxy-provided destination IP and port. + // using tproxy/intercept provided destination IP and port. HttpRequest *request = new HttpRequest(); static char ip[MAX_IPSTRLEN]; assert(params.conn->flags & (COMM_TRANSPARENT | COMM_INTERCEPTION)); request->SetHost(params.conn->local.NtoA(ip, sizeof(ip))); request->port = params.conn->local.GetPort(); request->myportname = s->name; ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, request, NULL); acl_checklist->src_addr = params.conn->remote; acl_checklist->my_addr = s->s; acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, connState); return; } else { SSL_CTX *sslContext = s->staticSslContext.get(); httpsEstablish(connState, sslContext, Ssl::bumpNone); } } void ConnStateData::sslCrtdHandleReplyWrapper(void *data, char *reply) === modified file 'src/client_side.h' --- src/client_side.h 2012-07-01 03:55:21 +0000 +++ src/client_side.h 2012-07-13 18:33:40 +0000 @@ -326,41 +326,46 @@ #if USE_SSL /// called by FwdState when it is done bumping the server void httpsPeeked(Comm::ConnectionPointer serverConnection); /// Start to create dynamic SSL_CTX for host or uses static port SSL context. void getSslContextStart(); /** * Done create dynamic ssl certificate. * * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage. */ void getSslContextDone(SSL_CTX * sslContext, bool isNew = false); /// Callback function. It is called when squid receive message from ssl_crtd. static void sslCrtdHandleReplyWrapper(void *data, char *reply); /// Proccess response from ssl_crtd. void sslCrtdHandleReply(const char * reply); void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode); bool switchedToHttps() const { return switchedToHttps_; } Ssl::ServerBump *serverBump() {return sslServerBump;} - void setServerBump(Ssl::ServerBump *srvBump) {if (!sslServerBump) sslServerBump = srvBump;} + inline void setServerBump(Ssl::ServerBump *srvBump) { + if (!sslServerBump) + sslServerBump = srvBump; + else + assert(sslServerBump == srvBump); + } /// Fill the certAdaptParams with the required data for certificate adaptation /// and create the key for storing/retrieve the certificate to/from the cache void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties); /// Called when the client sends the first request on a bumped connection. /// Returns false if no [delayed] error should be written to the client. /// Otherwise, writes the error to the client and returns true. Also checks /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests. bool serveDelayedError(ClientSocketContext *context); Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a). #else bool switchedToHttps() const { return false; } #endif protected: void startDechunkingRequest(); void finishDechunkingRequest(bool withSuccess); void abortChunkedRequestBody(const err_type error); err_type handleChunkedRequestBody(size_t &putSize); === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2012-07-01 03:55:21 +0000 +++ src/client_side_request.cc 2012-07-12 14:50:22 +0000 @@ -1506,99 +1506,101 @@ * longer valid, it should call cbdataReferenceDone() so that * ClientHttpRequest's reference count goes to zero and it will get * deleted. ClientHttpRequest will then delete ClientRequestContext. * * Note that we set the _done flags here before actually starting * the callout. This is strictly for convenience. */ extern tos_t aclMapTOS (acl_tos * head, ACLChecklist * ch); extern nfmark_t aclMapNfmark (acl_nfmark * head, ACLChecklist * ch); void ClientHttpRequest::doCallouts() { assert(calloutContext); /*Save the original request for logging purposes*/ if (!calloutContext->http->al.request) calloutContext->http->al.request = HTTPMSGLOCK(request); + if (!calloutContext->error) { // CVE-2009-0801: verify the Host: header is consistent with other known details. - if (!calloutContext->error && !calloutContext->host_header_verify_done) { - debugs(83, 3, HERE << "Doing calloutContext->hostHeaderVerify()"); - calloutContext->host_header_verify_done = true; - calloutContext->hostHeaderVerify(); - return; - } + if (!calloutContext->host_header_verify_done) { + debugs(83, 3, HERE << "Doing calloutContext->hostHeaderVerify()"); + calloutContext->host_header_verify_done = true; + calloutContext->hostHeaderVerify(); + return; + } - if (!calloutContext->error && !calloutContext->http_access_done) { - debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()"); - calloutContext->http_access_done = true; - calloutContext->clientAccessCheck(); - return; - } + if (!calloutContext->http_access_done) { + debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()"); + calloutContext->http_access_done = true; + calloutContext->clientAccessCheck(); + return; + } #if USE_ADAPTATION - if (!calloutContext->error && !calloutContext->adaptation_acl_check_done) { - calloutContext->adaptation_acl_check_done = true; - if (Adaptation::AccessCheck::Start( + if (!calloutContext->adaptation_acl_check_done) { + calloutContext->adaptation_acl_check_done = true; + if (Adaptation::AccessCheck::Start( Adaptation::methodReqmod, Adaptation::pointPreCache, request, NULL, this)) - return; // will call callback - } + return; // will call callback + } #endif - if (!calloutContext->error && !calloutContext->redirect_done) { - calloutContext->redirect_done = true; - assert(calloutContext->redirect_state == REDIRECT_NONE); - - if (Config.Program.redirect) { - debugs(83, 3, HERE << "Doing calloutContext->clientRedirectStart()"); - calloutContext->redirect_state = REDIRECT_PENDING; - calloutContext->clientRedirectStart(); - return; + if (!calloutContext->redirect_done) { + calloutContext->redirect_done = true; + assert(calloutContext->redirect_state == REDIRECT_NONE); + + if (Config.Program.redirect) { + debugs(83, 3, HERE << "Doing calloutContext->clientRedirectStart()"); + calloutContext->redirect_state = REDIRECT_PENDING; + calloutContext->clientRedirectStart(); + return; + } } - } - if (!calloutContext->error && !calloutContext->adapted_http_access_done) { - debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()"); - calloutContext->adapted_http_access_done = true; - calloutContext->clientAccessCheck2(); - return; - } + if (!calloutContext->adapted_http_access_done) { + debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()"); + calloutContext->adapted_http_access_done = true; + calloutContext->clientAccessCheck2(); + return; + } - if (!calloutContext->error && !calloutContext->interpreted_req_hdrs) { - debugs(83, 3, HERE << "Doing clientInterpretRequestHeaders()"); - calloutContext->interpreted_req_hdrs = 1; - clientInterpretRequestHeaders(this); - } + if (!calloutContext->interpreted_req_hdrs) { + debugs(83, 3, HERE << "Doing clientInterpretRequestHeaders()"); + calloutContext->interpreted_req_hdrs = 1; + clientInterpretRequestHeaders(this); + } - if (!calloutContext->error && !calloutContext->no_cache_done) { - calloutContext->no_cache_done = true; + if (!calloutContext->no_cache_done) { + calloutContext->no_cache_done = true; - if (Config.accessList.noCache && request->flags.cachable) { - debugs(83, 3, HERE << "Doing calloutContext->checkNoCache()"); - calloutContext->checkNoCache(); - return; + if (Config.accessList.noCache && request->flags.cachable) { + debugs(83, 3, HERE << "Doing calloutContext->checkNoCache()"); + calloutContext->checkNoCache(); + return; + } } - } + } // if !calloutContext->error if (!calloutContext->tosToClientDone) { calloutContext->tosToClientDone = true; if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConnection)) { ACLFilledChecklist ch(NULL, request, NULL); ch.src_addr = request->client_addr; ch.my_addr = request->my_addr; tos_t tos = aclMapTOS(Ip::Qos::TheConfig.tosToClient, &ch); if (tos) Ip::Qos::setSockTos(getConn()->clientConnection, tos); } } if (!calloutContext->nfmarkToClientDone) { calloutContext->nfmarkToClientDone = true; if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConnection)) { ACLFilledChecklist ch(NULL, request, NULL); ch.src_addr = request->client_addr; ch.my_addr = request->my_addr; nfmark_t mark = aclMapNfmark(Ip::Qos::TheConfig.nfmarkToClient, &ch); === modified file 'src/errorpage.cc' --- src/errorpage.cc 2012-06-19 21:51:49 +0000 +++ src/errorpage.cc 2012-07-12 14:59:05 +0000 @@ -581,46 +581,40 @@ request_hdrs(NULL), err_msg(NULL), #if USE_SSL detail(NULL), #endif detailCode(ERR_DETAIL_NONE) { memset(&flags, 0, sizeof(flags)); memset(&ftp, 0, sizeof(ftp)); if (page_id >= ERR_MAX && ErrorDynamicPages.items[page_id - ERR_MAX]->page_redirect != HTTP_STATUS_NONE) httpStatus = ErrorDynamicPages.items[page_id - ERR_MAX]->page_redirect; if (req != NULL) { request = HTTPMSGLOCK(req); src_addr = req->client_addr; } } void -ErrorState::detailError(int detailCode) -{ - detailCode = detailCode; -} - -void errorAppendEntry(StoreEntry * entry, ErrorState * err) { assert(entry->mem_obj != NULL); assert (entry->isEmpty()); debugs(4, 4, "Creating an error page for entry " << entry << " with errorstate " << err << " page id " << err->page_id); if (entry->store_status != STORE_PENDING) { debugs(4, 2, "Skipping error page due to store_status: " << entry->store_status); /* * If the entry is not STORE_PENDING, then no clients * care about it, and we don't need to generate an * error message */ assert(EBIT_TEST(entry->flags, ENTRY_ABORTED)); assert(entry->mem_obj->nclients == 0); delete err; return; } === modified file 'src/errorpage.h' --- src/errorpage.h 2012-06-19 21:51:49 +0000 +++ src/errorpage.h 2012-07-13 10:02:38 +0000 @@ -89,41 +89,41 @@ \endverbatim */ class HttpReply; class MemBuf; /// \ingroup ErrorPageAPI class ErrorState { public: ErrorState(err_type type, http_status, HttpRequest * request); ErrorState(); // not implemented. ~ErrorState(); /** * Allocates and initializes an error response */ HttpReply *BuildHttpReply(void); /// set error type-specific detail code - void detailError(int detailCode); + void detailError(int dCode) {detailCode = dCode;} private: /** * Locates error page template to be used for this error * and constructs the HTML page content from it. */ MemBuf *BuildContent(void); /** * Convert the given template string into textual output * * \param text The string to be converted * \param allowRecursion Whether to convert codes which output may contain codes */ MemBuf *ConvertText(const char *text, bool allowRecursion); /** * Generates the Location: header value for a deny_info error page * to be used for this error. */ === modified file 'src/url.cc' --- src/url.cc 2012-06-19 16:08:52 +0000 +++ src/url.cc 2012-07-12 15:42:23 +0000 @@ -445,40 +445,41 @@ } /** * Update request with parsed URI data. If the request arg is * non-NULL, put parsed values there instead of allocating a new * HttpRequest. */ static HttpRequest * urlParseFinish(const HttpRequestMethod& method, const AnyP::ProtocolType protocol, const char *const urlpath, const char *const host, const char *const login, const int port, HttpRequest *request) { if (NULL == request) request = new HttpRequest(method, protocol, urlpath); else { request->initHTTP(method, protocol, urlpath); + safe_free(request->canonical); } request->SetHost(host); xstrncpy(request->login, login, MAX_LOGIN_SZ); request->port = (unsigned short) port; return request; } static HttpRequest * 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; } return new HttpRequest(method, AnyP::PROTO_URN, urn + 4); }