]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Handle more partial responses (#791)
authorAlex Rousskov <rousskov@measurement-factory.com>
Fri, 2 Apr 2021 07:46:20 +0000 (07:46 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Fri, 2 Apr 2021 07:46:23 +0000 (07:46 +0000)
src/HttpHdrContRange.cc
src/HttpHeaderRange.h
src/clients/Client.cc
src/http/Stream.cc

index 8270e0f11aa26dc3ee1b5435890c6a94136b71f8..79a507fb84cb8ea41210db93ae9e7d921a9f29c7 100644 (file)
@@ -161,9 +161,13 @@ httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str)
 
     ++p;
 
-    if (*p == '*')
+    if (*p == '*') {
+        if (!known_spec(range->spec.offset)) {
+            debugs(68, 2, "invalid (*/*) content-range-spec near: '" << str << "'");
+            return 0;
+        }
         range->elength = range_spec_unknown;
-    else if (!httpHeaderParseOffset(p, &range->elength))
+    else if (!httpHeaderParseOffset(p, &range->elength))
         return 0;
     else if (range->elength <= 0) {
         /* Additional paranoidal check for BUG2155 - entity-length MUST be > 0 */
@@ -174,6 +178,12 @@ httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str)
         return 0;
     }
 
+    // reject unsatisfied-range and such; we only use well-defined ranges today
+    if (!known_spec(range->spec.offset) || !known_spec(range->spec.length)) {
+        debugs(68, 2, "unwanted content-range-spec near: '" << str << "'");
+        return 0;
+    }
+
     debugs(68, 8, "parsed content-range field: " <<
            (long int) range->spec.offset << "-" <<
            (long int) range->spec.offset + range->spec.length - 1 << " / " <<
index 6d93e72b2b8276323bdb357721f2a6e20fba9e5a..bf54c8562ba573f250cf44085bc28481f2157af7 100644 (file)
 class HttpReply;
 class Packable;
 
-/* http byte-range-spec */
-
+// TODO: Refactor to disambiguate and provide message-specific APIs.
+/// either byte-range-spec (in a request Range header)
+/// or suffix-byte-range-spec (in a request Range header)
+/// or byte-range part of byte-range-resp (in a response Content-Range header)
+/// or "*" part of unsatisfied-range (in a response Content-Range header)
 class HttpHdrRangeSpec
 {
     MEMPROXY_CLASS(HttpHdrRangeSpec);
index dfb13d053c310022ca1ad0c707170e45b1562f32..2a2f0e8f878aae5d2e28f8c40d384c2b49559d70 100644 (file)
@@ -520,8 +520,11 @@ Client::haveParsedReplyHeaders()
     maybePurgeOthers();
 
     // adaptation may overwrite old offset computed using the virgin response
-    const bool partial = theFinalReply->contentRange();
-    currentOffset = partial ? theFinalReply->contentRange()->spec.offset : 0;
+    currentOffset = 0;
+    if (const auto cr = theFinalReply->contentRange()) {
+        if (cr->spec.offset != HttpHdrRangeSpec::UnknownPosition)
+            currentOffset = cr->spec.offset;
+    }
 }
 
 /// whether to prevent caching of an otherwise cachable response
index 9e346b9d99d9ca12106bca36b32ec9defcbd19ee..d685a22306e6bbd11aa5cd22eb114f329b477eb1 100644 (file)
@@ -171,12 +171,13 @@ Http::Stream::getNextRangeOffset() const
             return start;
         }
 
-    } else if (reply && reply->contentRange()) {
+    } else if (const auto cr = reply ? reply->contentRange() : nullptr) {
         /* request does not have ranges, but reply does */
         /* TODO: should use range_iter_pos on reply, as soon as reply->content_range
          *        becomes HttpHdrRange rather than HttpHdrRangeSpec.
          */
-        return http->out.offset + reply->contentRange()->spec.offset;
+        if (cr->spec.offset != HttpHdrRangeSpec::UnknownPosition)
+            return http->out.offset + cr->spec.offset;
     }
 
     return http->out.offset;
@@ -240,6 +241,10 @@ Http::Stream::socketState()
 
             // did we get at least what we expected, based on range specs?
 
+            // this Content-Range does not tell us how many bytes to expect
+            if (bytesExpected == HttpHdrRangeSpec::UnknownPosition)
+                return STREAM_NONE;
+
             if (bytesSent == bytesExpected) // got everything
                 return STREAM_COMPLETE;