/*
- * DEBUG: section 52 URN Parsing
- * AUTHOR: Kostas Anagnostakis
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
+/* DEBUG: section 52 URN Parsing */
+
#include "squid.h"
+#include "AccessLogEntry.h"
+#include "acl/FilledChecklist.h"
+#include "base/TextException.h"
#include "cbdata.h"
#include "errorpage.h"
#include "FwdState.h"
#include "Store.h"
#include "StoreClient.h"
#include "tools.h"
-#include "URL.h"
#include "urn.h"
-#define URN_REQBUF_SZ 4096
+#define URN_REQBUF_SZ 4096
class UrnState : public StoreClient
{
+ CBDATA_CLASS(UrnState);
public:
+ explicit UrnState(const AccessLogEntry::Pointer &anAle): ale(anAle) {}
+
void created (StoreEntry *newEntry);
void start (HttpRequest *, StoreEntry *);
- char *getHost (String &urlpath);
void setUriResFromRequest(HttpRequest *);
- bool RequestNeedsMenu(HttpRequest *r);
- void updateRequestURL(HttpRequest *r, char const *newPath, const size_t newPath_len);
- void createUriResRequest (String &uri);
virtual ~UrnState();
- StoreEntry *entry;
- store_client *sc;
- StoreEntry *urlres_e;
+ StoreEntry *entry = nullptr;
+ store_client *sc = nullptr;
+ StoreEntry *urlres_e = nullptr;
HttpRequest::Pointer request;
HttpRequest::Pointer urlres_r;
+ AccessLogEntry::Pointer ale; ///< details of the requesting transaction
- struct {
- bool force_menu;
- } flags;
- char reqbuf[URN_REQBUF_SZ];
- int reqofs;
+ char reqbuf[URN_REQBUF_SZ] = { '\0' };
+ int reqofs = 0;
private:
- char *urlres;
+ /* StoreClient API */
+ virtual LogTags *loggingTags() { return ale ? &ale->cache.code : nullptr; }
+ virtual void fillChecklist(ACLFilledChecklist &) const;
- CBDATA_CLASS2(UrnState);
+ char *urlres = nullptr;
};
typedef struct {
static STCB urnHandleReply;
static url_entry *urnParseReply(const char *inbuf, const HttpRequestMethod&);
static const char *const crlf = "\r\n";
-static QS url_entry_sort;
CBDATA_CLASS_INIT(UrnState);
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 *
-urnFindMinRtt(url_entry * urls, const HttpRequestMethod& m, int *rtt_ret)
+urnFindMinRtt(url_entry * urls, const HttpRequestMethod &, int *rtt_ret)
{
int min_rtt = 0;
url_entry *u = NULL;
return min_u;
}
-char *
-UrnState::getHost (String &urlpath)
-{
- char * result;
- size_t p;
-
- /** FIXME: this appears to be parsing the URL. *very* badly. */
- /* a proper encapsulated URI/URL type needs to clear this up. */
- if ((p=urlpath.find(':')) != String::npos) {
- result=xstrndup(urlpath.rawBuf(),p-1);
- } else {
- result = xstrndup(urlpath.rawBuf(),urlpath.size());
- }
- return result;
-}
-
-bool
-UrnState::RequestNeedsMenu(HttpRequest *r)
-{
- if (r->urlpath.size() < 5)
- return false;
- //now we're sure it's long enough
- return strncasecmp(r->urlpath.rawBuf(), "menu.", 5) == 0;
-}
-
void
-UrnState::updateRequestURL(HttpRequest *r, char const *newPath, const size_t newPath_len)
-{
- char *new_path = xstrndup (newPath, newPath_len);
- r->urlpath = new_path;
- xfree(new_path);
-}
-
-void
-UrnState::createUriResRequest (String &uri)
+UrnState::setUriResFromRequest(HttpRequest *r)
{
+ 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:" SQUIDSTRINGPH,
- host, SQUIDSTRINGPRINT(uri));
- safe_free(host);
+ snprintf(local_urlres, 4096, "http://%s/uri-res/N2L?" SQUIDSBUFPH, host, SQUIDSBUFPRINT(query));
safe_free(urlres);
- urlres = xstrdup(local_urlres);
- urlres_r = HttpRequest::CreateFromUrl(urlres);
-}
-
-void
-UrnState::setUriResFromRequest(HttpRequest *r)
-{
- if (RequestNeedsMenu(r)) {
- updateRequestURL(r, r->urlpath.rawBuf() + 5, r->urlpath.size() - 5 );
- flags.force_menu = true;
- }
-
- createUriResRequest (r->urlpath);
+ urlres_r = HttpRequest::FromUrlXXX(local_urlres, r->masterXaction);
- if (urlres_r == NULL) {
- debugs(52, 3, "urnStart: Bad uri-res URL " << urlres);
- ErrorState *err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, r);
- err->url = urlres;
- urlres = NULL;
+ if (!urlres_r) {
+ debugs(52, 3, "Bad uri-res URL " << local_urlres);
+ const auto err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, r, ale);
+ err->url = xstrdup(local_urlres);
errorAppendEntry(entry, err);
return;
}
- urlres_r->header.putStr(HDR_ACCEPT, "text/plain");
+ urlres = xstrdup(local_urlres);
+ urlres_r->header.putStr(Http::HdrType::ACCEPT, "text/plain");
}
void
}
void
-UrnState::created(StoreEntry *newEntry)
+UrnState::fillChecklist(ACLFilledChecklist &checklist) const
{
- urlres_e = newEntry;
+ checklist.setRequest(request.getRaw());
+ checklist.al = ale;
+}
- if (urlres_e->isNull()) {
+void
+UrnState::created(StoreEntry *e)
+{
+ if (!e || (e->hittingRequiresCollapsing() && !startCollapsingOn(*e, false))) {
urlres_e = storeCreateEntry(urlres, urlres, RequestFlags(), Http::METHOD_GET);
sc = storeClientListAdd(urlres_e, this);
- FwdState::fwdStart(Comm::ConnectionPointer(), urlres_e, urlres_r.getRaw());
+ FwdState::Start(Comm::ConnectionPointer(), urlres_e, urlres_r.getRaw(), ale);
+ // TODO: StoreClients must either store/lock or abandon found entries.
+ //if (e)
+ // e->abandon();
} else {
+ urlres_e = e;
urlres_e->lock("UrnState::created");
sc = storeClientListAdd(urlres_e, this);
}
}
void
-urnStart(HttpRequest * r, StoreEntry * e)
+urnStart(HttpRequest *r, StoreEntry *e, const AccessLogEntryPointer &ale)
{
- UrnState *anUrn = new UrnState();
+ const auto anUrn = new UrnState(ale);
anUrn->start (r, e);
}
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)
url_entry *urls;
url_entry *u;
url_entry *min_u;
- MemBuf *mb = NULL;
ErrorState *err;
int i;
int urlcnt = 0;
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;
}
/* 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() << ".");
if (rep->sline.status() != Http::scOkay) {
debugs(52, 3, "urnHandleReply: failed.");
- err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, urnState->request.getRaw());
+ err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, urnState->request.getRaw(), urnState->ale);
err->url = xstrdup(e->url());
errorAppendEntry(e, err);
delete rep;
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
return;
}
urls = urnParseReply(s, urnState->request->method);
- for (i = 0; NULL != urls[i].url; ++i)
- ++urlcnt;
-
- debugs(53, 3, "urnFindMinRtt: Counted " << i << " URLs");
-
- if (urls == NULL) { /* unkown URN error */
+ if (!urls) { /* unknown URN error */
debugs(52, 3, "urnTranslateDone: unknown URN " << e->url());
- err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, urnState->request.getRaw());
+ 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;
}
+ for (i = 0; urls[i].url; ++i)
+ ++urlcnt;
+
+ debugs(53, 3, "urnFindMinRtt: Counted " << i << " URLs");
+
min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
e->buffer();
- mb = new MemBuf;
- mb->init();
- mb->Printf( "<TITLE>Select URL for %s</TITLE>\n"
- "<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n"
- "<H2>Select URL for %s</H2>\n"
- "<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", e->url(), e->url());
+ SBuf body;
+ SBuf *mb = &body; // diff reduction hack; TODO: Remove
+ mb->appendf( "<TITLE>Select URL for %s</TITLE>\n"
+ "<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n"
+ "<H2>Select URL for %s</H2>\n"
+ "<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", e->url(), e->url());
for (i = 0; i < urlcnt; ++i) {
u = &urls[i];
debugs(52, 3, "URL {" << u->url << "}");
- mb->Printf(
+ mb->appendf(
"<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
if (urls[i].rtt > 0)
- mb->Printf(
+ mb->appendf(
"<TD align=\"right\">%4d <it>ms</it></TD>", u->rtt);
else
- mb->Printf("<TD align=\"right\">Unknown</TD>");
+ mb->appendf("<TD align=\"right\">Unknown</TD>");
- mb->Printf(
- "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " ");
+ mb->appendf("<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " ");
}
- mb->Printf(
+ mb->appendf(
"</TABLE>"
"<HR noshade size=\"1px\">\n"
"<ADDRESS>\n"
"</ADDRESS>\n",
APP_FULLNAME, getMyHostname());
rep = new HttpReply;
- rep->setHeaders(Http::scMovedTemporarily, NULL, "text/html", mb->contentSize(), 0, squid_curtime);
+ 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) {
- rep->header.putStr(HDR_LOCATION, min_u->url);
+ if (min_u) {
+ rep->header.putStr(Http::HdrType::LOCATION, min_u->url);
}
- rep->body.setMb(mb);
- /* don't clean or delete mb; rep->body owns it now */
+ rep->body.set(body);
e->replaceHttpReply(rep);
e->complete();
}
safe_free(urls);
- /* mb was absorbed in httpBodySet call, so we must not clean it */
- storeUnregister(urnState->sc, urlres_e, urnState);
- urnHandleReplyError(urnState, urlres_e);
+ delete urnState;
}
static url_entry *
{
char *buf = xstrdup(inbuf);
char *token;
- char *url;
char *host;
url_entry *list;
url_entry *old;
safe_free(old);
}
- url = xstrdup(token);
- host = urlHostname(url);
+ host = urlHostname(token);
if (NULL == host)
continue;
list[i].rtt = 0;
#endif
- list[i].url = url;
+ list[i].url = xstrdup(token);
list[i].host = xstrdup(host);
// TODO: Use storeHas() or lock/unlock entry to avoid creating unlocked
// ones.
- list[i].flags.cached = storeGetPublic(url, m) ? 1 : 0;
+ list[i].flags.cached = storeGetPublic(list[i].url, m) ? 1 : 0;
++i;
}
debugs(52, 3, "urnParseReply: Found " << i << " URLs");
return list;
}
+