ICPState(icp_common_t &aHeader, HttpRequest *aRequest);
virtual ~ICPState();
+ /// whether the cache contains the requested entry
+ bool isHit() const;
+
icp_common_t header;
HttpRequest *request;
int fd;
Ip::Address from;
char *url;
+ mutable AccessLogEntryPointer al;
protected:
/* StoreClient API */
- virtual LogTags *loggingTags() override;
+ virtual LogTags *loggingTags() const override;
virtual void fillChecklist(ACLFilledChecklist &) const override;
/// either confirms and starts processing a cache hit or returns false
- bool confirmAndPrepHit(const StoreEntry &);
-
- mutable AccessLogEntryPointer al;
+ bool confirmAndPrepHit(const StoreEntry &) const;
};
extern Comm::ConnectionPointer icpIncomingConn;
public:
static size_t inUseCount();
- static void getPublicByRequestMethod(StoreClient * aClient, HttpRequest * request, const HttpRequestMethod& method);
- static void getPublicByRequest(StoreClient * aClient, HttpRequest * request);
- static void getPublic(StoreClient * aClient, const char *uri, const HttpRequestMethod& method);
void *operator new(size_t byteCount);
void operator delete(void *address);
class ACLFilledChecklist;
class LogTags;
-/// A StoreEntry::getPublic*() caller.
+/// a storeGetPublic*() caller
class StoreClient
{
public:
virtual ~StoreClient () {}
- // TODO: Remove? Probably added to make lookups asynchronous, but they are
- // still blocking. A lot more is needed to support async callbacks.
- /// Handle a StoreEntry::getPublic*() result.
- /// A nil entry indicates a cache miss.
- virtual void created(StoreEntry *) = 0;
-
/// \return LogTags (if the class logs transactions) or nil (otherwise)
- virtual LogTags *loggingTags() = 0;
+ virtual LogTags *loggingTags() const = 0;
protected:
/// configure the ACL checklist with the current transaction state
/// \returns whether the caller must collapse on the given entry
/// Before returning true, updates common collapsing-related stats.
/// See also: StoreEntry::hittingRequiresCollapsing().
- bool startCollapsingOn(const StoreEntry &, const bool doingRevalidation);
+ bool startCollapsingOn(const StoreEntry &, const bool doingRevalidation) const;
// These methods only interpret Squid configuration. Their allowances are
// provisional -- other factors may prevent collapsed forwarding. The first
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
repContext->setReplyToError(ERR_UNSUP_REQ, Http::scNotImplemented, request->method, NULL,
- conn->clientConnection->remote, request.getRaw(), NULL, NULL);
+ conn, request.getRaw(), nullptr, nullptr);
assert(context->http->out.offset == 0);
context->pullData();
clientProcessRequestFinished(conn, request);
conn->quitAfterError(request.getRaw());
repContext->setReplyToError(ERR_INVALID_REQ,
Http::scLengthRequired, request->method, NULL,
- conn->clientConnection->remote, request.getRaw(), NULL, NULL);
+ conn, request.getRaw(), nullptr, nullptr);
assert(context->http->out.offset == 0);
context->pullData();
clientProcessRequestFinished(conn, request);
conn->quitAfterError(request.getRaw());
repContext->setReplyToError(ERR_TOO_BIG,
Http::scPayloadTooLarge, Http::METHOD_NONE, NULL,
- conn->clientConnection->remote, http->request, NULL, NULL);
+ conn, http->request, nullptr, nullptr);
assert(context->http->out.offset == 0);
context->pullData();
clientProcessRequestFinished(conn, request);
/* Local functions */
extern "C" CSS clientReplyStatus;
-ErrorState *clientBuildError(err_type, Http::StatusCode, char const *, Ip::Address &, HttpRequest *, const AccessLogEntry::Pointer &);
+ErrorState *clientBuildError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const AccessLogEntry::Pointer &);
/* privates */
clientReplyContext::clientReplyContext(ClientHttpRequest *clientContext) :
purgeStatus(Http::scNone),
- lookingforstore(0),
http(cbdataReference(clientContext)),
headers_sz(0),
sc(NULL),
void
clientReplyContext::setReplyToError(
err_type err, Http::StatusCode status, const HttpRequestMethod& method, char const *uri,
- Ip::Address &addr, HttpRequest * failedrequest, const char *unparsedrequest,
+ const ConnStateData *conn, HttpRequest *failedrequest, const char *unparsedrequest,
#if USE_AUTH
Auth::UserRequest::Pointer auth_user_request
#else
#endif
)
{
- auto errstate = clientBuildError(err, status, uri, addr, failedrequest, http->al);
+ auto errstate = clientBuildError(err, status, uri, conn, failedrequest, http->al);
if (unparsedrequest)
errstate->request_hdrs = xstrdup(unparsedrequest);
return;
}
- Comm::ConnectionPointer conn = http->getConn() != nullptr ? http->getConn()->clientConnection : nullptr;
/// Deny loops
if (r->flags.loopDetected) {
http->al->http.code = Http::scForbidden;
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr();
- err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, nullptr, conn ? conn->remote : tmp_noaddr, http->request, http->al);
+ err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, nullptr, http->getConn(), http->request, http->al);
createStoreEntry(r->method, RequestFlags());
errorAppendEntry(http->storeEntry(), err);
triggerInitialStoreRead();
assert(r->clientConnectionManager == http->getConn());
+ Comm::ConnectionPointer conn = http->getConn() != nullptr ? http->getConn()->clientConnection : nullptr;
/** Start forwarding to get the new object from network */
FwdState::Start(conn, http->storeEntry(), r, http->al);
}
{
debugs(88, 4, http->request->method << ' ' << http->uri);
http->al->http.code = Http::scGatewayTimeout;
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr();
ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, Http::scGatewayTimeout, NULL,
- http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr,
- http->request, http->al);
+ http->getConn(), http->request, http->al);
removeClientStoreReference(&sc, http);
startError(err);
}
}
}
-void
-clientReplyContext::purgeRequestFindObjectToPurge()
-{
- /* Try to find a base entry */
- http->flags.purging = true;
- lookingforstore = 1;
-
- // TODO: can we use purgeAllCached() here instead of doing the
- // getPublicByRequestMethod() dance?
- StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_GET);
-}
-
// Purges all entries with a given url
// TODO: move to SideAgent parent, when we have one
/*
purgeEntriesByUrl(http->request, url.c_str());
}
-void
-clientReplyContext::created(StoreEntry *newEntry)
-{
- detailStoreLookup(newEntry ? "match" : "mismatch");
-
- if (lookingforstore == 1)
- purgeFoundGet(newEntry);
- else if (lookingforstore == 2)
- purgeFoundHead(newEntry);
- else if (lookingforstore == 3)
- purgeDoPurgeGet(newEntry);
- else if (lookingforstore == 4)
- purgeDoPurgeHead(newEntry);
- else if (lookingforstore == 5)
- identifyFoundObject(newEntry);
-}
-
LogTags *
-clientReplyContext::loggingTags()
+clientReplyContext::loggingTags() const
{
// XXX: clientReplyContext code assumes that http cbdata is always valid.
// TODO: Either add cbdataReferenceValid(http) checks in all the relevant
return &http->logType;
}
-void
-clientReplyContext::purgeFoundGet(StoreEntry *newEntry)
-{
- if (!newEntry) {
- lookingforstore = 2;
- StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_HEAD);
- } else
- purgeFoundObject (newEntry);
-}
-
-void
-clientReplyContext::purgeFoundHead(StoreEntry *newEntry)
-{
- if (!newEntry)
- purgeDoMissPurge();
- else
- purgeFoundObject (newEntry);
-}
-
-void
-clientReplyContext::purgeFoundObject(StoreEntry *entry)
-{
- assert (entry);
-
- if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) {
- http->logType.update(LOG_TCP_DENIED);
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr(); // TODO: make a global const
- ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL,
- http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr,
- http->request, http->al);
- startError(err);
- return; // XXX: leaking unused entry if some store does not keep it
- }
-
- StoreIOBuffer localTempBuffer;
- /* Swap in the metadata */
- http->storeEntry(entry);
-
- http->storeEntry()->lock("clientReplyContext::purgeFoundObject");
- http->storeEntry()->ensureMemObject(storeId(), http->log_uri,
- http->request->method);
-
- sc = storeClientListAdd(http->storeEntry(), this);
-
- http->logType.update(LOG_TCP_HIT);
-
- reqofs = 0;
-
- localTempBuffer.offset = http->out.offset;
-
- localTempBuffer.length = next()->readBuffer.length;
-
- localTempBuffer.data = next()->readBuffer.data;
-
- storeClientCopy(sc, http->storeEntry(),
- localTempBuffer, CacheHit, this);
-}
-
void
clientReplyContext::purgeRequest()
{
if (!Config2.onoff.enable_purge) {
http->logType.update(LOG_TCP_DENIED);
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr();
ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL,
- http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr, http->request, http->al);
+ http->getConn(), http->request, http->al);
startError(err);
return;
}
/* Release both IP cache */
ipcacheInvalidate(http->request->url.host());
- if (!http->flags.purging)
- purgeRequestFindObjectToPurge();
- else
- purgeDoMissPurge();
-}
-
-void
-clientReplyContext::purgeDoMissPurge()
-{
- http->logType.update(LOG_TCP_MISS);
- lookingforstore = 3;
- StoreEntry::getPublicByRequestMethod(this,http->request, Http::METHOD_GET);
+ // TODO: can we use purgeAllCached() here instead?
+ purgeDoPurge();
}
void
-clientReplyContext::purgeDoPurgeGet(StoreEntry *newEntry)
-{
- if (newEntry) {
- /* Release the cached URI */
- debugs(88, 4, "clientPurgeRequest: GET '" << newEntry->url() << "'" );
-#if USE_HTCP
- neighborsHtcpClear(newEntry, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE);
-#endif
- newEntry->release(true);
- purgeStatus = Http::scOkay;
+clientReplyContext::purgeDoPurge()
+{
+ auto firstFound = false;
+ if (const auto entry = storeGetPublicByRequestMethod(http->request, Http::METHOD_GET)) {
+ // special entries are only METHOD_GET entries without variance
+ if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) {
+ http->logType.update(LOG_TCP_DENIED);
+ const auto err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, nullptr,
+ http->getConn(), http->request, http->al);
+ startError(err);
+ entry->abandon(__FUNCTION__);
+ return;
+ }
+ firstFound = true;
+ if (!purgeEntry(*entry, Http::METHOD_GET))
+ return;
}
- lookingforstore = 4;
- StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_HEAD);
-}
+ detailStoreLookup(storeLookupString(firstFound));
-void
-clientReplyContext::purgeDoPurgeHead(StoreEntry *newEntry)
-{
- if (newEntry) {
- debugs(88, 4, "HEAD " << newEntry->url());
-#if USE_HTCP
- neighborsHtcpClear(newEntry, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE);
-#endif
- newEntry->release(true);
- purgeStatus = Http::scOkay;
+ if (const auto entry = storeGetPublicByRequestMethod(http->request, Http::METHOD_HEAD)) {
+ if (!purgeEntry(*entry, Http::METHOD_HEAD))
+ return;
}
/* And for Vary, release the base URI if none of the headers was included in the request */
&& http->request->vary_headers.find('=') != SBuf::npos) {
// XXX: performance regression, c_str() reallocates
SBuf tmp(http->request->effectiveRequestUri());
- StoreEntry *entry = storeGetPublic(tmp.c_str(), Http::METHOD_GET);
- if (entry) {
- debugs(88, 4, "Vary GET " << entry->url());
-#if USE_HTCP
- neighborsHtcpClear(entry, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE);
-#endif
- entry->release(true);
- purgeStatus = Http::scOkay;
+ if (const auto entry = storeGetPublic(tmp.c_str(), Http::METHOD_GET)) {
+ if (!purgeEntry(*entry, Http::METHOD_GET, "Vary "))
+ return;
}
- entry = storeGetPublic(tmp.c_str(), Http::METHOD_HEAD);
-
- if (entry) {
- debugs(88, 4, "Vary HEAD " << entry->url());
-#if USE_HTCP
- neighborsHtcpClear(entry, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE);
-#endif
- entry->release(true);
- purgeStatus = Http::scOkay;
+ if (const auto entry = storeGetPublic(tmp.c_str(), Http::METHOD_HEAD)) {
+ if (!purgeEntry(*entry, Http::METHOD_HEAD, "Vary "))
+ return;
}
}
http->storeEntry()->complete();
}
+bool
+clientReplyContext::purgeEntry(StoreEntry &entry, const Http::MethodType methodType, const char *descriptionPrefix)
+{
+ debugs(88, 4, descriptionPrefix << Http::MethodStr(methodType) << " '" << entry.url() << "'" );
+#if USE_HTCP
+ neighborsHtcpClear(&entry, http->request, HttpRequestMethod(methodType), HTCP_CLR_PURGE);
+#endif
+ entry.release(true);
+ purgeStatus = Http::scOkay;
+ return true;
+}
+
void
clientReplyContext::traceReply(clientStreamNode * node)
{
// client sent CC:no-cache or some other condition has been
// encountered which prevents delivering a public/cached object.
if (!r->flags.noCache || r->flags.internal) {
- lookingforstore = 5;
- StoreEntry::getPublicByRequest (this, r);
+ const auto e = storeGetPublicByRequest(r);
+ identifyFoundObject(e, storeLookupString(bool(e)));
} else {
// "external" no-cache requests skip Store lookups
- detailStoreLookup("no-cache");
- identifyFoundObject(nullptr);
+ identifyFoundObject(nullptr, "no-cache");
}
}
* to see if we can determine the final status of the request.
*/
void
-clientReplyContext::identifyFoundObject(StoreEntry *newEntry)
+clientReplyContext::identifyFoundObject(StoreEntry *newEntry, const char *detail)
{
+ detailStoreLookup(detail);
+
HttpRequest *r = http->request;
http->storeEntry(newEntry);
const auto e = http->storeEntry();
void
clientReplyContext::sendBodyTooLargeError()
{
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr(); // TODO: make a global const
http->logType.update(LOG_TCP_DENIED_REPLY);
ErrorState *err = clientBuildError(ERR_TOO_BIG, Http::scForbidden, NULL,
- http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmp_noaddr,
- http->request, http->al);
+ http->getConn(), http->request, http->al);
removeClientStoreReference(&(sc), http);
HTTPMSGUNLOCK(reply);
startError(err);
clientReplyContext::sendPreconditionFailedError()
{
http->logType.update(LOG_TCP_HIT);
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr();
ErrorState *const err =
clientBuildError(ERR_PRECONDITION_FAILED, Http::scPreconditionFailed,
- NULL, http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr, http->request, http->al);
+ nullptr, http->getConn(), http->request, http->al);
removeClientStoreReference(&sc, http);
HTTPMSGUNLOCK(reply);
startError(err);
if (page_id == ERR_NONE)
page_id = ERR_ACCESS_DENIED;
- Ip::Address tmp_noaddr;
- tmp_noaddr.setNoAddr();
err = clientBuildError(page_id, Http::scForbidden, NULL,
- http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmp_noaddr,
- http->request, http->al);
+ http->getConn(), http->request, http->al);
removeClientStoreReference(&sc, http);
ErrorState *
clientBuildError(err_type page_id, Http::StatusCode status, char const *url,
- Ip::Address &src_addr, HttpRequest * request, const AccessLogEntry::Pointer &al)
+ const ConnStateData *conn, HttpRequest *request, const AccessLogEntry::Pointer &al)
{
const auto err = new ErrorState(page_id, status, request, al);
- err->src_addr = src_addr;
+ err->src_addr = conn && conn->clientConnection ? conn->clientConnection->remote : Ip::Address::NoAddr();
if (url)
err->url = xstrdup(url);
void saveState();
void restoreState();
void purgeRequest ();
- void purgeRequestFindObjectToPurge();
- void purgeDoMissPurge();
- void purgeFoundGet(StoreEntry *newEntry);
- void purgeFoundHead(StoreEntry *newEntry);
- void purgeFoundObject(StoreEntry *entry);
void sendClientUpstreamResponse();
- void purgeDoPurgeGet(StoreEntry *entry);
- void purgeDoPurgeHead(StoreEntry *entry);
void doGetMoreData();
void identifyStoreObject();
- void identifyFoundObject(StoreEntry *entry);
+ void identifyFoundObject(StoreEntry *entry, const char *detail);
int storeOKTransferDone() const;
int storeNotOKTransferDone() const;
/// replaces current response store entry with the given one
void setReplyToStoreEntry(StoreEntry *e, const char *reason);
/// builds error using clientBuildError() and calls setReplyToError() below
- void setReplyToError(err_type, Http::StatusCode, const HttpRequestMethod&, char const *, Ip::Address &, HttpRequest *, const char *,
+ void setReplyToError(err_type, Http::StatusCode, const HttpRequestMethod&, char const *, const ConnStateData *, HttpRequest *, const char *,
#if USE_AUTH
Auth::UserRequest::Pointer);
#else
Http::StatusCode purgeStatus;
- /* state variable - replace with class to handle storeentries at some point */
- int lookingforstore;
-
/* StoreClient API */
- virtual void created (StoreEntry *newEntry);
- virtual LogTags *loggingTags();
+ virtual LogTags *loggingTags() const;
ClientHttpRequest *http;
/// Base reply header bytes received from Store.
void triggerInitialStoreRead();
void sendClientOldEntry();
void purgeAllCached();
+ /// attempts to release the cached entry
+ /// \returns whether the entry was released
+ bool purgeEntry(StoreEntry &, const Http::MethodType, const char *descriptionPrefix = "");
+ /// releases both cached GET and HEAD entries
+ void purgeDoPurge();
void forgetHit();
bool blockedHit() const;
+ const char *storeLookupString(bool found) const { return found ? "match" : "mismatch"; }
void detailStoreLookup(const char *detail);
void sendBodyTooLargeError();
static void clientFollowXForwardedForCheck(Acl::Answer answer, void *data);
#endif /* FOLLOW_X_FORWARDED_FOR */
-ErrorState *clientBuildError(err_type, Http::StatusCode, char const *url, Ip::Address &, HttpRequest *, const AccessLogEntry::Pointer &);
+ErrorState *clientBuildError(err_type, Http::StatusCode, char const *url, const ConnStateData *, HttpRequest *, const AccessLogEntry::Pointer &);
CBDATA_CLASS_INIT(ClientRequestContext);
assert (repContext);
repContext->setReplyToError(ERR_CONFLICT_HOST, Http::scConflict,
http->request->method, NULL,
- http->getConn()->clientConnection->remote,
+ http->getConn(),
http->request,
NULL,
#if USE_AUTH
page_id = ERR_ACCESS_DENIED;
}
- Ip::Address tmpnoaddr;
- tmpnoaddr.setNoAddr();
- error = clientBuildError(page_id, status,
- NULL,
- http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmpnoaddr,
- http->request, http->al
- );
+ error = clientBuildError(page_id, status, nullptr, http->getConn(), http->request, http->al);
#if USE_AUTH
error->auth_user_request =
// setReplyToError, but it seems unlikely that the errno reflects the
// true cause of the error at this point, so I did not pass it.
if (calloutContext) {
- Ip::Address noAddr;
- noAddr.setNoAddr();
ConnStateData * c = getConn();
calloutContext->error = clientBuildError(error, Http::scInternalServerError,
- NULL,
- c != NULL ? c->clientConnection->remote : noAddr,
- request,
- al
- );
+ nullptr, c, request, al);
#if USE_AUTH
calloutContext->error->auth_user_request =
c != NULL && c->getAuth() != NULL ? c->getAuth() : request->auth_user_request;
AccessLogEntry::Pointer al; ///< access.log entry
struct Flags {
- Flags() : accel(false), internal(false), done_copying(false), purging(false) {}
+ Flags() : accel(false), internal(false), done_copying(false) {}
bool accel;
bool internal;
bool done_copying;
- bool purging;
} flags;
struct Redirect {
/* don't touch incoming, it's a pointer into buffered anyway */
}
-ErrorState *clientBuildError(err_type, Http::StatusCode, char const *, Ip::Address &, HttpRequest *, const AccessLogEntry::Pointer &);
+ErrorState *clientBuildError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const AccessLogEntry::Pointer &);
/* This can ONLY be used before we have sent *any* data to the client */
void
flags.error = 1;
/* create an error object */
// XXX: with the in-direction on remote IP. does the http->getConn()->clientConnection exist?
- const auto err = clientBuildError(errorpage, errorstatus, nullptr, http->getConn()->clientConnection->remote, http->request, http->al);
+ const auto err = clientBuildError(errorpage, errorstatus, nullptr, http->getConn(), http->request, http->al);
err->err_msg = errormessage;
errormessage = NULL;
rep = err->BuildHttpReply();
virtual std::ostream &detailCodeContext(std::ostream &os) const; // override
/* StoreClient API */
- void created(StoreEntry *);
- virtual LogTags *loggingTags();
+ virtual LogTags *loggingTags() const;
virtual void fillChecklist(ACLFilledChecklist &) const;
public:
return;
}
- StoreEntry::getPublicByRequest(this, checkHitRequest.getRaw());
-}
-
-void
-htcpSpecifier::created(StoreEntry *e)
-{
+ const auto e = storeGetPublicByRequest(checkHitRequest.getRaw());
StoreEntry *hit = nullptr;
if (!e) {
- debugs(31, 3, "htcpCheckHit: NO; public object not found");
+ debugs(31, 3, "NO; public object not found");
} else if (!e->validToSend()) {
- debugs(31, 3, "htcpCheckHit: NO; entry not valid to send" );
+ debugs(31, 3, "NO; entry not valid to send" );
} else if (refreshCheckHTCP(e, checkHitRequest.getRaw())) {
- debugs(31, 3, "htcpCheckHit: NO; cached response is stale");
+ debugs(31, 3, "NO; cached response is stale");
} else if (e->hittingRequiresCollapsing() && !startCollapsingOn(*e, false)) {
- debugs(31, 3, "htcpCheckHit: NO; prohibited CF hit: " << *e);
+ debugs(31, 3, "NO; prohibited CF hit: " << *e);
} else {
- debugs(31, 3, "htcpCheckHit: YES!?");
+ debugs(31, 3, "YES!?");
hit = e;
}
}
LogTags *
-htcpSpecifier::loggingTags()
+htcpSpecifier::loggingTags() const
{
// calling htcpSyncAle() here would not change cache.code
if (!al)
}
bool
-ICPState::confirmAndPrepHit(const StoreEntry &e)
+ICPState::isHit() const
+{
+ const auto e = storeGetPublic(url, Http::METHOD_GET);
+
+ const auto hit = e && confirmAndPrepHit(*e);
+
+ if (e)
+ e->abandon(__FUNCTION__);
+
+ return hit;
+}
+
+bool
+ICPState::confirmAndPrepHit(const StoreEntry &e) const
{
if (!e.validToSend())
return false;
}
LogTags *
-ICPState::loggingTags()
+ICPState::loggingTags() const
{
// calling icpSyncAle(LOG_TAG_NONE) here would not change cache.code
if (!al)
ICPState(aHeader, aRequest),rtt(0),src_rtt(0),flags(0) {}
~ICP2State();
- virtual void created(StoreEntry * newEntry) override;
int rtt;
int src_rtt;
ICP2State::~ICP2State()
{}
-void
-ICP2State::created(StoreEntry *e)
-{
- debugs(12, 5, "icpHandleIcpV2: OPCODE " << icp_opcode_str[header.opcode]);
- icp_opcode codeToSend;
-
- if (e && confirmAndPrepHit(*e)) {
- codeToSend = ICP_HIT;
- } else {
-#if USE_ICMP
- if (Config.onoff.test_reachability && rtt == 0) {
- if ((rtt = netdbHostRtt(request->url.host())) == 0)
- netdbPingSite(request->url.host());
- }
-#endif /* USE_ICMP */
-
- if (icpGetCommonOpcode() != ICP_ERR)
- codeToSend = icpGetCommonOpcode();
- else if (Config.onoff.test_reachability && rtt == 0)
- codeToSend = ICP_MISS_NOFETCH;
- else
- codeToSend = ICP_MISS;
- }
-
- icpCreateAndSend(codeToSend, flags, url, header.reqnum, src_rtt, fd, from, al);
-
- // TODO: StoreClients must either store/lock or abandon found entries.
- //if (e)
- // e->abandon();
-
- delete this;
-}
-
/* End ICP2State */
/// updates ALE (if any) and logs the transaction (if needed)
#endif /* USE_ICMP */
/* The peer is allowed to use this cache */
- ICP2State *state = new ICP2State(header, icp_request);
- state->fd = fd;
- state->from = from;
- state->url = xstrdup(url);
- state->flags = flags;
- state->rtt = rtt;
- state->src_rtt = src_rtt;
+ ICP2State state(header, icp_request);
+ state.fd = fd;
+ state.from = from;
+ state.url = xstrdup(url);
+ state.flags = flags;
+ state.rtt = rtt;
+ state.src_rtt = src_rtt;
- StoreEntry::getPublic(state, url, Http::METHOD_GET);
+ icp_opcode codeToSend;
+
+ if (state.isHit()) {
+ codeToSend = ICP_HIT;
+ } else {
+#if USE_ICMP
+ if (Config.onoff.test_reachability && state.rtt == 0) {
+ if ((state.rtt = netdbHostRtt(state.request->url.host())) == 0)
+ netdbPingSite(state.request->url.host());
+ }
+#endif /* USE_ICMP */
+
+ if (icpGetCommonOpcode() != ICP_ERR)
+ codeToSend = icpGetCommonOpcode();
+ else if (Config.onoff.test_reachability && rtt == 0)
+ codeToSend = ICP_MISS_NOFETCH;
+ else
+ codeToSend = ICP_MISS;
+ }
+
+ icpCreateAndSend(codeToSend, flags, url, header.reqnum, src_rtt, fd, from, state.al);
HTTPMSGUNLOCK(icp_request);
}
return;
}
+ debugs(12, 5, "OPCODE " << icp_opcode_str[header.getOpCode()] << '=' << uint8_t(header.opcode));
+
switch (header.opcode) {
case ICP_QUERY:
ICP3State(icp_common_t &aHeader, HttpRequest *aRequest) :
ICPState(aHeader, aRequest) {}
- ~ICP3State();
- void created (StoreEntry *newEntry);
+ ~ICP3State() = default;
};
/// \ingroup ServerProtocolICPInternal3
}
/* The peer is allowed to use this cache */
- ICP3State *state = new ICP3State (header, icp_request);
- state->fd = fd;
- state->from = from;
- state->url = xstrdup(url);
+ ICP3State state(header, icp_request);
+ state.fd = fd;
+ state.from = from;
+ state.url = xstrdup(url);
- StoreEntry::getPublic (state, url, Http::METHOD_GET);
-}
-
-ICP3State::~ICP3State()
-{}
-
-void
-ICP3State::created(StoreEntry *e)
-{
- debugs(12, 5, "icpHandleIcpV3: OPCODE " << icp_opcode_str[header.opcode]);
icp_opcode codeToSend;
- if (e && confirmAndPrepHit(*e)) {
+ if (state.isHit()) {
codeToSend = ICP_HIT;
} else if (icpGetCommonOpcode() == ICP_ERR)
codeToSend = ICP_MISS;
else
codeToSend = icpGetCommonOpcode();
- icpCreateAndSend(codeToSend, 0, url, header.reqnum, 0, fd, from, al);
-
- // TODO: StoreClients must either store/lock or abandon found entries.
- //if (e)
- // e->abandon();
-
- delete this;
+ icpCreateAndSend(codeToSend, 0, url, header.reqnum, 0, fd, from, state.al);
}
/// \ingroup ServerProtocolICPInternal3
return;
}
+ debugs(12, 5, "OPCODE " << icp_opcode_str[header.getOpCode()] << '=' << uint8_t(header.opcode));
+
switch (header.opcode) {
case ICP_QUERY:
*/
bool GetHostByName(const char *s);
+ /// \returns an Address with true isNoAddr()
+ /// \see isNoAddr() for more details
+ static const Address &NoAddr() { static const Address noAddr(v6_noaddr); return noAddr; }
+
public:
/* XXX: When C => C++ conversion is done will be fully private.
* Legacy Transition Methods.
void load();
/* StoreClient API */
- virtual void created(StoreEntry *);
- virtual LogTags *loggingTags() { return nullptr; } // no access logging/ACLs
+ virtual LogTags *loggingTags() const { return nullptr; } // no access logging/ACLs
virtual void fillChecklist(ACLFilledChecklist &) const;
private:
if (type == NULL)
fatal("Unknown icon format while reading mime.conf\n");
- StoreEntry::getPublic(this, url_, Http::METHOD_GET);
-}
-
-void
-MimeIcon::created(StoreEntry *newEntry)
-{
- /* if the icon is already in the store, do nothing */
- if (newEntry)
+ if (const auto e = storeGetPublic(url_, Http::METHOD_GET)) {
+ // do not overwrite an already stored icon
+ e->abandon(__FUNCTION__);
return;
+ }
+
// XXX: if a 204 is cached due to earlier load 'failure' we should try to reload.
// default is a 200 object with image data.
clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
- Ip::Address tmpnoaddr;
- tmpnoaddr.setNoAddr();
repContext->setReplyToError(ERR_GATEWAY_FAILURE, status,
http->request->method, NULL,
- http->getConn() != NULL && http->getConn()->clientConnection != NULL ?
- http->getConn()->clientConnection->remote : tmpnoaddr,
+ http->getConn(),
http->request,
NULL,
#if USE_AUTH
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
- repContext->setReplyToError(requestError, errStatusCode, method, context->http->uri, clientConnection->remote, nullptr, requestErrorBytes, nullptr);
+ repContext->setReplyToError(requestError, errStatusCode, method, context->http->uri, this, nullptr, requestErrorBytes, nullptr);
assert(context->http->out.offset == 0);
context->pullData();
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
repContext->setReplyToError(ERR_INVALID_REQ, Http::scExpectationFailed, request->method, http->uri,
- clientConnection->remote, request.getRaw(), NULL, NULL);
+ this, request.getRaw(), nullptr, nullptr);
assert(context->http->out.offset == 0);
context->pullData();
clientProcessRequestFinished(this, request);
Store::Root().handleIdleEntry(*this); // may delete us
}
-void
-StoreEntry::getPublicByRequestMethod (StoreClient *aClient, HttpRequest * request, const HttpRequestMethod& method)
-{
- assert (aClient);
- aClient->created(storeGetPublicByRequestMethod(request, method));
-}
-
-void
-StoreEntry::getPublicByRequest (StoreClient *aClient, HttpRequest * request)
-{
- assert (aClient);
- aClient->created(storeGetPublicByRequest(request));
-}
-
-void
-StoreEntry::getPublic (StoreClient *aClient, const char *uri, const HttpRequestMethod& method)
-{
- assert (aClient);
- aClient->created(storeGetPublic(uri, method));
-}
-
StoreEntry *
storeGetPublic(const char *uri, const HttpRequestMethod& method)
{
}
bool
-StoreClient::startCollapsingOn(const StoreEntry &e, const bool doingRevalidation)
+StoreClient::startCollapsingOn(const StoreEntry &e, const bool doingRevalidation) const
{
if (!e.hittingRequiresCollapsing())
return false; // collapsing is impossible due to the entry state
icp_opcode icp_common_t::getOpCode() const STUB_RETVAL(ICP_INVALID)
ICPState::ICPState(icp_common_t &aHeader, HttpRequest *aRequest) STUB
ICPState::~ICPState() STUB
-bool ICPState::confirmAndPrepHit(const StoreEntry &) STUB_RETVAL(false)
-LogTags *ICPState::loggingTags() STUB_RETVAL(nullptr)
+bool ICPState::confirmAndPrepHit(const StoreEntry &) const STUB_RETVAL(false)
+LogTags *ICPState::loggingTags() const STUB_RETVAL(nullptr)
void ICPState::fillChecklist(ACLFilledChecklist&) const STUB
Comm::ConnectionPointer icpIncomingConn;
bool StoreEntry::hasIfNoneMatchEtag(const HttpRequest &request) const STUB_RETVAL(false)
Store::Disk &StoreEntry::disk() const STUB_RETREF(Store::Disk)
size_t StoreEntry::inUseCount() STUB_RETVAL(0)
-void StoreEntry::getPublicByRequestMethod(StoreClient * aClient, HttpRequest * request, const HttpRequestMethod& method) STUB
-void StoreEntry::getPublicByRequest(StoreClient * aClient, HttpRequest * request) STUB
-void StoreEntry::getPublic(StoreClient * aClient, const char *uri, const HttpRequestMethod& method) STUB
void *StoreEntry::operator new(size_t byteCount)
{
STUB
public:
explicit UrnState(const AccessLogEntry::Pointer &anAle): ale(anAle) {}
- void created (StoreEntry *newEntry);
void start (HttpRequest *, StoreEntry *);
void setUriResFromRequest(HttpRequest *);
private:
/* StoreClient API */
- virtual LogTags *loggingTags() { return ale ? &ale->cache.code : nullptr; }
+ virtual LogTags *loggingTags() const { return ale ? &ale->cache.code : nullptr; }
virtual void fillChecklist(ACLFilledChecklist &) const;
char *urlres = nullptr;
if (urlres_r == NULL)
return;
- StoreEntry::getPublic (this, urlres, Http::METHOD_GET);
-}
+ auto urlEntry = storeGetPublic(urlres, Http::METHOD_GET);
-void
-UrnState::fillChecklist(ACLFilledChecklist &checklist) const
-{
- checklist.setRequest(request.getRaw());
- checklist.al = ale;
-}
-
-void
-UrnState::created(StoreEntry *e)
-{
- if (!e || (e->hittingRequiresCollapsing() && !startCollapsingOn(*e, false))) {
+ if (!urlEntry || (urlEntry->hittingRequiresCollapsing() && !startCollapsingOn(*urlEntry, false))) {
urlres_e = storeCreateEntry(urlres, urlres, RequestFlags(), Http::METHOD_GET);
sc = storeClientListAdd(urlres_e, this);
FwdState::Start(Comm::ConnectionPointer(), urlres_e, urlres_r.getRaw(), ale);
- // TODO: StoreClients must either store/lock or abandon found entries.
- //if (e)
- // e->abandon();
+ if (urlEntry) {
+ urlEntry->abandon(__FUNCTION__);
+ urlEntry = nullptr;
+ }
} else {
- urlres_e = e;
- urlres_e->lock("UrnState::created");
+ urlres_e = urlEntry;
+ urlres_e->lock("UrnState::start");
sc = storeClientListAdd(urlres_e, this);
}
this);
}
+void
+UrnState::fillChecklist(ACLFilledChecklist &checklist) const
+{
+ checklist.setRequest(request.getRaw());
+ checklist.al = ale;
+}
+
void
urnStart(HttpRequest *r, StoreEntry *e, const AccessLogEntryPointer &ale)
{