]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Do not send Content-Length in 1xx or 204 responses (#249)
authorEduard Bagdasaryan <eduard.bagdasaryan@measurement-factory.com>
Tue, 31 Jul 2018 22:08:31 +0000 (22:08 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Wed, 1 Aug 2018 12:29:40 +0000 (12:29 +0000)
This is RFC 7230 section 3.3.2 requirement.

22 files changed:
src/HttpHeader.cc
src/HttpHeader.h
src/HttpReply.cc
src/HttpReply.h
src/HttpRequest.cc
src/HttpRequest.h
src/adaptation/icap/ModXact.cc
src/client_side_reply.cc
src/clients/FtpRelay.cc
src/ftp/Elements.h
src/htcp.cc
src/htcp.h
src/http.cc
src/http/ContentLengthInterpreter.cc
src/http/ContentLengthInterpreter.h
src/http/Message.cc
src/http/Message.h
src/http/StatusCode.h
src/http/forward.h
src/servers/Http1Server.cc
src/ssl/ErrorDetailManager.cc
src/tests/stub_HttpReply.cc

index 185399fafc3a44548597fad6eddb5ffd3670a7be..488e8f986f8a517277a80f749954861c58a586fd 100644 (file)
@@ -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 "<name>:[ws]<value>" lines delimited by <CRLF>.
      * 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);
index cc21d3e0c151dea05b148d885ad1a64fa14331b6..6e8f58bda580c1637841c445b8fb7e36074feff5 100644 (file)
@@ -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;
index 954876a02684c334b290d907a5071cb7786b1ad5..3adf08968a4efc12f1a56df9b3135266153c143e 100644 (file)
@@ -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");
+}
+
index 7860ff04d77f43995a6c8d566553f9ce22632c87..ab227c2cdf5f57cb03e4c14c5cd4bc4f6e9efe0b 100644 (file)
@@ -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();
index 72cb7f279e2579e2e9a7df54eac61123baac949d..d2f9e7f1d53c518ba71d107ec0054a3d181b04c7 100644 (file)
@@ -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()
 {
index eee849adcd45b332b15cc20cab3ce56ad7c371f0..138b2181b2d8537c8149eeb9a709118fea9acf49 100644 (file)
@@ -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 */
 
index 332ea5aeba0fcd320d3bdeac18685e0205653158..2a25d2a4fe9fecf13560cef29fa273539301b1f3 100644 (file)
@@ -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;
index 355863266b3330b2e2874f2e6a901b6cafad8430..04480b7eca82fc8361b01ffb9e2211c95c6545ae 100644 (file)
@@ -1408,6 +1408,8 @@ clientReplyContext::buildReplyHeader()
     }
 
     reply->header.removeHopByHopEntries();
+    // paranoid: ContentLengthInterpreter has cleaned non-generated replies
+    reply->removeIrrelevantContentLength();
 
     //    if (request->range)
     //      clientBuildRangeHeader(http, reply);
index b686d5c0d07f6cf8b590c72fe76317ab41e7975d..4d3b790b7ffa6019a939c10714160851b888ddde 100644 (file)
@@ -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
index 40d07d1b6037246e19907172c033ce4c8dc61f28..0676df9c31651b5e6c6a0dafd092d8002294d49e 100644 (file)
@@ -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 */
index f77d09dcbec7df419fba846c36e30883cb28f28e..87bd3d7a9de4d1b9ba004ec3bc7a805f809d9429 100644 (file)
@@ -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));
index ac2cdbe45cf6b8fac6af6c61f88642adf402858b..1f6b77a02bd78bdf297d5952c13623ec3db32548 100644 (file)
@@ -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;
index f3dcf010a83a7b63c7aa0c27b46a882192d9abab..5810ac93515ada15b230bf3d08022ae1041f7424 100644 (file)
@@ -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;
index f69d5eb0ca0b06037c5836d4fab5470b90270528..e2ac07ad6452ac0d778d2318a465be9c167e06a8 100644 (file)
 #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)
 {
 }
 
index 6801c1f0e5dd022b9e74ade7a25b6b9ccdf2e747..8b02e84316f027faae13c6969d89f94fae62d0c3 100644 (file)
@@ -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
index 37afd987afaf95d03dcb37ef3d1ecef6008abce4..1dc4f5c75f06d4914ecf57eb811bbd7ccabee9c6 100644 (file)
@@ -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;
     }
index 280ac60c0b4718136e0b56843612a9dfe030c288..53c4bbbd6b111e6f3179d069bcdf4da3c3b309e0 100644 (file)
@@ -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
index ea9234cff0c72c00b1a01608264644ea26bb86ca..3d9f88cb2a2cd9a83670ca0c4cdd1cc82255371d 100644 (file)
@@ -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
 
index df7d5ee109f0406029f4ce03ddb1f80802247406..a43827bfc8dc93b0c294fda9f2ce817437066718 100644 (file)
@@ -14,6 +14,8 @@
 namespace Http
 {
 
+class ContentLengthInterpreter;
+
 class Message;
 typedef RefCount<Http::Message> MessagePointer;
 
index 0ab2dbee73850c2ccd4c2b2428cca2a92229da0e..7a8edcf19dc833d488fe7798055239bbba045239 100644 (file)
@@ -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);
 
index 3a348558efd2ca0787eb2c068ef388eb50179ee2..c053a52cb4fa391e0e2c3d05aabaab436ae4f214 100644 (file)
@@ -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;
index ff20c4e3c2ea578d76e0e903e38376e30482bbe9..f22d324e046a2286e922f21c2f51622bd75be950 100644 (file)
@@ -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