]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpHdrContRange.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / HttpHdrContRange.cc
CommitLineData
7c887d1f 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7c887d1f 7 */
8
bbc27441
AJ
9/* DEBUG: section 68 HTTP Content-Range Header */
10
582c2af2
FC
11#include "squid.h"
12#include "Debug.h"
13#include "enums.h"
528b2c61 14#include "HttpHdrContRange.h"
582c2af2 15#include "HttpHeaderTools.h"
7c887d1f 16
b644367b 17/*
18 * Currently only byte ranges are supported
19 *
20 * Content-Range = "Content-Range" ":" content-range-spec
21 * content-range-spec = byte-content-range-spec
22 * byte-content-range-spec = bytes-unit SP
23 * ( byte-range-resp-spec | "*") "/"
24 * ( entity-length | "*" )
25 * byte-range-resp-spec = first-byte-pos "-" last-byte-pos
26 * entity-length = 1*DIGIT
27 */
7c887d1f 28
7c887d1f 29/* local constants */
ed013b6c 30#define range_spec_unknown (-1)
7c887d1f 31
32/* local routines */
33#define known_spec(s) ((s) != range_spec_unknown)
34#define size_min(a,b) ((a) <= (b) ? (a) : (b))
35#define size_diff(a,b) ((a) >= (b) ? ((a)-(b)) : 0)
36
37/* globals */
38
39/* parses range-resp-spec and inits spec, returns true on success */
40static int
b644367b 41httpHdrRangeRespSpecParseInit(HttpHdrRangeSpec * spec, const char *field, int flen)
7c887d1f 42{
43 const char *p;
44 assert(spec);
45 spec->offset = spec->length = range_spec_unknown;
62e76326 46
7c887d1f 47 if (flen < 2)
62e76326 48 return 0;
49
7c887d1f 50 /* is spec given ? */
51 if (*field == '*')
62e76326 52 return 1;
53
7c887d1f 54 /* check format, must be %d-%d */
b644367b 55 if (!((p = strchr(field, '-')) && (p - field < flen))) {
bf8fe701 56 debugs(68, 2, "invalid (no '-') resp-range-spec near: '" << field << "'");
62e76326 57 return 0;
7c887d1f 58 }
62e76326 59
7c887d1f 60 /* parse offset */
47f6e231 61 if (!httpHeaderParseOffset(field, &spec->offset))
62e76326 62 return 0;
63
03a7e69c
HN
64 /* Additional check for BUG2155 - there MUST BE first-byte-pos and it MUST be positive*/
65 if (spec->offset < 0) {
66 debugs(68, 2, "invalid (no first-byte-pos or it is negative) resp-range-spec near: '" << field << "'");
67 return 0;
68 }
69
95dc7ff4 70 ++p;
62e76326 71
7c887d1f 72 /* do we have last-pos ? */
03a7e69c
HN
73 if (p - field >= flen) {
74 debugs(68, 2, "invalid (no last-byte-pos) resp-range-spec near: '" << field << "'");
75 return 0;
76 }
77
78 int64_t last_pos;
62e76326 79
03a7e69c
HN
80 if (!httpHeaderParseOffset(p, &last_pos))
81 return 0;
62e76326 82
03a7e69c
HN
83 if (last_pos < spec->offset) {
84 debugs(68, 2, "invalid (negative last-byte-pos) resp-range-spec near: '" << field << "'");
85 return 0;
7c887d1f 86 }
62e76326 87
03a7e69c
HN
88 spec->length = size_diff(last_pos + 1, spec->offset);
89
7c887d1f 90 /* we managed to parse, check if the result makes sence */
03a7e69c 91 if (spec->length <= 0) {
4a7a3d56 92 debugs(68, 2, "invalid range (" << spec->offset << " += " <<
bf8fe701 93 (long int) spec->length << ") in resp-range-spec near: '" << field << "'");
62e76326 94 return 0;
7c887d1f 95 }
62e76326 96
7c887d1f 97 return 1;
98}
99
100static void
b644367b 101httpHdrRangeRespSpecPackInto(const HttpHdrRangeSpec * spec, Packer * p)
7c887d1f 102{
e6ccf245 103 /* Ensure typecast is safe */
104 assert (spec->length >= 0);
62e76326 105
47f6e231 106 if (!known_spec(spec->offset) || !known_spec(spec->length))
62e76326 107 packerPrintf(p, "*");
7c887d1f 108 else
c91ca3ce 109 packerPrintf(p, "bytes %" PRId64 "-%" PRId64,
47f6e231 110 spec->offset, spec->offset + spec->length - 1);
7c887d1f 111}
112
113/*
114 * Content Range
115 */
116
117HttpHdrContRange *
9bc73deb 118httpHdrContRangeCreate(void)
7c887d1f 119{
e6ccf245 120 HttpHdrContRange *r = (HttpHdrContRange *)memAllocate(MEM_HTTP_HDR_CONTENT_RANGE);
7c887d1f 121 r->spec.offset = r->spec.length = range_spec_unknown;
122 r->elength = range_spec_unknown;
123 return r;
124}
125
126HttpHdrContRange *
127httpHdrContRangeParseCreate(const char *str)
128{
129 HttpHdrContRange *r = httpHdrContRangeCreate();
62e76326 130
7c887d1f 131 if (!httpHdrContRangeParseInit(r, str)) {
62e76326 132 httpHdrContRangeDestroy(r);
133 r = NULL;
7c887d1f 134 }
62e76326 135
7c887d1f 136 return r;
137}
138
139/* returns true if ranges are valid; inits HttpHdrContRange */
140int
b644367b 141httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str)
7c887d1f 142{
143 const char *p;
144 assert(range && str);
bf8fe701 145 debugs(68, 8, "parsing content-range field: '" << str << "'");
de336bbe 146 /* check range type */
62e76326 147
de336bbe 148 if (strncasecmp(str, "bytes ", 6))
62e76326 149 return 0;
150
de336bbe 151 str += 6;
62e76326 152
7c887d1f 153 /* split */
154 if (!(p = strchr(str, '/')))
62e76326 155 return 0;
156
7c887d1f 157 if (*str == '*')
62e76326 158 range->spec.offset = range->spec.length = range_spec_unknown;
b644367b 159 else if (!httpHdrRangeRespSpecParseInit(&range->spec, str, p - str))
62e76326 160 return 0;
161
95dc7ff4 162 ++p;
62e76326 163
7c887d1f 164 if (*p == '*')
62e76326 165 range->elength = range_spec_unknown;
47f6e231 166 else if (!httpHeaderParseOffset(p, &range->elength))
62e76326 167 return 0;
03a7e69c
HN
168 else if (range->elength <= 0) {
169 /* Additional paranoidal check for BUG2155 - entity-length MUST be > 0 */
170 debugs(68, 2, "invalid (entity-length is negative) content-range-spec near: '" << str << "'");
171 return 0;
172 } else if (known_spec(range->spec.length) && range->elength < (range->spec.offset + range->spec.length)) {
173 debugs(68, 2, "invalid (range is outside entity-length) content-range-spec near: '" << str << "'");
174 return 0;
175 }
62e76326 176
26ac0430
AJ
177 debugs(68, 8, "parsed content-range field: " <<
178 (long int) range->spec.offset << "-" <<
179 (long int) range->spec.offset + range->spec.length - 1 << " / " <<
180 (long int) range->elength);
62e76326 181
7c887d1f 182 return 1;
183}
184
185void
b644367b 186httpHdrContRangeDestroy(HttpHdrContRange * range)
7c887d1f 187{
188 assert(range);
db1cd23c 189 memFree(range, MEM_HTTP_HDR_CONTENT_RANGE);
7c887d1f 190}
191
192HttpHdrContRange *
193httpHdrContRangeDup(const HttpHdrContRange * range)
194{
195 HttpHdrContRange *dup;
196 assert(range);
197 dup = httpHdrContRangeCreate();
198 *dup = *range;
199 return dup;
200}
201
202void
203httpHdrContRangePackInto(const HttpHdrContRange * range, Packer * p)
204{
205 assert(range && p);
206 httpHdrRangeRespSpecPackInto(&range->spec, p);
e6ccf245 207 /* Ensure typecast is safe */
208 assert (range->elength >= 0);
62e76326 209
47f6e231 210 if (!known_spec(range->elength))
62e76326 211 packerPrintf(p, "/*");
7c887d1f 212 else
c91ca3ce 213 packerPrintf(p, "/%" PRId64, range->elength);
7c887d1f 214}
d192d11f 215
216void
47f6e231 217httpHdrContRangeSet(HttpHdrContRange * cr, HttpHdrRangeSpec spec, int64_t ent_len)
d192d11f 218{
219 assert(cr && ent_len >= 0);
220 cr->spec = spec;
221 cr->elength = ent_len;
222}
f53969cc 223