/*
- * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
surrogateNoStore = false;
serverConnection = fwd->serverConnection();
- // reset peer response time stats for %<pt
- request->hier.peer_http_request_sent.tv_sec = 0;
- request->hier.peer_http_request_sent.tv_usec = 0;
-
if (fwd->serverConnection() != NULL)
_peer = cbdataReference(fwd->serverConnection()->getPeer()); /* might be NULL */
* for example, the request to this neighbor fails.
*/
if (_peer->options.proxy_only)
- entry->releaseRequest();
+ entry->releaseRequest(true);
#if USE_DELAY_POOLS
entry->setNoDelay(_peer->options.no_delay);
#if USE_HTCP
neighborsHtcpClear(e, nullptr, e->mem_obj->request.getRaw(), e->mem_obj->method, HTCP_CLR_INVALIDATION);
#endif
- pe->release();
+ pe->release(true);
}
/** \par
#if USE_HTCP
neighborsHtcpClear(e, nullptr, e->mem_obj->request.getRaw(), HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_INVALIDATION);
#endif
- pe->release();
+ pe->release(true);
}
}
#endif
if (EBIT_TEST(entry->flags, RELEASE_REQUEST))
- return decision.make(ReuseDecision::reuseNot, "the entry has been released");
+ return decision.make(ReuseDecision::doNotCacheButShare, "the entry has been released");
// RFC 7234 section 4: a cache MUST use the most recent response
// (as determined by the Date header field)
// check whether the 1xx response forwarding is allowed by squid.conf
if (Config.accessList.reply) {
ACLFilledChecklist ch(Config.accessList.reply, originalRequest().getRaw());
+ ch.al = fwd->al;
ch.reply = reply;
+ ch.syncAle(originalRequest().getRaw(), nullptr);
HTTPMSGLOCK(ch.reply);
- if (ch.fastCheck() != ACCESS_ALLOWED) { // TODO: support slow lookups?
+ if (!ch.fastCheck().allowed()) { // TODO: support slow lookups?
debugs(11, 3, HERE << "ignoring denied 1xx");
proceedAfter1xx();
return;
/* Check if object is cacheable or not based on reply code */
debugs(11, 3, "HTTP CODE: " << statusCode);
- if (const StoreEntry *oldEntry = findPreviouslyCachedEntry(entry))
+ if (StoreEntry *oldEntry = findPreviouslyCachedEntry(entry)) {
+ oldEntry->lock("HttpStateData::haveParsedReplyHeaders");
sawDateGoBack = rep->olderThan(oldEntry->getReply());
+ oldEntry->unlock("HttpStateData::haveParsedReplyHeaders");
+ }
if (neighbors_do_private_keys && !sawDateGoBack)
httpMaybeRemovePublic(entry, rep->sline.status());
break;
case ReuseDecision::cachePositively:
- entry->makePublic();
+ if (!entry->makePublic()) {
+ decision.make(ReuseDecision::doNotCacheButShare, "public key creation error");
+ entry->makePrivate(true);
+ }
break;
case ReuseDecision::cacheNegatively:
- entry->cacheNegatively();
+ if (!entry->cacheNegatively()) {
+ decision.make(ReuseDecision::doNotCacheButShare, "public key creation error");
+ entry->makePrivate(true);
+ }
break;
case ReuseDecision::doNotCacheButShare:
++ IOStats.Http.read_hist[bin];
- // update peer response time stats (%<pt)
- const timeval &sent = request->hier.peer_http_request_sent;
- if (sent.tv_sec)
- tvSub(request->hier.peer_response_time, sent, current_time);
- else
- request->hier.peer_response_time.tv_sec = -1;
+ request->hier.notePeerRead();
}
/* Continue to process previously read data */
void
HttpStateData::processReplyBody()
{
- Ip::Address client_addr;
- bool ispinned = false;
-
if (!flags.headers_parsed) {
flags.do_next_read = true;
maybeReadVirginBody();
}
break;
- case COMPLETE_PERSISTENT_MSG:
+ case COMPLETE_PERSISTENT_MSG: {
debugs(11, 5, "processReplyBody: COMPLETE_PERSISTENT_MSG from " << serverConnection);
- /* yes we have to clear all these! */
+
+ // TODO: Remove serverConnectionSaved but preserve exception safety.
+
commUnsetConnTimeout(serverConnection);
flags.do_next_read = false;
comm_remove_close_handler(serverConnection->fd, closeHandler);
closeHandler = NULL;
- fwd->unregister(serverConnection);
+ Ip::Address client_addr; // XXX: Remove as unused. Why was it added?
if (request->flags.spoofClientIp)
client_addr = request->client_addr;
+ auto serverConnectionSaved = serverConnection;
+ fwd->unregister(serverConnection);
+ serverConnection = nullptr;
+
+ bool ispinned = false; // TODO: Rename to isOrShouldBePinned
if (request->flags.pinned) {
ispinned = true;
} else if (request->flags.connectionAuth && request->flags.authSent) {
ispinned = true;
}
- if (ispinned && request->clientConnectionManager.valid()) {
- request->clientConnectionManager->pinConnection(serverConnection, request.getRaw(), _peer,
- (request->flags.connectionAuth));
+ if (ispinned) {
+ if (request->clientConnectionManager.valid()) {
+ CallJobHere1(11, 4, request->clientConnectionManager,
+ ConnStateData,
+ notePinnedConnectionBecameIdle,
+ ConnStateData::PinnedIdleContext(serverConnectionSaved, request));
+ } else {
+ // must not pool/share ispinned connections, even orphaned ones
+ serverConnectionSaved->close();
+ }
} else {
- fwd->pconnPush(serverConnection, request->url.host());
+ fwd->pconnPush(serverConnectionSaved, request->url.host());
}
- serverConnection = NULL;
serverComplete();
return;
+ }
case COMPLETE_NONPERSISTENT_MSG:
debugs(11, 5, "processReplyBody: COMPLETE_NONPERSISTENT_MSG from " << serverConnection);
entry->mem_obj->checkUrlChecksum();
#endif
+ // XXX: Keep in sync with Client::sentRequestBody().
+ // TODO: Extract common parts.
+
if (io.size > 0) {
fd_bytes(io.fd, io.size, FD_WRITE);
statCounter.server.all.kbytes_out += io.size;
if (io.flag == Comm::ERR_CLOSING)
return;
+ // both successful and failed writes affect response times
+ request->hier.notePeerWrite();
+
if (io.flag) {
ErrorState *err = new ErrorState(ERR_WRITE_ERROR, Http::scBadGateway, fwd->request);
err->xerrno = io.xerrno;
commSetConnTimeout(serverConnection, Config.Timeout.read, timeoutCall);
flags.request_sent = true;
- request->hier.peer_http_request_sent = current_time;
}
void
}
}
- uint8_t loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
+ char loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
size_t blen;
struct base64_encode_ctx ctx;
base64_encode_init(&ctx);
/* append Authorization if known in URL, not in header and going direct */
if (!hdr_out->has(Http::HdrType::AUTHORIZATION)) {
if (!request->flags.proxying && !request->url.userInfo().isEmpty()) {
- static uint8_t result[base64_encode_len(MAX_URL*2)]; // should be big enough for a single URI segment
+ static char result[base64_encode_len(MAX_URL*2)]; // should be big enough for a single URI segment
struct base64_encode_ctx ctx;
base64_encode_init(&ctx);
size_t blen = base64_encode_update(&ctx, result, request->url.userInfo().length(), reinterpret_cast<const uint8_t*>(request->url.userInfo().rawContent()));
}
ACLFilledChecklist ch(Config.accessList.brokenPosts, originalRequest().getRaw());
- if (ch.fastCheck() != ACCESS_ALLOWED) {
+ ch.al = fwd->al;
+ ch.syncAle(originalRequest().getRaw(), nullptr);
+ if (!ch.fastCheck().allowed()) {
debugs(11, 5, HERE << "didn't match brokenPosts");
return false;
}