]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/HttpHdrContRange.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / HttpHdrContRange.cc
index d1993a09d0261d47165f4651b5d35eb3a6639e09..98eebf1bb69927358645a35f6c4a5c130c207731 100644 (file)
@@ -1,39 +1,18 @@
-
 /*
- * $Id: HttpHdrContRange.cc,v 1.9 1998/09/23 21:52:20 rousskov Exp $
- *
- * DEBUG: section 68    HTTP Content-Range Header
- * AUTHOR: Alex Rousskov
- *
- * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from the
- *  Internet community.  Development is led by Duane Wessels of the
- *  National Laboratory for Applied Network Research and funded by the
- *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
- *  Duane Wessels and the University of California San Diego.  Please
- *  see the COPYRIGHT file for full details.  Squid incorporates
- *  software developed and/or copyrighted by other sources.  Please 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-2015 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 68    HTTP Content-Range Header */
+
 #include "squid.h"
+#include "Debug.h"
+#include "enums.h"
+#include "HttpHdrContRange.h"
+#include "HttpHeaderTools.h"
 
 /*
  *    Currently only byte ranges are supported
@@ -47,9 +26,8 @@
  *    entity-length        = 1*DIGIT
  */
 
-
 /* local constants */
-#define range_spec_unknown ((size_t)-1)
+#define range_spec_unknown (-1)
 
 /* local routines */
 #define known_spec(s) ((s) != range_spec_unknown)
