*/
#include "squid.h"
+
+#include "acl/FilledChecklist.h"
+#include "auth/UserRequest.h"
+#if DELAY_POOLS
+#include "DelayPools.h"
+#endif
#include "errorpage.h"
-#include "MemBuf.h"
+#include "fde.h"
#include "http.h"
-#include "auth/UserRequest.h"
-#include "Store.h"
-#include "HttpReply.h"
-#include "HttpRequest.h"
-#include "MemObject.h"
#include "HttpHdrContRange.h"
#include "HttpHdrSc.h"
#include "HttpHdrScTarget.h"
-#include "ACLChecklist.h"
-#include "fde.h"
-#if DELAY_POOLS
-#include "DelayPools.h"
-#endif
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "MemBuf.h"
+#include "MemObject.h"
+#include "protos.h"
+#include "rfc1738.h"
#include "SquidTime.h"
+#include "Store.h"
#include "TextException.h"
+
#define SQUID_ENTER_THROWING_CODE() try {
#define SQUID_EXIT_THROWING_CODE(status) \
status = true; \
HttpHeader * hdr_out, const int we_do_ranges, const http_state_flags);
HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"), ServerStateData(theFwdState),
- lastChunk(0), header_bytes_read(0), reply_bytes_read(0), httpChunkDecoder(NULL)
+ lastChunk(0), header_bytes_read(0), reply_bytes_read(0),
+ body_bytes_truncated(0), httpChunkDecoder(NULL)
{
debugs(11,5,HERE << "HttpStateData " << this << " created");
ignoreCacheControl = false;
surrogateNoStore = false;
fd = fwd->server_fd;
readBuf = new MemBuf;
- readBuf->init(4096, SQUID_TCP_SO_RCVBUF);
+ readBuf->init();
orig_request = HTTPMSGLOCK(fwd->request);
+ // reset peer response time stats for %<pt
+ orig_request->hier.peer_http_request_sent.tv_sec = 0;
+ orig_request->hier.peer_http_request_sent.tv_usec = 0;
+
if (fwd->servers)
_peer = fwd->servers->_peer; /* might be NULL */
void
HttpStateData::processSurrogateControl(HttpReply *reply)
{
-#if USE_SQUID_ESI
-
if (request->flags.accelerated && reply->surrogate_control) {
- HttpHdrScTarget *sctusable =
- httpHdrScGetMergedTarget(reply->surrogate_control,
- Config.Accel.surrogate_id);
+ HttpHdrScTarget *sctusable = httpHdrScGetMergedTarget(reply->surrogate_control, Config.Accel.surrogate_id);
if (sctusable) {
if (EBIT_TEST(sctusable->mask, SC_NO_STORE) ||
/* The HttpHeader logic cannot tell if the header it's parsing is a reply to an
* accelerated request or not...
- * Still, this is an abtraction breach. - RC
+ * Still, this is an abstraction breach. - RC
*/
if (sctusable->max_age != -1) {
if (sctusable->max_age < sctusable->max_stale)
httpHdrScTargetDestroy(sctusable);
}
}
-
-#endif
}
int
return 0;
- default: /* Unknown status code */
- debugs (11, 0, HERE << "HttpStateData::cacheableReply: unexpected http status code " << rep->sline.status);
+ default:
+ /* RFC 2616 section 6.1.1: an unrecognized response MUST NOT be cached. */
+ debugs (11, 3, HERE << "Unknown HTTP status code " << rep->sline.status << ". Not cacheable.");
return 0;
if (_peer)
_peer->stats.n_keepalives_recv++;
- if (Config.onoff.detect_broken_server_pconns
- && reply->bodySize(request->method) == -1 && !flags.chunked) {
+ if (Config.onoff.detect_broken_server_pconns
+ && reply->bodySize(request->method) == -1 && !flags.chunked) {
debugs(11, 1, "keepaliveAccounting: Impossible keep-alive header from '" << entry->url() << "'" );
// debugs(11, 2, "GOT HTTP REPLY HDR:\n---------\n" << readBuf->content() << "\n----------" );
flags.keepalive_broken = 1;
HttpReply *newrep = new HttpReply;
const bool parsed = newrep->parse(readBuf, eof, &error);
- if (!parsed && readBuf->contentSize() > 5 && strncmp(readBuf->content(), "HTTP/", 5) != 0) {
+ if (!parsed && readBuf->contentSize() > 5 && strncmp(readBuf->content(), "HTTP/", 5) != 0 && strncmp(readBuf->content(), "ICY", 3) != 0) {
MemBuf *mb;
HttpReply *tmprep = new HttpReply;
- tmprep->sline.version = HttpVersion(1, 0);
- tmprep->sline.status = HTTP_OK;
- tmprep->header.putTime(HDR_DATE, squid_curtime);
+ tmprep->setHeaders(HTTP_OK, "Gatewaying", NULL, -1, -1, -1);
tmprep->header.putExt("X-Transformed-From", "HTTP/0.9");
mb = tmprep->pack();
newrep->parse(mb, eof, &error);
if (!parsed && error > 0) { // unrecoverable parsing error
debugs(11, 3, "processReplyHeader: Non-HTTP-compliant header: '" << readBuf->content() << "'");
flags.headers_parsed = 1;
- newrep->sline.version = HttpVersion(1, 0);
+ newrep->sline.version = HttpVersion(1,0);
newrep->sline.status = error;
HttpReply *vrep = setVirginReply(newrep);
entry->replaceHttpReply(vrep);
readBuf->consume(header_bytes_read);
}
+ /* Skip 1xx messages for now. Advertised in Via as an internal 1.0 hop */
+ if (newrep->sline.protocol == PROTO_HTTP && newrep->sline.status >= 100 && newrep->sline.status < 200) {
+
+#if WHEN_HTTP11
+ /* When HTTP/1.1 check if the client is expecting a 1xx reply and maybe pass it on */
+ if (orig_request->header.has(HDR_EXPECT)) {
+ // TODO: pass to the client anyway?
+ }
+#endif
+ delete newrep;
+ debugs(11, 2, HERE << "1xx headers consume " << header_bytes_read << " bytes header.");
+ header_bytes_read = 0;
+ if (reply_bytes_read > 0)
+ debugs(11, 2, HERE << "1xx headers consume " << reply_bytes_read << " bytes reply.");
+ reply_bytes_read = 0;
+ ctx_exit(ctx);
+ processReplyHeader();
+ return;
+ }
+
flags.chunked = 0;
- if (newrep->header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) {
+ if (newrep->sline.protocol == PROTO_HTTP && newrep->header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) {
flags.chunked = 1;
httpChunkDecoder = new ChunkedCodingParser;
}
* Parse the header and remove all referenced headers
*/
+ orig_request->hier.peer_reply_status = newrep->sline.status;
+
ctx_exit(ctx);
}
if (!vary) {
entry->makePrivate();
+ if (!fwd->reforwardableStatus(rep->sline.status))
+ EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
goto no_cache;
-
}
entry->mem_obj->vary_headers = xstrdup(vary);
if (body_bytes_read < vrep->content_length)
return INCOMPLETE_MSG;
+
+ if (body_bytes_truncated > 0) // already read more than needed
+ return COMPLETE_NONPERSISTENT_MSG; // disable pconns
}
/** \par
assert (fd == httpState->fd);
// assert(buf == readBuf->content());
PROF_start(HttpStateData_readReply);
- httpState->readReply (len, flag, xerrno);
+ httpState->readReply(len, flag, xerrno);
PROF_stop(HttpStateData_readReply);
}
*/
/* XXX this function is too long! */
void
-HttpStateData::readReply (const CommIoCbParams &io)
+HttpStateData::readReply(const CommIoCbParams &io)
{
int bin;
int clen;
clen >>= 1;
IOStats.Http.read_hist[bin]++;
+
+ // update peer response time stats (%<pt)
+ const timeval &sent = orig_request->hier.peer_http_request_sent;
+ orig_request->hier.peer_response_time =
+ sent.tv_sec ? tvSubMsec(sent, current_time) : -1;
}
/** \par
const http_status s = vrep->sline.status;
const HttpVersion &v = vrep->sline.version;
if (s == HTTP_INVALID_HEADER && v != HttpVersion(0,9)) {
+ debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Bad header encountered from " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
error = ERR_INVALID_RESP;
- } else
- if (s == HTTP_HEADER_TOO_LARGE) {
- fwd->dontRetry(true);
- error = ERR_TOO_BIG;
- } else {
- return true; // done parsing, got reply, and no error
- }
+ } else if (s == HTTP_HEADER_TOO_LARGE) {
+ fwd->dontRetry(true);
+ error = ERR_TOO_BIG;
+ } else {
+ return true; // done parsing, got reply, and no error
+ }
} else {
// parsed headers but got no reply
+ debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: No reply at all for " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
error = ERR_INVALID_RESP;
}
} else {
assert(eof);
- error = readBuf->hasContent() ?
- ERR_INVALID_RESP : ERR_ZERO_SIZE_OBJECT;
+ if (readBuf->hasContent()) {
+ error = ERR_INVALID_RESP;
+ debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Headers did not parse at all for " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
+ } else {
+ error = ERR_ZERO_SIZE_OBJECT;
+ debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: No object data received for " << entry->url() << " AKA " << orig_request->GetHost() << orig_request->urlpath.termedBuf() );
+ }
}
assert(error != ERR_NONE);
return false; // quit on error
}
+/** truncate what we read if we read too much so that writeReplyBody()
+ writes no more than what we should have read */
+void
+HttpStateData::truncateVirginBody()
+{
+ assert(flags.headers_parsed);
+
+ HttpReply *vrep = virginReply();
+ int64_t clen = -1;
+ if (!vrep->expectingBody(request->method, clen) || clen < 0)
+ return; // no body or a body of unknown size, including chunked
+
+ const int64_t body_bytes_read = reply_bytes_read - header_bytes_read;
+ if (body_bytes_read - body_bytes_truncated <= clen)
+ return; // we did not read too much or already took care of the extras
+
+ if (const int64_t extras = body_bytes_read - body_bytes_truncated - clen) {
+ // server sent more that the advertised content length
+ debugs(11,5, HERE << "body_bytes_read=" << body_bytes_read <<
+ " clen=" << clen << '/' << vrep->content_length <<
+ " body_bytes_truncated=" << body_bytes_truncated << '+' << extras);
+
+ readBuf->truncate(extras);
+ body_bytes_truncated += extras;
+ }
+}
+
/**
* Call this when there is data from the origin server
* which should be sent to either StoreEntry, or to ICAP...
void
HttpStateData::writeReplyBody()
{
+ truncateVirginBody(); // if needed
const char *data = readBuf->content();
int len = readBuf->contentSize();
addVirginReplyBody(data, len);
{
const char *data = NULL;
int len;
- bool status = false;
+ bool wasThereAnException = false;
assert(flags.chunked);
assert(httpChunkDecoder);
SQUID_ENTER_THROWING_CODE();
MemBuf decodedData;
decodedData.init();
- const bool done = httpChunkDecoder->parse(readBuf,&decodedData);
+ const bool doneParsing = httpChunkDecoder->parse(readBuf,&decodedData);
len = decodedData.contentSize();
data=decodedData.content();
addVirginReplyBody(data, len);
- if (done) {
+ if (doneParsing) {
lastChunk = 1;
flags.do_next_read = 0;
}
- SQUID_EXIT_THROWING_CODE(status);
- return status;
+ SQUID_EXIT_THROWING_CODE(wasThereAnException);
+ return wasThereAnException;
}
/**
}
#if USE_ADAPTATION
+ debugs(11,5, HERE << "adaptationAccessCheckPending=" << adaptationAccessCheckPending);
if (adaptationAccessCheckPending)
return;
void
HttpStateData::maybeReadVirginBody()
{
- int read_sz = replyBodySpace(readBuf->spaceSize());
+ // we may need to grow the buffer if headers do not fit
+ const int minRead = flags.headers_parsed ? 0 :1024;
+ const int read_size = replyBodySpace(*readBuf, minRead);
debugs(11,9, HERE << (flags.do_next_read ? "may" : "wont") <<
- " read up to " << read_sz << " bytes from FD " << fd);
+ " read up to " << read_size << " bytes from FD " << fd);
/*
* why <2? Because delayAwareRead() won't actually read if
* handler until we get a notification from someone that
* its okay to read again.
*/
- if (read_sz < 2) {
- if (flags.headers_parsed)
- return;
- else
- read_sz = 1024;
- }
+ if (read_size < 2)
+ return;
if (flags.do_next_read) {
flags.do_next_read = 0;
typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
- entry->delayAwareRead(fd, readBuf->space(read_sz), read_sz,
+ entry->delayAwareRead(fd, readBuf->space(read_size), read_size,
asyncCall(11, 5, "HttpStateData::readReply",
Dialer(this, &HttpStateData::readReply)));
}
commSetTimeout(fd, Config.Timeout.read, timeoutCall);
flags.request_sent = 1;
+
+ orig_request->hier.peer_http_request_sent = current_time;
}
// Close the HTTP server connection. Used by serverComplete().
return fd < 0;
}
+
+/*
+ * Fixup authentication request headers for special cases
+ */
+static void
+httpFixupAuthentication(HttpRequest * request, HttpRequest * orig_request, const HttpHeader * hdr_in, HttpHeader * hdr_out, http_state_flags flags)
+{
+ http_hdr_type header = flags.originpeer ? HDR_AUTHORIZATION : HDR_PROXY_AUTHORIZATION;
+
+ /* Nothing to do unless we are forwarding to a peer */
+ if (!request->flags.proxying)
+ return;
+
+ /* Needs to be explicitly enabled */
+ if (!orig_request->peer_login)
+ return;
+
+ /* Maybe already dealt with? */
+ if (hdr_out->has(header))
+ return;
+
+ /* Nothing to do here for PASSTHRU */
+ if (strcmp(orig_request->peer_login, "PASSTHRU") == 0)
+ return;
+
+ /* PROXYPASS is a special case, single-signon to servers with the proxy password (basic only) */
+ if (flags.originpeer && strcmp(orig_request->peer_login, "PROXYPASS") == 0 && hdr_in->has(HDR_PROXY_AUTHORIZATION)) {
+ const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION);
+
+ if (auth && strncasecmp(auth, "basic ", 6) == 0) {
+ hdr_out->putStr(header, auth);
+ return;
+ }
+ }
+
+ /* Special mode to pass the username to the upstream cache */
+ if (*orig_request->peer_login == '*') {
+ char loginbuf[256];
+ const char *username = "-";
+
+ if (orig_request->extacl_user.size())
+ username = orig_request->extacl_user.termedBuf();
+ else if (orig_request->auth_user_request)
+ username = orig_request->auth_user_request->username();
+
+ snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
+
+ httpHeaderPutStrf(hdr_out, header, "Basic %s",
+ base64_encode(loginbuf));
+ return;
+ }
+
+ /* external_acl provided credentials */
+ if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size() &&
+ (strcmp(orig_request->peer_login, "PASS") == 0 ||
+ strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
+ char loginbuf[256];
+ snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
+ SQUIDSTRINGPRINT(orig_request->extacl_user),
+ SQUIDSTRINGPRINT(orig_request->extacl_passwd));
+ httpHeaderPutStrf(hdr_out, header, "Basic %s",
+ base64_encode(loginbuf));
+ return;
+ }
+
+ /* Kerberos login to peer */
+#if HAVE_KRB5 && HAVE_GSSAPI
+ if (strncmp(orig_request->peer_login, "NEGOTIATE",strlen("NEGOTIATE")) == 0) {
+ char *Token=NULL;
+ char *PrincipalName=NULL,*p;
+ if ((p=strchr(orig_request->peer_login,':')) != NULL ) {
+ PrincipalName=++p;
+ }
+ Token = peer_proxy_negotiate_auth(PrincipalName,request->peer_host);
+ if (Token) {
+ httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Negotiate %s",Token);
+ }
+ return;
+ }
+#endif /* HAVE_KRB5 && HAVE_GSSAPI */
+
+ httpHeaderPutStrf(hdr_out, header, "Basic %s",
+ base64_encode(orig_request->peer_login));
+ return;
+}
+
/*
* build request headers and append them to a given MemBuf
* used by buildRequestPrefix()
LOCAL_ARRAY(char, ntoabuf, MAX_IPSTRLEN);
const HttpHeader *hdr_in = &orig_request->header;
const HttpHeaderEntry *e = NULL;
- String strFwd;
HttpHeaderPos pos = HttpHeaderInitPos;
assert (hdr_out->owner == hoRequest);
strVia.clean();
}
-#if USE_SQUID_ESI
- {
+ if (orig_request->flags.accelerated) {
/* Append Surrogate-Capabilities */
- String strSurrogate (hdr_in->getList(HDR_SURROGATE_CAPABILITY));
- snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0 ESI/1.0\"",
- Config.Accel.surrogate_id);
+ String strSurrogate(hdr_in->getList(HDR_SURROGATE_CAPABILITY));
+#if USE_SQUID_ESI
+ snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0 ESI/1.0\"", Config.Accel.surrogate_id);
+#else
+ snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0\"", Config.Accel.surrogate_id);
+#endif
strListAdd(&strSurrogate, bbuf, ',');
hdr_out->putStr(HDR_SURROGATE_CAPABILITY, strSurrogate.termedBuf());
}
-#endif
-
- strFwd = hdr_in->getList(HDR_X_FORWARDED_FOR);
/** \pre Handle X-Forwarded-For */
if (strcmp(opt_forwarded_for, "delete") != 0) {
+
+ String strFwd = hdr_in->getList(HDR_X_FORWARDED_FOR);
+
+ if (strFwd.size() > 65536/2) {
+ // There is probably a forwarding loop with Via detection disabled.
+ // If we do nothing, String will assert on overflow soon.
+ // TODO: Terminate all transactions with huge XFF?
+ strFwd = "error";
+
+ static int warnedCount = 0;
+ if (warnedCount++ < 100) {
+ const char *url = entry ? entry->url() : urlCanonical(orig_request);
+ debugs(11, 1, "Warning: likely forwarding loop with " << url);
+ }
+ }
+
if (strcmp(opt_forwarded_for, "on") == 0) {
/** If set to ON - append client IP or 'unknown'. */
- strFwd = hdr_in->getList(HDR_X_FORWARDED_FOR);
if ( orig_request->client_addr.IsNoAddr() )
strListAdd(&strFwd, "unknown", ',');
else
strListAdd(&strFwd, orig_request->client_addr.NtoA(ntoabuf, MAX_IPSTRLEN), ',');
} else if (strcmp(opt_forwarded_for, "off") == 0) {
/** If set to OFF - append 'unknown'. */
- strFwd = hdr_in->getList(HDR_X_FORWARDED_FOR);
strListAdd(&strFwd, "unknown", ',');
} else if (strcmp(opt_forwarded_for, "transparent") == 0) {
/** If set to TRANSPARENT - pass through unchanged. */
- strFwd = hdr_in->getList(HDR_X_FORWARDED_FOR);
} else if (strcmp(opt_forwarded_for, "truncate") == 0) {
/** If set to TRUNCATE - drop existing list and replace with client IP or 'unknown'. */
if ( orig_request->client_addr.IsNoAddr() )
hdr_out->putStr(HDR_X_FORWARDED_FOR, strFwd.termedBuf());
}
/** If set to DELETE - do not copy through. */
- strFwd.clean();
/* append Host if not there already */
if (!hdr_out->has(HDR_HOST)) {
}
}
- /* append Proxy-Authorization if configured for peer, and proxying */
- if (request->flags.proxying && orig_request->peer_login &&
- !hdr_out->has(HDR_PROXY_AUTHORIZATION)) {
- if (*orig_request->peer_login == '*') {
- /* Special mode, to pass the username to the upstream cache */
- char loginbuf[256];
- const char *username = "-";
-
- if (orig_request->extacl_user.size())
- username = orig_request->extacl_user.termedBuf();
- else if (orig_request->auth_user_request)
- username = orig_request->auth_user_request->username();
-
- snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
-
- httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
- base64_encode(loginbuf));
- } else if (strcmp(orig_request->peer_login, "PASS") == 0) {
- if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size()) {
- char loginbuf[256];
- snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
- SQUIDSTRINGPRINT(orig_request->extacl_user),
- SQUIDSTRINGPRINT(orig_request->extacl_passwd));
- httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
- base64_encode(loginbuf));
- }
- } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) {
- /* Nothing to do */
- } else {
- httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
- base64_encode(orig_request->peer_login));
- }
- }
-
- /* append WWW-Authorization if configured for peer */
- if (flags.originpeer && orig_request->peer_login &&
- !hdr_out->has(HDR_AUTHORIZATION)) {
- if (strcmp(orig_request->peer_login, "PASS") == 0) {
- /* No credentials to forward.. (should have been done above if available) */
- } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) {
- /* Special mode, convert proxy authentication to WWW authentication
- * (also applies to authentication provided by external acl)
- */
- const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION);
-
- if (auth && strncasecmp(auth, "basic ", 6) == 0) {
- hdr_out->putStr(HDR_AUTHORIZATION, auth);
- } else if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size()) {
- char loginbuf[256];
- snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
- SQUIDSTRINGPRINT(orig_request->extacl_user),
- SQUIDSTRINGPRINT(orig_request->extacl_passwd));
- httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
- base64_encode(loginbuf));
- }
- } else if (*orig_request->peer_login == '*') {
- /* Special mode, to pass the username to the upstream cache */
- char loginbuf[256];
- const char *username = "-";
-
- if (orig_request->auth_user_request)
- username = orig_request->auth_user_request->username();
- else if (orig_request->extacl_user.size())
- username = orig_request->extacl_user.termedBuf();
-
- snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
+ /* Fixup (Proxy-)Authorization special cases. Plain relaying dealt with above */
+ httpFixupAuthentication(request, orig_request, hdr_in, hdr_out, flags);
- httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
- base64_encode(loginbuf));
- } else {
- /* Fixed login string */
- httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
- base64_encode(orig_request->peer_login));
- }
- }
-
- /* append Cache-Control, add max-age if not there already */ {
+ /* append Cache-Control, add max-age if not there already */
+ {
HttpHdrCc *cc = hdr_in->getCc();
if (!cc)
EBIT_SET(cc->mask, CC_NO_CACHE);
#endif
- /* Add max-age only without no-cache */
- if (!EBIT_TEST(cc->mask, CC_MAX_AGE) && !EBIT_TEST(cc->mask, CC_NO_CACHE)) {
+ /* Add max-age only without no-cache */
+ if (!EBIT_TEST(cc->mask, CC_MAX_AGE) && !EBIT_TEST(cc->mask, CC_NO_CACHE)) {
const char *url =
entry ? entry->url() : urlCanonical(orig_request);
httpHdrCcSetMaxAge(cc, getMaxAge(url));
switch (e->id) {
-/** \title RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid should not pass on. */
+ /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid should not pass on. */
case HDR_PROXY_AUTHORIZATION:
/** \par Proxy-Authorization:
* Only pass on proxy authentication to peers for which
* authentication forwarding is explicitly enabled
*/
-
- if (flags.proxying && orig_request->peer_login &&
+ if (!flags.originpeer && flags.proxying && orig_request->peer_login &&
(strcmp(orig_request->peer_login, "PASS") == 0 ||
- strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
+ strcmp(orig_request->peer_login, "PROXYPASS") == 0 ||
+ strcmp(orig_request->peer_login, "PASSTHRU") == 0)) {
hdr_out->addEntry(e->clone());
}
-
break;
-/** \title RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid does not pass on. */
+ /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid does not pass on. */
case HDR_CONNECTION: /** \par Connection: */
case HDR_TE: /** \par TE: */
break;
-/** \title OTHER headers I haven't bothered to track down yet. */
+ /** \par OTHER headers I haven't bothered to track down yet. */
case HDR_AUTHORIZATION:
/** \par WWW-Authorization:
hdr_out->addEntry(e->clone());
} else {
/** \note In accelerators, only forward authentication if enabled
- * by login=PASS or login=PROXYPASS
- * (see also below for proxy->server authentication)
+ * (see also httpFixupAuthentication for special cases)
*/
if (orig_request->peer_login &&
(strcmp(orig_request->peer_login, "PASS") == 0 ||
+ strcmp(orig_request->peer_login, "PASSTHRU") == 0 ||
strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
hdr_out->addEntry(e->clone());
}
case HDR_IF_MODIFIED_SINCE:
/** \par If-Modified-Since:
- * append unless we added our own;
+ * append unless we added our own;
* \note at most one client's ims header can pass through */
if (!hdr_out->has(HDR_IF_MODIFIED_SINCE))
case HDR_MAX_FORWARDS:
/** \par Max-Forwards:
- * pass only on TRACE requests */
- if (orig_request->method == METHOD_TRACE) {
- const int hops = e->getInt();
+ * pass only on TRACE or OPTIONS requests */
+ if (orig_request->method == METHOD_TRACE || orig_request->method == METHOD_OPTIONS) {
+ const int64_t hops = e->getInt64();
if (hops > 0)
- hdr_out->putInt(HDR_MAX_FORWARDS, hops - 1);
+ hdr_out->putInt64(HDR_MAX_FORWARDS, hops - 1);
}
break;
/* build request prefix and append it to a given MemBuf;
* return the length of the prefix */
mb_size_t
-HttpStateData::buildRequestPrefix(HttpRequest * request,
- HttpRequest * orig_request,
- StoreEntry * entry,
+HttpStateData::buildRequestPrefix(HttpRequest * aRequest,
+ HttpRequest * original_request,
+ StoreEntry * sentry,
MemBuf * mb,
- http_state_flags flags)
+ http_state_flags stateFlags)
{
const int offset = mb->size;
- HttpVersion httpver(1, 0);
+ HttpVersion httpver(1,1);
mb->Printf("%s %s HTTP/%d.%d\r\n",
- RequestMethodStr(request->method),
- request->urlpath.size() ? request->urlpath.termedBuf() : "/",
+ RequestMethodStr(aRequest->method),
+ aRequest->urlpath.size() ? aRequest->urlpath.termedBuf() : "/",
httpver.major,httpver.minor);
/* build and pack headers */
{
HttpHeader hdr(hoRequest);
Packer p;
- httpBuildRequestHeader(request, orig_request, entry, &hdr, flags);
+ httpBuildRequestHeader(aRequest, original_request, sentry, &hdr, stateFlags);
- if (request->flags.pinned && request->flags.connection_auth)
- request->flags.auth_sent = 1;
+ if (aRequest->flags.pinned && aRequest->flags.connection_auth)
+ aRequest->flags.auth_sent = 1;
else if (hdr.has(HDR_AUTHORIZATION))
- request->flags.auth_sent = 1;
+ aRequest->flags.auth_sent = 1;
packerToMemInit(&p, mb);
hdr.packInto(&p);
}
mb.init();
+ request->peer_host=_peer?_peer->host:NULL;
buildRequestPrefix(request, orig_request, entry, &mb, flags);
debugs(11, 6, "httpSendRequest: FD " << fd << ":\n" << mb.buf);
comm_write_mbuf(fd, &mb, requestSender);
debugs(11,5, HERE << "doneSendingRequestBody: FD " << fd);
#if HTTP_VIOLATIONS
- ACLChecklist ch;
- ch.request = HTTPMSGLOCK(request);
-
if (Config.accessList.brokenPosts) {
- ch.accessList = cbdataReference(Config.accessList.brokenPosts);
- /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */
-
+ ACLFilledChecklist ch(Config.accessList.brokenPosts, request, NULL);
if (!ch.fastCheck()) {
debugs(11, 5, "doneSendingRequestBody: didn't match brokenPosts");
CommIoCbParams io(NULL);
deleteThis("HttpStateData::abortTransaction");
}
-#if DEAD_CODE
-void
-httpBuildVersion(HttpVersion * version, unsigned int major, unsigned int minor)
-{
- version->major = major;
- version->minor = minor;
-}
-#endif
-
HttpRequest *
HttpStateData::originalRequest()
{