/*
- * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#include "squid.h"
#include "AccessLogEntry.h"
#include "acl/FilledChecklist.h"
+#include "base/TextException.h"
#include "cbdata.h"
#include "errorpage.h"
#include "FwdState.h"
public:
explicit UrnState(const AccessLogEntry::Pointer &anAle): ale(anAle) {}
- void created (StoreEntry *newEntry);
void start (HttpRequest *, StoreEntry *);
- char *getHost(const SBuf &urlpath);
void setUriResFromRequest(HttpRequest *);
virtual ~UrnState();
HttpRequest::Pointer urlres_r;
AccessLogEntry::Pointer ale; ///< details of the requesting transaction
- struct {
- bool force_menu = false;
- } flags;
char reqbuf[URN_REQBUF_SZ] = { '\0' };
int reqofs = 0;
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;
UrnState::~UrnState()
{
- safe_free(urlres);
+ SWALLOW_EXCEPTIONS({
+ if (urlres_e) {
+ if (sc)
+ storeUnregister(sc, urlres_e, this);
+ urlres_e->unlock("~UrnState+res");
+ }
+
+ if (entry)
+ entry->unlock("~UrnState+prime");
+
+ safe_free(urlres);
+ });
}
static url_entry *
return min_u;
}
-char *
-UrnState::getHost(const SBuf &urlpath)
-{
- /** FIXME: this appears to be parsing the URL. *very* badly. */
- /* a proper encapsulated URI/URL type needs to clear this up. */
- size_t p;
- if ((p = urlpath.find(':')) != SBuf::npos)
- return SBufToCstring(urlpath.substr(0, p-1));
-
- return SBufToCstring(urlpath);
-}
-
void
UrnState::setUriResFromRequest(HttpRequest *r)
{
- static const SBuf menu(".menu");
- if (r->url.path().startsWith(menu)) {
- r->url.path(r->url.path().substr(5)); // strip prefix "menu."
- flags.force_menu = true;
- }
-
- SBuf uri = r->url.path();
+ const auto &query = r->url.absolute();
+ const auto host = r->url.host();
// TODO: use class AnyP::Uri instead of generating a string and re-parsing
LOCAL_ARRAY(char, local_urlres, 4096);
- char *host = getHost(uri);
- snprintf(local_urlres, 4096, "http://%s/uri-res/N2L?urn:" SQUIDSBUFPH, host, SQUIDSBUFPRINT(uri));
- safe_free(host);
+ snprintf(local_urlres, 4096, "http://%s/uri-res/N2L?" SQUIDSBUFPH, host, SQUIDSBUFPRINT(query));
safe_free(urlres);
- urlres_r = HttpRequest::FromUrl(local_urlres, r->masterXaction);
+ urlres_r = HttpRequest::FromUrlXXX(local_urlres, r->masterXaction);
if (!urlres_r) {
debugs(52, 3, "Bad uri-res URL " << local_urlres);
if (urlres_r == NULL)
return;
- StoreEntry::getPublic (this, urlres, Http::METHOD_GET);
-}
-
-void
-UrnState::fillChecklist(ACLFilledChecklist &checklist) const
-{
- checklist.setRequest(request.getRaw());
- checklist.al = ale;
-}
+ auto urlEntry = storeGetPublic(urlres, Http::METHOD_GET);
-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)
{
return u1->rtt - u2->rtt;
}
-static void
-urnHandleReplyError(UrnState *urnState, StoreEntry *urlres_e)
-{
- urlres_e->unlock("urnHandleReplyError+res");
- urnState->entry->unlock("urnHandleReplyError+prime");
- delete urnState;
-}
-
/* TODO: use the clientStream support for this */
static void
urnHandleReply(void *data, StoreIOBuffer result)
debugs(52, 3, "urnHandleReply: Called with size=" << result.length << ".");
- if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED) || result.length == 0 || result.flags.error) {
- urnHandleReplyError(urnState, urlres_e);
+ if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED) || result.flags.error) {
+ delete urnState;
+ return;
+ }
+
+ if (!e->isAccepting()) {
+ debugs(52, 3, "terminating due to bad " << *e);
+ delete urnState;
return;
}
/* Handle reqofs being bigger than normal */
if (urnState->reqofs >= URN_REQBUF_SZ) {
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
return;
}
/* If we haven't received the entire object (urn), copy more */
- if (urlres_e->store_status == STORE_PENDING &&
- urnState->reqofs < URN_REQBUF_SZ) {
+ if (urlres_e->store_status == STORE_PENDING) {
+ Must(result.length > 0); // zero length ought to imply STORE_OK
tempBuffer.offset = urnState->reqofs;
- tempBuffer.length = URN_REQBUF_SZ;
+ tempBuffer.length = URN_REQBUF_SZ - urnState->reqofs;
tempBuffer.data = urnState->reqbuf + urnState->reqofs;
storeClientCopy(urnState->sc, urlres_e,
tempBuffer,
if (0 == k) {
debugs(52, DBG_IMPORTANT, "urnHandleReply: didn't find end-of-headers for " << e->url() );
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
return;
}
s = buf + k;
- assert(urlres_e->getReply());
+ // TODO: Check whether we should parse urlres_e reply, as before 528b2c61.
rep = new HttpReply;
rep->parseCharBuf(buf, k);
debugs(52, 3, "reply exists, code=" << rep->sline.status() << ".");
err->url = xstrdup(e->url());
errorAppendEntry(e, err);
delete rep;
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
return;
}
err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, urnState->request.getRaw(), urnState->ale);
err->url = xstrdup(e->url());
errorAppendEntry(e, err);
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
return;
}
rep = new HttpReply;
rep->setHeaders(Http::scFound, NULL, "text/html", mb->length(), 0, squid_curtime);
- if (urnState->flags.force_menu) {
- debugs(51, 3, "urnHandleReply: forcing menu");
- } else if (min_u) {
+ if (min_u) {
rep->header.putStr(Http::HdrType::LOCATION, min_u->url);
}
}
safe_free(urls);
- storeUnregister(urnState->sc, urlres_e, urnState);
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
}
static url_entry *
{
char *buf = xstrdup(inbuf);
char *token;
- char *host;
url_entry *list;
url_entry *old;
int n = 32;
safe_free(old);
}
- host = urlHostname(token);
-
- if (NULL == host)
+ AnyP::Uri uri;
+ if (!uri.parse(m, SBuf(token)) || !*uri.host())
continue;
#if USE_ICMP
- list[i].rtt = netdbHostRtt(host);
+ list[i].rtt = netdbHostRtt(uri.host());
if (0 == list[i].rtt) {
- debugs(52, 3, "urnParseReply: Pinging " << host);
- netdbPingSite(host);
+ debugs(52, 3, "Pinging " << uri.host());
+ netdbPingSite(uri.host());
}
#else
list[i].rtt = 0;
#endif
- list[i].url = xstrdup(token);
- list[i].host = xstrdup(host);
+ list[i].url = xstrdup(uri.absolute().c_str());
+ list[i].host = xstrdup(uri.host());
// TODO: Use storeHas() or lock/unlock entry to avoid creating unlocked
// ones.
list[i].flags.cached = storeGetPublic(list[i].url, m) ? 1 : 0;
}
debugs(52, 3, "urnParseReply: Found " << i << " URLs");
+ xfree(buf);
return list;
}