@@ -65,44 +43,71 @@ httpHdrRangeRespSpecParseInit(HttpHdrRangeSpec * spec, const char *field, int fl
     const char *p;
     assert(spec);
     spec->offset = spec->length = range_spec_unknown;
+
     if (flen < 2)
-       return 0;
+        return 0;
+
     /* is spec given ? */
     if (*field == '*')
-       return 1;
+        return 1;
+
     /* check format, must be %d-%d */
     if (!((p = strchr(field, '-')) && (p - field < flen))) {
-       debug(68, 2) ("invalid (no '-') resp-range-spec near: '%s'\n", field);
-       return 0;
+        debugs(68, 2, "invalid (no '-') resp-range-spec near: '" << field << "'");
+        return 0;
     }
+
     /* parse offset */
-    if (!httpHeaderParseSize(field, &spec->offset))
-       return 0;
-    p++;
+    if (!httpHeaderParseOffset(field, &spec->offset))
+        return 0;
+
+    /* Additional check for BUG2155 - there MUST BE first-byte-pos and it MUST be positive*/
+    if (spec->offset < 0) {
+        debugs(68, 2, "invalid (no first-byte-pos or it is negative) resp-range-spec near: '" << field << "'");
+        return 0;
+    }
+
+    ++p;
+
     /* do we have last-pos ? */
-    if (p - field < flen) {
-       size_t last_pos;
-       if (!httpHeaderParseSize(p, &last_pos))
-           return 0;
-       spec->length = size_diff(last_pos + 1, spec->offset);
+    if (p - field >= flen) {
+        debugs(68, 2, "invalid (no last-byte-pos) resp-range-spec near: '" << field << "'");
+        return 0;
+    }
+
+    int64_t last_pos;
+
+    if (!httpHeaderParseOffset(p, &last_pos))
+        return 0;
+
+    if (last_pos < spec->offset) {
+        debugs(68, 2, "invalid (negative last-byte-pos) resp-range-spec near: '" << field << "'");
+        return 0;
     }
+
+    spec->length = size_diff(last_pos + 1, spec->offset);
+
     /* we managed to parse, check if the result makes sence */
-    if (known_spec(spec->length) && !spec->length) {
-       debug(68, 2) ("invalid range (%d += %d) in resp-range-spec near: '%s'\n",
-           spec->offset, spec->length, field);
-       return 0;
+    if (spec->length <= 0) {
+        debugs(68, 2, "invalid range (" << spec->offset << " += " <<
+               (long int) spec->length << ") in resp-range-spec near: '" << field << "'");
+        return 0;
     }
+
     return 1;
 }
 
 static void
 httpHdrRangeRespSpecPackInto(const HttpHdrRangeSpec * spec, Packer * p)
 {
+    /* Ensure typecast is safe */
+    assert (spec->length >= 0);
+
     if (!known_spec(spec->offset) || !known_spec(spec->length))
-       packerPrintf(p, "*");
+        packerPrintf(p, "*");
     else
-       packerPrintf(p, "bytes %d-%d",
-           spec->offset, spec->offset + spec->length - 1);
+        packerPrintf(p, "bytes %" PRId64 "-%" PRId64,
+                     spec->offset, spec->offset + spec->length - 1);
 }
 
 /*
@@ -110,9 +115,9 @@ httpHdrRangeRespSpecPackInto(const HttpHdrRangeSpec * spec, Packer * p)
  */
 
 HttpHdrContRange *
-httpHdrContRangeCreate()
+httpHdrContRangeCreate(void)
 {
-    HttpHdrContRange *r = memAllocate(MEM_HTTP_HDR_CONTENT_RANGE);
+    HttpHdrContRange *r = (HttpHdrContRange *)memAllocate(MEM_HTTP_HDR_CONTENT_RANGE);
     r->spec.offset = r->spec.length = range_spec_unknown;
     r->elength = range_spec_unknown;
     return r;
@@ -122,10 +127,12 @@ HttpHdrContRange *
 httpHdrContRangeParseCreate(const char *str)
 {
     HttpHdrContRange *r = httpHdrContRangeCreate();
+
     if (!httpHdrContRangeParseInit(r, str)) {
-       httpHdrContRangeDestroy(r);
-       r = NULL;
+        httpHdrContRangeDestroy(r);
+        r = NULL;
     }
+
     return r;
 }
 
@@ -135,26 +142,43 @@ httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str)
 {
     const char *p;
     assert(range && str);
-    debug(68, 8) ("parsing content-range field: '%s'\n", str);
+    debugs(68, 8, "parsing content-range field: '" << str << "'");
     /* check range type */
+
     if (strncasecmp(str, "bytes ", 6))
-       return 0;
+        return 0;
+
     str += 6;
+
     /* split */
     if (!(p = strchr(str, '/')))
-       return 0;
+        return 0;
+
     if (*str == '*')
-       range->spec.offset = range->spec.length = range_spec_unknown;
+        range->spec.offset = range->spec.length = range_spec_unknown;
     else if (!httpHdrRangeRespSpecParseInit(&range->spec, str, p - str))
-       return 0;
-    p++;
+        return 0;
+
+    ++p;
+
     if (*p == '*')
-       range->elength = range_spec_unknown;
-    else if (!httpHeaderParseSize(p, &range->elength))
-       return 0;
-    debug(68, 8) ("parsed content-range field: %d-%d / %d\n",
-       range->spec.offset, range->spec.offset + range->spec.length - 1,
-       range->elength);
+        range->elength = range_spec_unknown;
+    else if (!httpHeaderParseOffset(p, &range->elength))
+        return 0;
+    else if (range->elength <= 0) {
+        /* Additional paranoidal check for BUG2155 - entity-length MUST be > 0 */
+        debugs(68, 2, "invalid (entity-length is negative) content-range-spec near: '" << str << "'");
+        return 0;
+    } else if (known_spec(range->spec.length) && range->elength < (range->spec.offset + range->spec.length)) {
+        debugs(68, 2, "invalid (range is outside entity-length) 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 << " / " <<
+           (long int) range->elength);
+
     return 1;
 }
 
@@ -162,7 +186,7 @@ void
 httpHdrContRangeDestroy(HttpHdrContRange * range)
 {
     assert(range);
-    memFree(MEM_HTTP_HDR_CONTENT_RANGE, range);
+    memFree(range, MEM_HTTP_HDR_CONTENT_RANGE);
 }
 
 HttpHdrContRange *
@@ -180,16 +204,20 @@ httpHdrContRangePackInto(const HttpHdrContRange * range, Packer * p)
 {
     assert(range && p);
     httpHdrRangeRespSpecPackInto(&range->spec, p);
+    /* Ensure typecast is safe */
+    assert (range->elength >= 0);
+
     if (!known_spec(range->elength))
-       packerPrintf(p, "/*");
+        packerPrintf(p, "/*");
     else
-       packerPrintf(p, "/%d", range->elength);
+        packerPrintf(p, "/%" PRId64, range->elength);
 }
 
 void
-httpHdrContRangeSet(HttpHdrContRange * cr, HttpHdrRangeSpec spec, size_t ent_len)
+httpHdrContRangeSet(HttpHdrContRange * cr, HttpHdrRangeSpec spec, int64_t ent_len)
 {
     assert(cr && ent_len >= 0);
     cr->spec = spec;
     cr->elength = ent_len;
 }
+