From 4f1c93a7a0d14eec223e199275ce570d840f71bc Mon Sep 17 00:00:00 2001 From: Eduard Bagdasaryan Date: Tue, 31 Jul 2018 22:08:31 +0000 Subject: [PATCH] Do not send Content-Length in 1xx or 204 responses (#249) This is RFC 7230 section 3.3.2 requirement. --- src/HttpHeader.cc | 16 +++++++++++----- src/HttpHeader.h | 4 ++-- src/HttpReply.cc | 21 +++++++++++++++++++++ src/HttpReply.h | 7 +++++++ src/HttpRequest.cc | 15 +++++++++++++++ src/HttpRequest.h | 9 +++++++++ src/adaptation/icap/ModXact.cc | 7 ++++++- src/client_side_reply.cc | 2 ++ src/clients/FtpRelay.cc | 12 ++++++------ src/ftp/Elements.h | 3 +++ src/htcp.cc | 19 ++++++++++++++----- src/htcp.h | 4 ++++ src/http.cc | 2 +- src/http/ContentLengthInterpreter.cc | 7 ++++--- src/http/ContentLengthInterpreter.h | 27 ++++++++++++++++++++++++++- src/http/Message.cc | 10 +++++++--- src/http/Message.h | 9 ++++++--- src/http/StatusCode.h | 4 ++++ src/http/forward.h | 2 ++ src/servers/Http1Server.cc | 2 ++ src/ssl/ErrorDetailManager.cc | 5 ++++- src/tests/stub_HttpReply.cc | 1 + 22 files changed, 157 insertions(+), 31 deletions(-) diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index 185399fafc..488e8f986f 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -344,7 +344,7 @@ HttpHeader::Isolate(const char **parse_start, size_t l, const char **blk_start, } int -HttpHeader::parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz) +HttpHeader::parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz, Http::ContentLengthInterpreter &clen) { const char *parse_start = buf; const char *blk_start, *blk_end; @@ -359,7 +359,7 @@ HttpHeader::parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz) blk_end = blk_start + strlen(blk_start); } - if (parse(blk_start, blk_end - blk_start)) { + if (parse(blk_start, blk_end - blk_start, clen)) { hdr_sz = parse_start - buf; return 1; } @@ -367,7 +367,7 @@ HttpHeader::parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz) } int -HttpHeader::parse(const char *header_start, size_t hdrLen) +HttpHeader::parse(const char *header_start, size_t hdrLen, Http::ContentLengthInterpreter &clen) { const char *field_ptr = header_start; const char *header_end = header_start + hdrLen; // XXX: remove @@ -388,7 +388,6 @@ HttpHeader::parse(const char *header_start, size_t hdrLen) return 0; } - Http::ContentLengthInterpreter clen(warnOnError); /* common format headers are ":[ws]" lines delimited by . * continuation lines start with a (single) space or tab */ while (field_ptr < header_end) { @@ -520,7 +519,14 @@ HttpHeader::parse(const char *header_start, size_t hdrLen) Raw("header", header_start, hdrLen)); } - if (chunked()) { + if (clen.prohibitedAndIgnored()) { + // RFC 7230 section 3.3.2: A server MUST NOT send a Content-Length + // header field in any response with a status code of 1xx (Informational) + // or 204 (No Content). And RFC 7230 3.3.3#1 tells recipients to ignore + // such Content-Lengths. + if (delById(Http::HdrType::CONTENT_LENGTH)) + debugs(55, 3, "Content-Length is " << clen.prohibitedAndIgnored()); + } else if (chunked()) { // RFC 2616 section 4.4: ignore Content-Length with Transfer-Encoding // RFC 7230 section 3.3.3 #3: Transfer-Encoding overwrites Content-Length delById(Http::HdrType::CONTENT_LENGTH); diff --git a/src/HttpHeader.h b/src/HttpHeader.h index cc21d3e0c1..6e8f58bda5 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -84,12 +84,12 @@ public: void append(const HttpHeader * src); bool update(HttpHeader const *fresh); void compact(); - int parse(const char *header_start, size_t len); + int parse(const char *header_start, size_t len, Http::ContentLengthInterpreter &interpreter); /// Parses headers stored in a buffer. /// \returns 1 and sets hdr_sz on success /// \returns 0 when needs more data /// \returns -1 on error - int parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz); + int parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz, Http::ContentLengthInterpreter &interpreter); void packInto(Packable * p, bool mask_sensitive_info=false) const; HttpHeaderEntry *getEntry(HttpHeaderPos * pos) const; HttpHeaderEntry *findEntry(Http::HdrType id) const; diff --git a/src/HttpReply.cc b/src/HttpReply.cc index 954876a026..3adf08968a 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -13,6 +13,7 @@ #include "acl/FilledChecklist.h" #include "base/EnumIterator.h" #include "globals.h" +#include "http/ContentLengthInterpreter.h" #include "HttpBody.h" #include "HttpHdrCc.h" #include "HttpHdrContRange.h" @@ -452,6 +453,19 @@ HttpReply::parseFirstLine(const char *blk_start, const char *blk_end) return sline.parse(protoPrefix, blk_start, blk_end); } +void +HttpReply::configureContentLengthInterpreter(Http::ContentLengthInterpreter &interpreter) +{ + interpreter.applyStatusCodeRules(sline.status()); +} + +bool +HttpReply::parseHeader(Http1::Parser &hp) +{ + Http::ContentLengthInterpreter clen; + return Message::parseHeader(hp, clen); +} + /* handy: resets and returns -1 */ int HttpReply::httpMsgParseError() @@ -649,3 +663,10 @@ HttpReply::olderThan(const HttpReply *them) const return date < them->date; } +void +HttpReply::removeIrrelevantContentLength() { + if (Http::ProhibitsContentLength(sline.status())) + if (header.delById(Http::HdrType::CONTENT_LENGTH)) + debugs(58, 3, "Removing unexpected Content-Length header"); +} + diff --git a/src/HttpReply.h b/src/HttpReply.h index 7860ff04d7..ab227c2cdf 100644 --- a/src/HttpReply.h +++ b/src/HttpReply.h @@ -120,6 +120,13 @@ public: /// \returns false if any information is missing bool olderThan(const HttpReply *them) const; + /// Some response status codes prohibit sending Content-Length (RFC 7230 section 3.3.2). + void removeIrrelevantContentLength(); + + virtual void configureContentLengthInterpreter(Http::ContentLengthInterpreter &); + /// parses reply header using Parser + bool parseHeader(Http1::Parser &hp); + private: /** initialize */ void init(); diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 72cb7f279e..d2f9e7f1d5 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -20,6 +20,7 @@ #include "globals.h" #include "gopher.h" #include "http.h" +#include "http/ContentLengthInterpreter.h" #include "http/one/RequestParser.h" #include "http/Stream.h" #include "HttpHdrCc.h" @@ -649,6 +650,20 @@ HttpRequest::canHandle1xx() const return true; } +bool +HttpRequest::parseHeader(Http1::Parser &hp) +{ + Http::ContentLengthInterpreter clen; + return Message::parseHeader(hp, clen); +} + +bool +HttpRequest::parseHeader(const char *buffer, const size_t size) +{ + Http::ContentLengthInterpreter clen; + return header.parse(buffer, size, clen); +} + ConnStateData * HttpRequest::pinnedConnection() { diff --git a/src/HttpRequest.h b/src/HttpRequest.h index eee849adcd..138b2181b2 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -236,6 +236,15 @@ public: NotePairs::Pointer notes(); bool hasNotes() const { return bool(theNotes) && !theNotes->empty(); } + virtual void configureContentLengthInterpreter(Http::ContentLengthInterpreter &) {} + + /// Parses request header using Parser. + /// Use it in contexts where the Parser object is available. + bool parseHeader(Http1::Parser &hp); + /// Parses request header from the buffer. + /// Use it in contexts where the Parser object not available. + bool parseHeader(const char *buffer, const size_t size); + private: mutable int64_t rangeOffsetLimit; /* caches the result of getRangeOffsetLimit */ diff --git a/src/adaptation/icap/ModXact.cc b/src/adaptation/icap/ModXact.cc index 332ea5aeba..2a25d2a4fe 100644 --- a/src/adaptation/icap/ModXact.cc +++ b/src/adaptation/icap/ModXact.cc @@ -25,6 +25,7 @@ #include "comm.h" #include "comm/Connection.h" #include "err_detail_type.h" +#include "http/ContentLengthInterpreter.h" #include "http/one/TeChunkedParser.h" #include "HttpHeaderTools.h" #include "HttpReply.h" @@ -2063,7 +2064,11 @@ void Adaptation::Icap::ModXactLauncher::updateHistory(bool doStart) } bool Adaptation::Icap::TrailerParser::parse(const char *buf, int len, int atEnd, Http::StatusCode *error) { - const int parsed = trailer.parse(buf, len, atEnd, hdr_sz); + Http::ContentLengthInterpreter clen; + // RFC 7230 section 4.1.2: MUST NOT generate a trailer that contains + // a field necessary for message framing (e.g., Transfer-Encoding and Content-Length) + clen.applyTrailerRules(); + const int parsed = trailer.parse(buf, len, atEnd, hdr_sz, clen); if (parsed < 0) *error = Http::scInvalidHeader; // TODO: should we add a new Http::scInvalidTrailer? return parsed > 0; diff --git a/src/client_side_reply.cc b/src/client_side_reply.cc index 355863266b..04480b7eca 100644 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@ -1408,6 +1408,8 @@ clientReplyContext::buildReplyHeader() } reply->header.removeHopByHopEntries(); + // paranoid: ContentLengthInterpreter has cleaned non-generated replies + reply->removeIrrelevantContentLength(); // if (request->range) // clientBuildRangeHeader(http, reply); diff --git a/src/clients/FtpRelay.cc b/src/clients/FtpRelay.cc index b686d5c0d0..4d3b790b7f 100644 --- a/src/clients/FtpRelay.cc +++ b/src/clients/FtpRelay.cc @@ -567,7 +567,7 @@ Ftp::Relay::readReply() assert(serverState() == fssConnected || serverState() == fssHandleUploadRequest); - if (100 <= ctrl.replycode && ctrl.replycode < 200) + if (Is1xx(ctrl.replycode)) forwardPreliminaryReply(&Ftp::Relay::scheduleReadControlReply); else forwardReply(); @@ -578,7 +578,7 @@ Ftp::Relay::readFeatReply() { assert(serverState() == fssHandleFeat); - if (100 <= ctrl.replycode && ctrl.replycode < 200) + if (Is1xx(ctrl.replycode)) return; // ignore preliminary replies forwardReply(); @@ -589,7 +589,7 @@ Ftp::Relay::readPasvReply() { assert(serverState() == fssHandlePasv || serverState() == fssHandleEpsv || serverState() == fssHandlePort || serverState() == fssHandleEprt); - if (100 <= ctrl.replycode && ctrl.replycode < 200) + if (Is1xx(ctrl.replycode)) return; // ignore preliminary replies if (handlePasvReply(updateMaster().clientDataAddr)) @@ -601,7 +601,7 @@ Ftp::Relay::readPasvReply() void Ftp::Relay::readEpsvReply() { - if (100 <= ctrl.replycode && ctrl.replycode < 200) + if (Is1xx(ctrl.replycode)) return; // ignore preliminary replies if (handleEpsvReply(updateMaster().clientDataAddr)) { @@ -680,7 +680,7 @@ Ftp::Relay::readCwdOrCdupReply() debugs(9, 5, "got code " << ctrl.replycode << ", msg: " << ctrl.last_reply); - if (100 <= ctrl.replycode && ctrl.replycode < 200) + if (Is1xx(ctrl.replycode)) return; if (weAreTrackingDir()) { // we are tracking @@ -694,7 +694,7 @@ Ftp::Relay::readCwdOrCdupReply() void Ftp::Relay::readUserOrPassReply() { - if (100 <= ctrl.replycode && ctrl.replycode < 200) + if (Is1xx(ctrl.replycode)) return; //Just ignore if (weAreTrackingDir()) { // we are tracking diff --git a/src/ftp/Elements.h b/src/ftp/Elements.h index 40d07d1b60..0676df9c31 100644 --- a/src/ftp/Elements.h +++ b/src/ftp/Elements.h @@ -49,6 +49,9 @@ const SBuf &cmdStor(); const SBuf &cmdStou(); const SBuf &cmdUser(); +/// whether this is an informational 1xx response status code +inline bool Is1xx(const int sc) { return Http::scContinue <= sc && sc < Http::scOkay; } + } // namespace Ftp #endif /* SQUID_FTP_ELEMENTS_H */ diff --git a/src/htcp.cc b/src/htcp.cc index f77d09dcbe..87bd3d7a9d 100644 --- a/src/htcp.cc +++ b/src/htcp.cc @@ -21,6 +21,7 @@ #include "globals.h" #include "htcp.h" #include "http.h" +#include "http/ContentLengthInterpreter.h" #include "HttpRequest.h" #include "icmp/net_db.h" #include "ip/tools.h" @@ -924,7 +925,7 @@ htcpSpecifier::checkHit() return; } - if (!checkHitRequest->header.parse(req_hdrs, reqHdrsSz)) { + if (!checkHitRequest->parseHeader(req_hdrs, reqHdrsSz)) { debugs(31, 3, "htcpCheckHit: NO; failed to parse request headers"); checkHitRequest = nullptr; checkedHit(nullptr); @@ -993,7 +994,7 @@ htcpClrStore(const htcpSpecifier::Pointer &s) } /* Parse request headers */ - if (!request->header.parse(s->req_hdrs, s->reqHdrsSz)) { + if (!request->parseHeader(s->req_hdrs, s->reqHdrsSz)) { debugs(31, 2, "htcpClrStore: failed to parse request headers"); return -1; } @@ -1033,6 +1034,14 @@ HtcpReplyData::HtcpReplyData() : memset(&cto, 0, sizeof(cto)); } +bool +HtcpReplyData::parseHeader(const char *buffer, const size_t size) +{ + Http::ContentLengthInterpreter interpreter; + // no applyStatusCodeRules() -- HTCP replies lack cached HTTP status code + return hdr.parse(buffer, size, interpreter); +} + static void htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from) @@ -1088,13 +1097,13 @@ htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from } if ((t = d->resp_hdrs)) - htcpReply.hdr.parse(t, d->respHdrsSz); + htcpReply.parseHeader(t, d->respHdrsSz); if ((t = d->entity_hdrs)) - htcpReply.hdr.parse(t, d->entityHdrsSz); + htcpReply.parseHeader(t, d->entityHdrsSz); if ((t = d->cache_hdrs)) - htcpReply.hdr.parse(t, d->cacheHdrsSz); + htcpReply.parseHeader(t, d->cacheHdrsSz); } debugs(31, 3, "htcpHandleTstResponse: key (" << key << ") " << storeKeyText(key)); diff --git a/src/htcp.h b/src/htcp.h index ac2cdbe45c..1f6b77a02b 100644 --- a/src/htcp.h +++ b/src/htcp.h @@ -22,6 +22,10 @@ class HtcpReplyData public: HtcpReplyData(); + + /// parses request header from the buffer + bool parseHeader(const char *buffer, const size_t size); + int hit; HttpHeader hdr; uint32_t msg_id; diff --git a/src/http.cc b/src/http.cc index f3dcf010a8..5810ac9351 100644 --- a/src/http.cc +++ b/src/http.cc @@ -751,7 +751,7 @@ HttpStateData::processReplyHeader() newrep->removeStaleWarnings(); - if (newrep->sline.protocol == AnyP::PROTO_HTTP && newrep->sline.status() >= 100 && newrep->sline.status() < 200) { + if (newrep->sline.protocol == AnyP::PROTO_HTTP && Http::Is1xx(newrep->sline.status())) { handle1xx(newrep); ctx_exit(ctx); return; diff --git a/src/http/ContentLengthInterpreter.cc b/src/http/ContentLengthInterpreter.cc index f69d5eb0ca..e2ac07ad64 100644 --- a/src/http/ContentLengthInterpreter.cc +++ b/src/http/ContentLengthInterpreter.cc @@ -18,13 +18,14 @@ #include "SquidString.h" #include "StrList.h" -Http::ContentLengthInterpreter::ContentLengthInterpreter(const int aDebugLevel): +Http::ContentLengthInterpreter::ContentLengthInterpreter(): value(-1), headerWideProblem(nullptr), - debugLevel(aDebugLevel), + debugLevel(Config.onoff.relaxed_header_parser <= 0 ? DBG_IMPORTANT : 2), sawBad(false), needsSanitizing(false), - sawGood(false) + sawGood(false), + prohibitedAndIgnored_(nullptr) { } diff --git a/src/http/ContentLengthInterpreter.h b/src/http/ContentLengthInterpreter.h index 6801c1f0e5..8b02e84316 100644 --- a/src/http/ContentLengthInterpreter.h +++ b/src/http/ContentLengthInterpreter.h @@ -9,6 +9,8 @@ #ifndef SQUID_SRC_HTTP_CONTENTLENGTH_INTERPRETER_H #define SQUID_SRC_HTTP_CONTENTLENGTH_INTERPRETER_H +#include "http/StatusCode.h" + class String; namespace Http @@ -19,12 +21,31 @@ namespace Http class ContentLengthInterpreter { public: - explicit ContentLengthInterpreter(const int aDebugLevel); + ContentLengthInterpreter(); /// updates history based on the given message-header field /// \return true iff the field should be added/remembered for future use bool checkField(const String &field); + /// prohibits Content-Length in 1xx and 204 responses + void applyStatusCodeRules(const StatusCode code) { + if (!prohibitedAndIgnored_ && ProhibitsContentLength(code)) + prohibitedAndIgnored_ = (code == scNoContent) ? "prohibited and ignored in the 204 response" : + "prohibited and ignored the 1xx response"; + } + + // TODO: implement + /// prohibits Content-Length in GET/HEAD requests + // void applyRequestMethodRules(const Http::MethodType method); + + /// prohibits Content-Length in trailer + void applyTrailerRules() { + if (!prohibitedAndIgnored_) + prohibitedAndIgnored_ = "prohibited in trailers"; + } + + const char *prohibitedAndIgnored() const { return prohibitedAndIgnored_; } + /// intended Content-Length value if sawGood is set and sawBad is not set /// meaningless otherwise int64_t value; @@ -49,6 +70,10 @@ protected: bool goodSuffix(const char *suffix, const char * const end) const; bool checkValue(const char *start, const int size); bool checkList(const String &list); + +private: + /// whether and why Content-Length is prohibited + const char *prohibitedAndIgnored_; }; } // namespace Http diff --git a/src/http/Message.cc b/src/http/Message.cc index 37afd987af..1dc4f5c75f 100644 --- a/src/http/Message.cc +++ b/src/http/Message.cc @@ -10,6 +10,7 @@ #include "squid.h" #include "Debug.h" +#include "http/ContentLengthInterpreter.h" #include "http/Message.h" #include "http/one/Parser.h" #include "HttpHdrCc.h" @@ -205,7 +206,9 @@ Http::Message::httpMsgParseStep(const char *buf, int len, int atEnd) */ if (pstate == Http::Message::psReadyToParseHeaders) { size_t hsize = 0; - const int parsed = header.parse(parse_start, parse_len, atEnd, hsize); + Http::ContentLengthInterpreter interpreter; + configureContentLengthInterpreter(interpreter); + const int parsed = header.parse(parse_start, parse_len, atEnd, hsize, interpreter); if (parsed <= 0) { PROF_stop(HttpMsg_httpMsgParseStep); return !parsed ? 0 : httpMsgParseError(); @@ -220,12 +223,13 @@ Http::Message::httpMsgParseStep(const char *buf, int len, int atEnd) } bool -Http::Message::parseHeader(Http1::Parser &hp) +Http::Message::parseHeader(Http1::Parser &hp, Http::ContentLengthInterpreter &clen) { // HTTP/1 message contains "zero or more header fields" // zero does not need parsing // XXX: c_str() reallocates. performance regression. - if (hp.headerBlockSize() && !header.parse(hp.mimeHeader().c_str(), hp.headerBlockSize())) { + configureContentLengthInterpreter(clen); + if (hp.headerBlockSize() && !header.parse(hp.mimeHeader().c_str(), hp.headerBlockSize(), clen)) { pstate = Http::Message::psError; return false; } diff --git a/src/http/Message.h b/src/http/Message.h index 280ac60c0b..53c4bbbd6b 100644 --- a/src/http/Message.h +++ b/src/http/Message.h @@ -112,9 +112,6 @@ public: virtual int httpMsgParseError(); - // Parser-NG transitional parsing of mime headers - bool parseHeader(Http1::Parser &); // TODO move this function to the parser - virtual bool expectingBody(const HttpRequestMethod&, int64_t&) const = 0; void firstLineBuf(MemBuf&); @@ -136,6 +133,12 @@ protected: virtual bool parseFirstLine(const char *blk_start, const char *blk_end) = 0; virtual void hdrCacheInit(); + + /// configures the interpreter as needed + virtual void configureContentLengthInterpreter(Http::ContentLengthInterpreter &) = 0; + + // Parser-NG transitional parsing of mime headers + bool parseHeader(Http1::Parser &, Http::ContentLengthInterpreter &); // TODO move this function to the parser }; } // namespace Http diff --git a/src/http/StatusCode.h b/src/http/StatusCode.h index ea9234cff0..3d9f88cb2a 100644 --- a/src/http/StatusCode.h +++ b/src/http/StatusCode.h @@ -88,6 +88,10 @@ typedef enum { } StatusCode; const char *StatusCodeString(const Http::StatusCode status); +/// whether this is an informational 1xx response status code +inline bool Is1xx(const int sc) { return scContinue <= sc && sc < scOkay; } +/// whether this response status code prohibits sending Content-Length +inline bool ProhibitsContentLength(const StatusCode sc) { return sc == scNoContent || Is1xx(sc); } } // namespace Http diff --git a/src/http/forward.h b/src/http/forward.h index df7d5ee109..a43827bfc8 100644 --- a/src/http/forward.h +++ b/src/http/forward.h @@ -14,6 +14,8 @@ namespace Http { +class ContentLengthInterpreter; + class Message; typedef RefCount MessagePointer; diff --git a/src/servers/Http1Server.cc b/src/servers/Http1Server.cc index 0ab2dbee73..7a8edcf19d 100644 --- a/src/servers/Http1Server.cc +++ b/src/servers/Http1Server.cc @@ -335,6 +335,8 @@ Http::One::Server::writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &ca // apply selected clientReplyContext::buildReplyHeader() mods // it is not clear what headers are required for control messages rep->header.removeHopByHopEntries(); + // paranoid: ContentLengthInterpreter has cleaned non-generated replies + rep->removeIrrelevantContentLength(); rep->header.putStr(Http::HdrType::CONNECTION, "keep-alive"); httpHdrMangleList(&rep->header, http->request, http->al, ROR_REPLY); diff --git a/src/ssl/ErrorDetailManager.cc b/src/ssl/ErrorDetailManager.cc index 3a348558ef..c053a52cb4 100644 --- a/src/ssl/ErrorDetailManager.cc +++ b/src/ssl/ErrorDetailManager.cc @@ -10,6 +10,7 @@ #include "ErrorDetail.h" #include "ErrorDetailManager.h" #include "errorpage.h" +#include "http/ContentLengthInterpreter.h" #include "mime_header.h" void Ssl::errorDetailInitialize() @@ -212,7 +213,9 @@ Ssl::ErrorDetailFile::parse(const char *buffer, int len, bool eof) if ( s != e) { DetailEntryParser parser; - if (!parser.parse(s, e - s)) { + Http::ContentLengthInterpreter interpreter; + // no applyStatusCodeRules() -- error templates lack HTTP status code + if (!parser.parse(s, e - s, interpreter)) { debugs(83, DBG_IMPORTANT, HERE << "WARNING! parse error on:" << s); return false; diff --git a/src/tests/stub_HttpReply.cc b/src/tests/stub_HttpReply.cc index ff20c4e3c2..f22d324e04 100644 --- a/src/tests/stub_HttpReply.cc +++ b/src/tests/stub_HttpReply.cc @@ -32,4 +32,5 @@ bool HttpReply::inheritProperties(const Http::Message *aMsg) STUB_RETVAL(false) bool HttpReply::updateOnNotModified(HttpReply const*) STUB_RETVAL(false) int64_t HttpReply::bodySize(const HttpRequestMethod&) const STUB_RETVAL(0) const HttpHdrContRange *HttpReply::contentRange() const STUB_RETVAL(nullptr) +void HttpReply::configureContentLengthInterpreter(Http::ContentLengthInterpreter &) STUB -- 2.47.2