* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
-#include "config.h"
-
-/* for ClientActiveRequests global */
-#include "dlink.h"
-
-/* old includes without reasons given. */
#include "squid.h"
#include "acl/FilledChecklist.h"
#include "acl/Gadgets.h"
-#if USE_AUTH
-#include "auth/UserRequest.h"
-#endif
-#include "client_side.h"
+#include "anyp/PortCfg.h"
#include "client_side_reply.h"
+#include "client_side.h"
#include "clientStream.h"
-#if USE_DELAY_POOLS
-#include "DelayPools.h"
-#endif
+#include "dlink.h"
#include "errorpage.h"
-#if USE_SQUID_ESI
-#include "esi/Esi.h"
-#endif
#include "fde.h"
+#include "format/Token.h"
#include "forward.h"
+#include "globals.h"
+#include "globals.h"
#include "HttpReply.h"
#include "HttpRequest.h"
#include "ip/QosConfig.h"
#include "ipcache.h"
-#include "log/Tokens.h"
#include "MemObject.h"
-#include "ProtoPort.h"
+#include "protos.h"
#include "SquidTime.h"
-#include "StoreClient.h"
#include "Store.h"
+#include "StoreClient.h"
+#if USE_AUTH
+#include "auth/UserRequest.h"
+#endif
+#if USE_DELAY_POOLS
+#include "DelayPools.h"
+#endif
+#if USE_SQUID_ESI
+#include "esi/Esi.h"
+#endif
CBDATA_CLASS_INIT(clientReplyContext);
err_type err, http_status status, const HttpRequestMethod& method, char const *uri,
Ip::Address &addr, HttpRequest * failedrequest, const char *unparsedrequest,
#if USE_AUTH
- AuthUserRequest::Pointer auth_user_request
+ Auth::UserRequest::Pointer auth_user_request
#else
void*
#endif
if (unparsedrequest)
errstate->request_hdrs = xstrdup(unparsedrequest);
- if (status == HTTP_NOT_IMPLEMENTED && http->request)
+#if USE_AUTH
+ errstate->auth_user_request = auth_user_request;
+#endif
+ setReplyToError(method, errstate);
+}
+
+void clientReplyContext::setReplyToError(const HttpRequestMethod& method, ErrorState *errstate)
+{
+ if (errstate->httpStatus == HTTP_NOT_IMPLEMENTED && http->request)
/* prevent confusion over whether we default to persistent or not */
http->request->flags.proxy_keepalive = 0;
- http->al.http.code = errstate->httpStatus;
+ http->al->http.code = errstate->httpStatus;
createStoreEntry(method, request_flags());
-#if USE_AUTH
- errstate->auth_user_request = auth_user_request;
-#endif
assert(errstate->callback_data == NULL);
errorAppendEntry(http->storeEntry(), errstate);
/* Now the caller reads to get this */
}
+void clientReplyContext::setReplyToStoreEntry(StoreEntry *entry)
+{
+ entry->lock(); // removeClientStoreReference() unlocks
+ sc = storeClientListAdd(entry, this);
+#if USE_DELAY_POOLS
+ sc->setDelayId(DelayId::DelayClient(http));
+#endif
+ reqofs = 0;
+ reqsize = 0;
+ flags.storelogiccomplete = 1;
+ http->storeEntry(entry);
+}
+
void
clientReplyContext::removeStoreReference(store_client ** scp,
StoreEntry ** ep)
* this clientReplyContext does
*/
Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL;
- FwdState::fwdStart(conn, http->storeEntry(), http->request);
+ FwdState::Start(conn, http->storeEntry(), http->request, http->al);
/* Register with storage manager to receive updates when data comes in. */
if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
- debugs(88, 0, "clientReplyContext::processExpired: Found ENTRY_ABORTED object");
+ debugs(88, DBG_CRITICAL, "clientReplyContext::processExpired: Found ENTRY_ABORTED object");
{
/* start counting the length from 0 */
}
}
-
void
clientReplyContext::sendClientUpstreamResponse()
{
// origin replied 304
if (status == HTTP_NOT_MODIFIED) {
http->logType = LOG_TCP_REFRESH_UNMODIFIED;
+ http->request->flags.stale_if_hit = 0; // old_entry is no longer stale
// update headers on existing entry
old_rep->updateOnNotModified(http->storeEntry()->getReply());
assert(http->logType == LOG_TCP_HIT);
if (strcmp(e->mem_obj->url, urlCanonical(r)) != 0) {
- debugs(33, 1, "clientProcessHit: URL mismatch, '" << e->mem_obj->url << "' != '" << urlCanonical(r) << "'");
+ debugs(33, DBG_IMPORTANT, "clientProcessHit: URL mismatch, '" << e->mem_obj->url << "' != '" << urlCanonical(r) << "'");
processMiss();
return;
}
case VARY_CANCEL:
/* varyEvaluateMatch found a object loop. Process as miss */
- debugs(88, 1, "clientProcessHit: Vary object loop!");
+ debugs(88, DBG_IMPORTANT, "clientProcessHit: Vary object loop!");
processMiss();
return;
}
*/
if (http->storeEntry()) {
if (EBIT_TEST(http->storeEntry()->flags, ENTRY_SPECIAL)) {
- debugs(88, 0, "clientProcessMiss: miss on a special object (" << url << ").");
- debugs(88, 0, "\tlog_type = " << log_tags[http->logType]);
+ debugs(88, DBG_CRITICAL, "clientProcessMiss: miss on a special object (" << url << ").");
+ debugs(88, DBG_CRITICAL, "\tlog_type = " << Format::log_tags[http->logType]);
http->storeEntry()->dump(1);
}
/// Deny loops for accelerator and interceptor. TODO: deny in all modes?
if (r->flags.loopdetect &&
(http->flags.accel || http->flags.intercepted)) {
- http->al.http.code = HTTP_FORBIDDEN;
+ http->al->http.code = HTTP_FORBIDDEN;
err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->clientConnection->remote, http->request);
createStoreEntry(r->method, request_flags());
errorAppendEntry(http->storeEntry(), err);
if (http->redirect.status) {
HttpReply *rep = new HttpReply;
-#if LOG_TCP_REDIRECTS
-
http->logType = LOG_TCP_REDIRECT;
-#endif
-
http->storeEntry()->releaseRequest();
rep->redirect(http->redirect.status, http->redirect.location);
http->storeEntry()->replaceHttpReply(rep);
/** Start forwarding to get the new object from network */
Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL;
- FwdState::fwdStart(conn, http->storeEntry(), r);
+ FwdState::Start(conn, http->storeEntry(), r, http->al);
}
}
{
debugs(88, 4, "clientProcessOnlyIfCachedMiss: '" <<
RequestMethodStr(http->request->method) << " " << http->uri << "'");
- http->al.http.code = HTTP_GATEWAY_TIMEOUT;
+ http->al->http.code = HTTP_GATEWAY_TIMEOUT;
ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT, NULL,
http->getConn()->clientConnection->remote, http->request);
removeClientStoreReference(&sc, http);
int
clientReplyContext::storeOKTransferDone() const
{
+ assert(http->storeEntry()->objectLen() >= 0);
+ assert(http->storeEntry()->objectLen() >= headers_sz);
if (http->out.offset >= http->storeEntry()->objectLen() - headers_sz) {
debugs(88,3,HERE << "storeOKTransferDone " <<
" out.offset=" << http->out.offset <<
}
}
-
/* A write has completed, what is the next status based on the
* canonical request data?
* 1 something is wrong
{
#if SIZEOF_INT64_T == 4
if (http->out.size > 0x7FFF0000) {
- debugs(88, 1, "WARNING: closing FD " << fd << " to prevent out.size counter overflow");
- debugs(88, 1, "\tclient " << http->getConn()->peer);
- debugs(88, 1, "\treceived " << http->out.size << " bytes");
- debugs(88, 1, "\tURI " << http->log_uri);
+ debugs(88, DBG_IMPORTANT, "WARNING: closing FD " << fd << " to prevent out.size counter overflow");
+ debugs(88, DBG_IMPORTANT, "\tclient " << http->getConn()->peer);
+ debugs(88, DBG_IMPORTANT, "\treceived " << http->out.size << " bytes");
+ debugs(88, DBG_IMPORTANT, "\tURI " << http->log_uri);
return 1;
}
if (http->out.offset > 0x7FFF0000) {
- debugs(88, 1, "WARNING: closing FD " << fd < " to prevent out.offset counter overflow");
- debugs(88, 1, "\tclient " << http->getConn()->peer);
- debugs(88, 1, "\treceived " << http->out.size << " bytes, offset " << http->out.offset);
- debugs(88, 1, "\tURI " << http->log_uri);
+ debugs(88, DBG_IMPORTANT, "WARNING: closing FD " << fd < " to prevent out.offset counter overflow");
+ debugs(88, DBG_IMPORTANT, "\tclient " << http->getConn()->peer);
+ debugs(88, DBG_IMPORTANT, "\treceived " << http->out.size << " bytes, offset " << http->out.offset);
+ debugs(88, DBG_IMPORTANT, "\tURI " << http->log_uri);
return 1;
}
hdr->insertTime(HDR_DATE, squid_curtime);
} else if (http->getConn() && http->getConn()->port->actAsOrigin) {
// Swap the Date: header to current time if we are simulating an origin
- HttpHeaderEntry *h = hdr->findEntry(HDR_DATE);
- if (h)
- hdr->putExt("X-Origin-Date", h->value.termedBuf());
+ HttpHeaderEntry *h = hdr->findEntry(HDR_DATE);
+ if (h)
+ hdr->putExt("X-Origin-Date", h->value.termedBuf());
hdr->delById(HDR_DATE);
hdr->insertTime(HDR_DATE, squid_curtime);
- h = hdr->findEntry(HDR_EXPIRES);
- if (h && http->storeEntry()->expires >= 0) {
- hdr->putExt("X-Origin-Expires", h->value.termedBuf());
- hdr->delById(HDR_EXPIRES);
- hdr->insertTime(HDR_EXPIRES, squid_curtime + http->storeEntry()->expires - http->storeEntry()->timestamp);
- }
+ h = hdr->findEntry(HDR_EXPIRES);
+ if (h && http->storeEntry()->expires >= 0) {
+ hdr->putExt("X-Origin-Expires", h->value.termedBuf());
+ hdr->delById(HDR_EXPIRES);
+ hdr->insertTime(HDR_EXPIRES, squid_curtime + http->storeEntry()->expires - http->storeEntry()->timestamp);
+ }
if (http->storeEntry()->timestamp <= squid_curtime) {
// put X-Cache-Age: instead of Age:
- char age[64];
- snprintf(age, sizeof(age), "%ld", (long int) squid_curtime - http->storeEntry()->timestamp);
- hdr->putExt("X-Cache-Age", age);
- }
+ char age[64];
+ snprintf(age, sizeof(age), "%ld", (long int) squid_curtime - http->storeEntry()->timestamp);
+ hdr->putExt("X-Cache-Age", age);
+ }
} else if (http->storeEntry()->timestamp <= squid_curtime) {
hdr->putInt(HDR_AGE,
squid_curtime - http->storeEntry()->timestamp);
#endif
const bool maySendChunkedReply = !request->multipartRangeRequest() &&
+ reply->sline.protocol == AnyP::PROTO_HTTP && // response is HTTP
(request->http_ver >= HttpVersion(1, 1));
/* Check whether we should send keep-alive */
} else if (fdUsageHigh()&& !request->flags.must_keepalive) {
debugs(88, 3, "clientBuildReplyHeader: Not many unused FDs, can't keep-alive");
request->flags.proxy_keepalive = 0;
+ } else if (request->flags.sslBumped && !reply->persistent()) {
+ // We do not really have to close, but we pretend we are a tunnel.
+ debugs(88, 3, "clientBuildReplyHeader: bumped reply forces close");
+ request->flags.proxy_keepalive = 0;
}
// Decide if we send chunked reply
httpHdrMangleList(hdr, request, ROR_REPLY);
}
-
void
clientReplyContext::cloneReply()
{
*/
if (r->flags.nocache) {
-#if USE_DNSSERVERS
-
+#if USE_DNSHELPER
ipcacheInvalidate(r->GetHost());
-
#else
-
ipcacheInvalidateNegative(r->GetHost());
-
-#endif /* USE_DNSSERVERS */
+#endif /* USE_DNSHELPER */
}
else if (r->flags.nocache_hack) {
-#if USE_DNSSERVERS
-
+#if USE_DNSHELPER
ipcacheInvalidate(r->GetHost());
-
#else
-
ipcacheInvalidateNegative(r->GetHost());
-
-#endif /* USE_DNSSERVERS */
+#endif /* USE_DNSHELPER */
}
if (http->redirect.status) {
/** \li If redirection status is True force this to be a MISS */
- debugs(85, 3, "clientProcessRequest2: redirectStatus forced StoreEntry to NULL - MISS");
+ debugs(85, 3, HERE << "REDIRECT status forced StoreEntry to NULL (no body on 3XX responses)");
http->storeEntry(NULL);
- http->logType = LOG_TCP_MISS;
+ http->logType = LOG_TCP_REDIRECT;
doGetMoreData();
return;
}
assert (context);
assert(context->http == http);
-
clientStreamNode *next = ( clientStreamNode *)aNode->node.next->data;
if (!context->ourNode)
http->logType == LOG_TCP_DENIED_REPLY ||
alwaysAllowResponse(reply->sline.status)) {
headers_sz = reply->hdr_sz;
- processReplyAccessResult(1);
+ processReplyAccessResult(ACCESS_ALLOWED);
return;
}
/** check for absent access controls (permit by default) */
if (!Config.accessList.reply) {
- processReplyAccessResult(1);
+ processReplyAccessResult(ACCESS_ALLOWED);
return;
}
}
void
-clientReplyContext::ProcessReplyAccessResult (int rv, void *voidMe)
+clientReplyContext::ProcessReplyAccessResult(allow_t rv, void *voidMe)
{
clientReplyContext *me = static_cast<clientReplyContext *>(voidMe);
me->processReplyAccessResult(rv);
}
void
-clientReplyContext::processReplyAccessResult(bool accessAllowed)
+clientReplyContext::processReplyAccessResult(const allow_t &accessAllowed)
{
debugs(88, 2, "The reply for " << RequestMethodStr(http->request->method)
- << " " << http->uri << " is "
- << ( accessAllowed ? "ALLOWED" : "DENIED")
- << ", because it matched '"
+ << " " << http->uri << " is " << accessAllowed << ", because it matched '"
<< (AclMatchedName ? AclMatchedName : "NO ACL's") << "'" );
- if (!accessAllowed) {
+ if (accessAllowed != ACCESS_ALLOWED) {
ErrorState *err;
err_type page_id;
page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName, 1);
startError(err);
-
return;
}
ConnStateData * conn = http->getConn();
- // AYJ: this seems a bit weird to ignore CLOSED but drop on closing.
- if (conn != NULL && Comm::IsConnOpen(conn->clientConnection) && fd_table[conn->clientConnection->fd].closing()) {
+ if (conn == NULL || !conn->isOpen()) {
// too late, our conn is closing
// TODO: should we also quit?
debugs(33,3, HERE << "not sending more data to a closing " << conn->clientConnection);
size_t k;
if ((k = headersEnd(buf, reqofs))) {
- safe_free(http->al.headers.reply);
- http->al.headers.reply = (char *)xcalloc(k + 1, 1);
- xstrncpy(http->al.headers.reply, buf, k);
+ safe_free(http->al->headers.reply);
+ http->al->headers.reply = (char *)xcalloc(k + 1, 1);
+ xstrncpy(http->al->headers.reply, buf, k);
}
}
return;
}
-
-
/* Using this breaks the client layering just a little!
*/
void
clientBuildError(err_type page_id, http_status status, char const *url,
Ip::Address &src_addr, HttpRequest * request)
{
- ErrorState *err = errorCon(page_id, status, request);
+ ErrorState *err = new ErrorState(page_id, status, request);
err->src_addr = src_addr;
if (url)