-
/*
- * $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
* 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)
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);
}
/*
*/
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;
httpHdrContRangeParseCreate(const char *str)
{
HttpHdrContRange *r = httpHdrContRangeCreate();
+
if (!httpHdrContRangeParseInit(r, str)) {
- httpHdrContRangeDestroy(r);
- r = NULL;
+ httpHdrContRangeDestroy(r);
+ r = NULL;
}
+
return r;
}
{
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;
}
httpHdrContRangeDestroy(HttpHdrContRange * range)
{
assert(range);
- memFree(MEM_HTTP_HDR_CONTENT_RANGE, range);
+ memFree(range, MEM_HTTP_HDR_CONTENT_RANGE);
}
HttpHdrContRange *
{
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;
}
+