static void httpMaybeRemovePublic(StoreEntry *, Http::StatusCode);
static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request,
HttpHeader * hdr_out, const int we_do_ranges, const HttpStateFlags &);
-//Declared in HttpHeaderTools.cc
-void httpHdrAdd(HttpHeader *heads, HttpRequest *request, const AccessLogEntryPointer &al, HeaderWithAclList &headers_add);
HttpStateData::HttpStateData(FwdState *theFwdState) :
AsyncJob("HttpStateData"),
fwd->fail(new ErrorState(ERR_READ_TIMEOUT, Http::scGatewayTimeout, fwd->request));
}
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::httpTimeout");
}
/// Remove an existing public store entry if the incoming response (to be
/* NOTREACHED */
}
-/*
- * For Vary, store the relevant request headers as
- * virtual headers in the reply
- * Returns false if the variance cannot be stored
- */
-const char *
-httpMakeVaryMark(HttpRequest * request, HttpReply const * reply)
+/// assemble a variant key (vary-mark) from the given Vary header and HTTP request
+static void
+assembleVaryKey(String &vary, SBuf &vstr, const HttpRequest &request)
{
- String vary, hdr;
- const char *pos = NULL;
- const char *item;
- const char *value;
- int ilen;
- static String vstr;
-
- vstr.clean();
- vary = reply->header.getList(Http::HdrType::VARY);
+ static const SBuf asterisk("*");
+ const char *pos = nullptr;
+ const char *item = nullptr;
+ int ilen = 0;
while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
- static const SBuf asterisk("*");
SBuf name(item, ilen);
if (name == asterisk) {
- vstr.clean();
+ vstr.clear();
break;
}
name.toLower();
- strListAdd(&vstr, name.c_str(), ',');
- hdr = request->header.getByName(name);
- value = hdr.termedBuf();
+ if (!vstr.isEmpty())
+ vstr.append(", ", 2);
+ vstr.append(name);
+ String hdr(request.header.getByName(name));
+ const char *value = hdr.termedBuf();
if (value) {
value = rfc1738_escape_part(value);
vstr.append("=\"", 2);
hdr.clean();
}
+}
- vary.clean();
-#if X_ACCELERATOR_VARY
-
- pos = NULL;
- vary = reply->header.getList(Http::HdrType::HDR_X_ACCELERATOR_VARY);
-
- while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
- char *name = (char *)xmalloc(ilen + 1);
- xstrncpy(name, item, ilen + 1);
- Tolower(name);
- strListAdd(&vstr, name, ',');
- hdr = request->header.getByName(name);
- safe_free(name);
- value = hdr.termedBuf();
-
- if (value) {
- value = rfc1738_escape_part(value);
- vstr.append("=\"", 2);
- vstr.append(value);
- vstr.append("\"", 1);
- }
+/*
+ * For Vary, store the relevant request headers as
+ * virtual headers in the reply
+ * Returns an empty SBuf if the variance cannot be stored
+ */
+SBuf
+httpMakeVaryMark(HttpRequest * request, HttpReply const * reply)
+{
+ SBuf vstr;
+ String vary;
- hdr.clean();
- }
+ vary = reply->header.getList(Http::HdrType::VARY);
+ assembleVaryKey(vary, vstr, *request);
+#if X_ACCELERATOR_VARY
vary.clean();
+ vary = reply->header.getList(Http::HdrType::HDR_X_ACCELERATOR_VARY);
+ assembleVaryKey(vary, vstr, *request);
#endif
- debugs(11, 3, "httpMakeVaryMark: " << vstr);
- return vstr.termedBuf();
+ debugs(11, 3, vstr);
+ return vstr;
}
void
|| rep->header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY)
#endif
) {
- const char *vary = httpMakeVaryMark(request, rep);
+ const SBuf vary(httpMakeVaryMark(request, rep));
- if (!vary) {
+ if (vary.isEmpty()) {
entry->makePrivate();
if (!fwd->reforwardableStatus(rep->sline.status()))
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
varyFailure = true;
} else {
- entry->mem_obj->vary_headers = xstrdup(vary);
+ entry->mem_obj->vary_headers = vary;
}
}
err->xerrno = rd.xerrno;
fwd->fail(err);
flags.do_next_read = false;
- io.conn->close();
-
+ closeServer();
+ mustStop("HttpStateData::readReply");
return;
}
entry->reset();
fwd->fail(new ErrorState(error, Http::scBadGateway, fwd->request));
flags.do_next_read = false;
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::continueAfterParsingHeader");
return false; // quit on error
}
writeReplyBody();
}
+ // storing/sending methods like earlier adaptOrFinalizeReply() or
+ // above writeReplyBody() may release/abort the store entry.
if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
- // The above writeReplyBody() call may have aborted the store entry.
+ // TODO: In some cases (e.g., 304), we should keep persistent conn open.
+ // Detect end-of-reply (and, hence, pool our idle pconn) earlier (ASAP).
abortTransaction("store entry aborted while storing reply");
return;
} else
ErrorState *err = new ErrorState(ERR_WRITE_ERROR, Http::scBadGateway, fwd->request);
err->xerrno = io.xerrno;
fwd->fail(err);
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::wroteLast");
return;
}
request->hier.peer_http_request_sent = current_time;
}
-// Close the HTTP server connection. Used by serverComplete().
void
HttpStateData::closeServer()
{
}
/* Now mangle the headers. */
- if (Config2.onoff.mangle_request_headers)
- httpHdrMangleList(hdr_out, request, ROR_REQUEST);
-
- if (Config.request_header_add && !Config.request_header_add->empty())
- httpHdrAdd(hdr_out, request, al, *Config.request_header_add);
+ httpHdrMangleList(hdr_out, request, al, ROR_REQUEST);
strConnection.clean();
}
debugs(11, DBG_IMPORTANT, "http handleMoreRequestBodyAvailable: Likely proxy abuse detected '" << request->client_addr << "' -> '" << entry->url() << "'" );
if (virginReply()->sline.status() == Http::scInvalidHeader) {
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::handleMoreRequestBodyAvailable");
return;
}
}