]>
Commit | Line | Data |
---|---|---|
b5107edb | 1 | |
2 | /* | |
47f6e231 | 3 | * $Id: HttpHdrRange.cc,v 1.45 2007/08/13 17:20:51 hno Exp $ |
b5107edb | 4 | * |
d76fcfa7 | 5 | * DEBUG: section 64 HTTP Range Header |
b5107edb | 6 | * AUTHOR: Alex Rousskov |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
b5107edb | 10 | * |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
b5107edb | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
b5107edb | 34 | */ |
35 | ||
36 | #include "squid.h" | |
e6ccf245 | 37 | #include "Store.h" |
528b2c61 | 38 | #include "HttpHeaderRange.h" |
39 | #include "client_side_request.h" | |
924f73bc | 40 | #include "HttpReply.h" |
b5107edb | 41 | |
b644367b | 42 | /* |
43 | * Currently only byte ranges are supported | |
44 | * | |
45 | * Essentially, there are three types of byte ranges: | |
46 | * | |
47 | * 1) first-byte-pos "-" last-byte-pos // range | |
48 | * 2) first-byte-pos "-" // trailer | |
49 | * 3) "-" suffix-length // suffix (last length bytes) | |
50 | * | |
51 | * | |
52 | * When Range field is parsed, we have no clue about the content | |
53 | * length of the document. Thus, we simply code an "absent" part | |
528b2c61 | 54 | * using HttpHdrRangeSpec::UnknownPosition constant. |
b644367b | 55 | * |
56 | * Note: when response length becomes known, we convert any range | |
57 | * spec into type one above. (Canonization process). | |
58 | */ | |
b5107edb | 59 | |
60 | ||
b5107edb | 61 | /* local routines */ |
528b2c61 | 62 | #define known_spec(s) ((s) > HttpHdrRangeSpec::UnknownPosition) |
b5107edb | 63 | |
64 | /* globals */ | |
528b2c61 | 65 | size_t HttpHdrRange::ParsedCount = 0; |
47f6e231 | 66 | int64_t const HttpHdrRangeSpec::UnknownPosition = -1; |
b5107edb | 67 | |
68 | /* | |
69 | * Range-Spec | |
70 | */ | |
71 | ||
528b2c61 | 72 | HttpHdrRangeSpec::HttpHdrRangeSpec() : offset(UnknownPosition), length(UnknownPosition){} |
73 | ||
b5107edb | 74 | /* parses range-spec and returns new object on success */ |
528b2c61 | 75 | HttpHdrRangeSpec * |
76 | HttpHdrRangeSpec::Create(const char *field, int flen) | |
77 | { | |
78 | HttpHdrRangeSpec spec; | |
62e76326 | 79 | |
528b2c61 | 80 | if (!spec.parseInit(field, flen)) |
62e76326 | 81 | return NULL; |
82 | ||
528b2c61 | 83 | return new HttpHdrRangeSpec(spec); |
84 | } | |
85 | ||
86 | bool | |
87 | HttpHdrRangeSpec::parseInit(const char *field, int flen) | |
b5107edb | 88 | { |
b5107edb | 89 | const char *p; |
62e76326 | 90 | |
b5107edb | 91 | if (flen < 2) |
62e76326 | 92 | return false; |
93 | ||
b5107edb | 94 | /* is it a suffix-byte-range-spec ? */ |
95 | if (*field == '-') { | |
47f6e231 | 96 | if (!httpHeaderParseOffset(field + 1, &length)) |
62e76326 | 97 | return false; |
b5107edb | 98 | } else |
62e76326 | 99 | /* must have a '-' somewhere in _this_ field */ |
100 | if (!((p = strchr(field, '-')) || (p - field >= flen))) { | |
bf8fe701 | 101 | debugs(64, 2, "ignoring invalid (missing '-') range-spec near: '" << field << "'"); |
62e76326 | 102 | return false; |
103 | } else { | |
47f6e231 | 104 | if (!httpHeaderParseOffset(field, &offset)) |
62e76326 | 105 | return false; |
106 | ||
107 | p++; | |
108 | ||
109 | /* do we have last-pos ? */ | |
110 | if (p - field < flen) { | |
47f6e231 | 111 | int64_t last_pos; |
62e76326 | 112 | |
47f6e231 | 113 | if (!httpHeaderParseOffset(p, &last_pos)) |
62e76326 | 114 | return false; |
115 | ||
116 | HttpHdrRangeSpec::HttpRange aSpec (offset, last_pos + 1); | |
117 | ||
118 | length = aSpec.size(); | |
119 | } | |
120 | } | |
121 | ||
b5107edb | 122 | /* we managed to parse, check if the result makes sence */ |
528b2c61 | 123 | if (length == 0) { |
bf8fe701 | 124 | debugs(64, 2, "ignoring invalid (zero length) range-spec near: '" << field << "'"); |
62e76326 | 125 | return false; |
b5107edb | 126 | } |
62e76326 | 127 | |
528b2c61 | 128 | return true; |
b5107edb | 129 | } |
130 | ||
528b2c61 | 131 | void |
132 | HttpHdrRangeSpec::packInto(Packer * packer) const | |
02922e76 | 133 | { |
528b2c61 | 134 | if (!known_spec(offset)) /* suffix */ |
47f6e231 | 135 | packerPrintf(packer, "-%"PRId64, length); |
528b2c61 | 136 | else if (!known_spec(length)) /* trailer */ |
47f6e231 | 137 | packerPrintf(packer, "%"PRId64"-", offset); |
528b2c61 | 138 | else /* range */ |
47f6e231 | 139 | packerPrintf(packer, "%"PRId64"-%"PRId64, |
140 | offset, offset + length - 1); | |
02922e76 | 141 | } |
142 | ||
528b2c61 | 143 | void |
144 | HttpHdrRangeSpec::outputInfo( char const *note) const | |
d76fcfa7 | 145 | { |
bf8fe701 | 146 | debugs(64, 5, "HttpHdrRangeSpec::canonize: " << note << ": [" << |
47f6e231 | 147 | offset << ", " << offset + length << |
148 | ") len: " << length); | |
d76fcfa7 | 149 | } |
150 | ||
62e76326 | 151 | /* fills "absent" positions in range specification based on response body size |
b644367b | 152 | * returns true if the range is still valid |
153 | * range is valid if its intersection with [0,length-1] is not empty | |
154 | */ | |
528b2c61 | 155 | int |
47f6e231 | 156 | HttpHdrRangeSpec::canonize(int64_t clen) |
528b2c61 | 157 | { |
158 | outputInfo ("have"); | |
159 | HttpRange object(0, clen); | |
62e76326 | 160 | |
161 | if (!known_spec(offset)) /* suffix */ | |
162 | { | |
163 | assert(known_spec(length)); | |
164 | offset = object.intersection(HttpRange (clen - length, clen)).start; | |
165 | } else if (!known_spec(length)) /* trailer */ | |
166 | { | |
167 | assert(known_spec(offset)); | |
168 | HttpRange newRange = object.intersection(HttpRange (offset, clen)); | |
169 | length = newRange.size(); | |
528b2c61 | 170 | } |
b5107edb | 171 | /* we have a "range" now, adjust length if needed */ |
528b2c61 | 172 | assert(known_spec(length)); |
62e76326 | 173 | |
528b2c61 | 174 | assert(known_spec(offset)); |
62e76326 | 175 | |
528b2c61 | 176 | HttpRange newRange = object.intersection (HttpRange (offset, offset + length)); |
62e76326 | 177 | |
528b2c61 | 178 | length = newRange.size(); |
62e76326 | 179 | |
528b2c61 | 180 | outputInfo ("done"); |
62e76326 | 181 | |
528b2c61 | 182 | return length > 0; |
b5107edb | 183 | } |
184 | ||
62e76326 | 185 | /* merges recepient with donor if possible; returns true on success |
889b534a | 186 | * both specs must be canonized prior to merger, of course */ |
62e76326 | 187 | bool |
528b2c61 | 188 | HttpHdrRangeSpec::mergeWith(const HttpHdrRangeSpec * donor) |
889b534a | 189 | { |
528b2c61 | 190 | bool merged (false); |
67bff3c8 | 191 | #if MERGING_BREAKS_NOTHING |
192 | /* Note: this code works, but some clients may not like its effects */ | |
47f6e231 | 193 | int64_t rhs = offset + length; /* no -1 ! */ |
194 | const int64_t donor_rhs = donor->offset + donor->length; /* no -1 ! */ | |
528b2c61 | 195 | assert(known_spec(offset)); |
889b534a | 196 | assert(known_spec(donor->offset)); |
528b2c61 | 197 | assert(length > 0); |
889b534a | 198 | assert(donor->length > 0); |
199 | /* do we have a left hand side overlap? */ | |
62e76326 | 200 | |
528b2c61 | 201 | if (donor->offset < offset && offset <= donor_rhs) { |
62e76326 | 202 | offset = donor->offset; /* decrease left offset */ |
203 | merged = 1; | |
889b534a | 204 | } |
62e76326 | 205 | |
889b534a | 206 | /* do we have a right hand side overlap? */ |
207 | if (donor->offset <= rhs && rhs < donor_rhs) { | |
62e76326 | 208 | rhs = donor_rhs; /* increase right offset */ |
209 | merged = 1; | |
889b534a | 210 | } |
62e76326 | 211 | |
889b534a | 212 | /* adjust length if offsets have been changed */ |
213 | if (merged) { | |
62e76326 | 214 | assert(rhs > offset); |
215 | length = rhs - offset; | |
889b534a | 216 | } else { |
62e76326 | 217 | /* does recepient contain donor? */ |
218 | merged = | |
219 | offset <= donor->offset && donor->offset < rhs; | |
889b534a | 220 | } |
62e76326 | 221 | |
67bff3c8 | 222 | #endif |
889b534a | 223 | return merged; |
224 | } | |
225 | ||
b5107edb | 226 | /* |
227 | * Range | |
228 | */ | |
229 | ||
528b2c61 | 230 | HttpHdrRange::HttpHdrRange () : clen (HttpHdrRangeSpec::UnknownPosition) |
62e76326 | 231 | {} |
b5107edb | 232 | |
233 | HttpHdrRange * | |
30abd221 | 234 | HttpHdrRange::ParseCreate(const String * range_spec) |
b5107edb | 235 | { |
528b2c61 | 236 | HttpHdrRange *r = new HttpHdrRange; |
62e76326 | 237 | |
528b2c61 | 238 | if (!r->parseInit(range_spec)) { |
00d77d6b | 239 | delete r; |
62e76326 | 240 | r = NULL; |
b5107edb | 241 | } |
62e76326 | 242 | |
b5107edb | 243 | return r; |
244 | } | |
245 | ||
246 | /* returns true if ranges are valid; inits HttpHdrRange */ | |
528b2c61 | 247 | bool |
30abd221 | 248 | HttpHdrRange::parseInit(const String * range_spec) |
b5107edb | 249 | { |
250 | const char *item; | |
251 | const char *pos = NULL; | |
252 | int ilen; | |
99edd1c3 | 253 | int count = 0; |
528b2c61 | 254 | assert(this && range_spec); |
255 | ++ParsedCount; | |
30abd221 | 256 | debugs(64, 8, "parsing range field: '" << range_spec->buf() << "'"); |
d0700d54 | 257 | /* check range type */ |
62e76326 | 258 | |
30abd221 | 259 | if (range_spec->caseCmp("bytes=", 6)) |
62e76326 | 260 | return 0; |
261 | ||
99edd1c3 | 262 | /* skip "bytes="; hack! */ |
30abd221 | 263 | pos = range_spec->buf() + 5; |
62e76326 | 264 | |
b5107edb | 265 | /* iterate through comma separated list */ |
528b2c61 | 266 | while (strListGetItem(range_spec, ',', &item, &ilen, &pos)) { |
62e76326 | 267 | HttpHdrRangeSpec *spec = HttpHdrRangeSpec::Create(item, ilen); |
268 | /* | |
269 | * HTTP/1.1 draft says we must ignore the whole header field if one spec | |
270 | * is invalid. However, RFC 2068 just says that we must ignore that spec. | |
271 | */ | |
272 | ||
273 | if (spec) | |
274 | specs.push_back(spec); | |
275 | ||
276 | ++count; | |
b5107edb | 277 | } |
62e76326 | 278 | |
30abd221 | 279 | debugs(64, 8, "parsed range range count: " << count << ", kept " << |
280 | specs.size()); | |
528b2c61 | 281 | return specs.count != 0; |
282 | } | |
283 | ||
284 | HttpHdrRange::~HttpHdrRange() | |
285 | { | |
286 | while (specs.size()) | |
00d77d6b | 287 | delete specs.pop_back(); |
528b2c61 | 288 | } |
289 | ||
290 | HttpHdrRange::HttpHdrRange(HttpHdrRange const &old) : specs() | |
291 | { | |
292 | specs.reserve(old.specs.size()); | |
62e76326 | 293 | |
528b2c61 | 294 | for (const_iterator i = old.begin(); i != old.end(); ++i) |
62e76326 | 295 | specs.push_back(new HttpHdrRangeSpec ( **i)); |
296 | ||
528b2c61 | 297 | assert(old.specs.size() == specs.size()); |
298 | } | |
299 | ||
300 | HttpHdrRange::iterator | |
301 | HttpHdrRange::begin() | |
302 | { | |
303 | return specs.begin(); | |
304 | } | |
305 | ||
306 | HttpHdrRange::iterator | |
307 | HttpHdrRange::end() | |
308 | { | |
309 | return specs.end(); | |
310 | } | |
311 | ||
312 | HttpHdrRange::const_iterator | |
313 | HttpHdrRange::begin() const | |
314 | { | |
315 | return specs.begin(); | |
316 | } | |
317 | ||
318 | HttpHdrRange::const_iterator | |
319 | HttpHdrRange::end() const | |
320 | { | |
321 | return specs.end(); | |
b5107edb | 322 | } |
323 | ||
324 | void | |
528b2c61 | 325 | HttpHdrRange::packInto(Packer * packer) const |
b5107edb | 326 | { |
528b2c61 | 327 | const_iterator pos = begin(); |
328 | assert(this); | |
62e76326 | 329 | |
528b2c61 | 330 | while (pos != end()) { |
62e76326 | 331 | if (pos != begin()) |
332 | packerAppend(packer, ",", 1); | |
333 | ||
334 | (*pos)->packInto(packer); | |
335 | ||
336 | ++pos; | |
528b2c61 | 337 | } |
b5107edb | 338 | } |
339 | ||
528b2c61 | 340 | void |
341 | HttpHdrRange::merge (Vector<HttpHdrRangeSpec *> &basis) | |
02922e76 | 342 | { |
528b2c61 | 343 | /* reset old array */ |
344 | specs.clean(); | |
345 | /* merge specs: | |
346 | * take one spec from "goods" and merge it with specs from | |
347 | * "specs" (if any) until there is no overlap */ | |
348 | iterator i = basis.begin(); | |
62e76326 | 349 | |
528b2c61 | 350 | while (i != basis.end()) { |
62e76326 | 351 | if (specs.size() && (*i)->mergeWith(specs.back())) { |
352 | /* merged with current so get rid of the prev one */ | |
00d77d6b | 353 | delete specs.pop_back(); |
62e76326 | 354 | continue; /* re-iterate */ |
355 | } | |
356 | ||
357 | specs.push_back (*i); | |
358 | ++i; /* progress */ | |
528b2c61 | 359 | } |
62e76326 | 360 | |
e4049756 | 361 | debugs(64, 3, "HttpHdrRange::merge: had " << basis.size() << |
362 | " specs, merged " << basis.size() - specs.size() << " specs"); | |
02922e76 | 363 | } |
364 | ||
528b2c61 | 365 | |
02922e76 | 366 | void |
528b2c61 | 367 | HttpHdrRange::getCanonizedSpecs (Vector<HttpHdrRangeSpec *> ©) |
368 | { | |
369 | /* canonize each entry and destroy bad ones if any */ | |
62e76326 | 370 | |
528b2c61 | 371 | for (iterator pos (begin()); pos != end(); ++pos) { |
62e76326 | 372 | if ((*pos)->canonize(clen)) |
373 | copy.push_back (*pos); | |
374 | else | |
00d77d6b | 375 | delete (*pos); |
02922e76 | 376 | } |
62e76326 | 377 | |
e4049756 | 378 | debugs(64, 3, "HttpHdrRange::getCanonizedSpecs: found " << |
379 | specs.size() - copy.size() << " bad specs"); | |
02922e76 | 380 | } |
381 | ||
528b2c61 | 382 | #include "HttpHdrContRange.h" |
383 | ||
b5107edb | 384 | /* |
385 | * canonizes all range specs within a set preserving the order | |
386 | * returns true if the set is valid after canonization; | |
387 | * the set is valid if | |
388 | * - all range specs are valid and | |
389 | * - there is at least one range spec | |
390 | */ | |
391 | int | |
528b2c61 | 392 | HttpHdrRange::canonize(HttpReply *rep) |
b5107edb | 393 | { |
528b2c61 | 394 | assert(this && rep); |
62e76326 | 395 | |
528b2c61 | 396 | if (rep->content_range) |
62e76326 | 397 | clen = rep->content_range->elength; |
528b2c61 | 398 | else |
62e76326 | 399 | clen = rep->content_length; |
400 | ||
528b2c61 | 401 | return canonize (clen); |
b5107edb | 402 | } |
403 | ||
528b2c61 | 404 | int |
47f6e231 | 405 | HttpHdrRange::canonize (int64_t newClen) |
b5107edb | 406 | { |
528b2c61 | 407 | clen = newClen; |
e4049756 | 408 | debugs(64, 3, "HttpHdrRange::canonize: started with " << specs.count << |
409 | " specs, clen: " << clen); | |
528b2c61 | 410 | Vector<HttpHdrRangeSpec*> goods; |
411 | getCanonizedSpecs(goods); | |
412 | merge (goods); | |
e4049756 | 413 | debugs(64, 3, "HttpHdrRange::canonize: finished with " << specs.count << |
414 | " specs"); | |
528b2c61 | 415 | return specs.count > 0; |
b5107edb | 416 | } |
d192d11f | 417 | |
418 | /* hack: returns true if range specs are too "complex" for Squid to handle */ | |
67bff3c8 | 419 | /* requires that specs are "canonized" first! */ |
528b2c61 | 420 | bool |
421 | HttpHdrRange::isComplex() const | |
d192d11f | 422 | { |
47f6e231 | 423 | int64_t offset = 0; |
528b2c61 | 424 | assert(this); |
d192d11f | 425 | /* check that all rangers are in "strong" order */ |
528b2c61 | 426 | const_iterator pos (begin()); |
62e76326 | 427 | |
528b2c61 | 428 | while (pos != end()) { |
62e76326 | 429 | /* Ensure typecasts is safe */ |
430 | assert ((*pos)->offset >= 0); | |
431 | ||
47f6e231 | 432 | if ((*pos)->offset < offset) |
62e76326 | 433 | return 1; |
434 | ||
435 | offset = (*pos)->offset + (*pos)->length; | |
436 | ||
437 | ++pos; | |
d192d11f | 438 | } |
62e76326 | 439 | |
d192d11f | 440 | return 0; |
441 | } | |
442 | ||
9bc73deb | 443 | /* |
444 | * hack: returns true if range specs may be too "complex" when "canonized". | |
528b2c61 | 445 | * see also: HttpHdrRange::isComplex. |
9bc73deb | 446 | */ |
528b2c61 | 447 | bool |
448 | HttpHdrRange::willBeComplex() const | |
67bff3c8 | 449 | { |
528b2c61 | 450 | assert(this); |
67bff3c8 | 451 | /* check that all rangers are in "strong" order, */ |
452 | /* as far as we can tell without the content length */ | |
47f6e231 | 453 | int64_t offset = 0; |
62e76326 | 454 | |
528b2c61 | 455 | for (const_iterator pos (begin()); pos != end(); ++pos) { |
62e76326 | 456 | if (!known_spec((*pos)->offset)) /* ignore unknowns */ |
457 | continue; | |
458 | ||
459 | /* Ensure typecasts is safe */ | |
460 | assert ((*pos)->offset >= 0); | |
461 | ||
47f6e231 | 462 | if ((*pos)->offset < offset) |
62e76326 | 463 | return true; |
464 | ||
465 | offset = (*pos)->offset; | |
466 | ||
467 | if (known_spec((*pos)->length)) /* avoid unknowns */ | |
468 | offset += (*pos)->length; | |
67bff3c8 | 469 | } |
62e76326 | 470 | |
528b2c61 | 471 | return false; |
67bff3c8 | 472 | } |
473 | ||
9bc73deb | 474 | /* |
528b2c61 | 475 | * Returns lowest known offset in range spec(s), |
476 | * or HttpHdrRangeSpec::UnknownPosition | |
9bc73deb | 477 | * this is used for size limiting |
478 | */ | |
47f6e231 | 479 | int64_t |
528b2c61 | 480 | HttpHdrRange::firstOffset() const |
481 | { | |
47f6e231 | 482 | int64_t offset = HttpHdrRangeSpec::UnknownPosition; |
528b2c61 | 483 | assert(this); |
484 | const_iterator pos = begin(); | |
62e76326 | 485 | |
528b2c61 | 486 | while (pos != end()) { |
62e76326 | 487 | if ((*pos)->offset < offset || !known_spec(offset)) |
488 | offset = (*pos)->offset; | |
489 | ||
490 | ++pos; | |
c68e9c6b | 491 | } |
62e76326 | 492 | |
cfbf5373 | 493 | return offset; |
c68e9c6b | 494 | } |
495 | ||
9bc73deb | 496 | /* |
497 | * Returns lowest offset in range spec(s), 0 if unknown. | |
498 | * This is used for finding out where we need to start if all | |
cfbf5373 | 499 | * ranges are combined into one, for example FTP REST. |
500 | * Use 0 for size if unknown | |
501 | */ | |
47f6e231 | 502 | int64_t |
503 | HttpHdrRange::lowestOffset(int64_t size) const | |
528b2c61 | 504 | { |
47f6e231 | 505 | int64_t offset = HttpHdrRangeSpec::UnknownPosition; |
528b2c61 | 506 | const_iterator pos = begin(); |
507 | assert(this); | |
62e76326 | 508 | |
528b2c61 | 509 | while (pos != end()) { |
47f6e231 | 510 | int64_t current = (*pos)->offset; |
62e76326 | 511 | |
512 | if (!known_spec(current)) { | |
513 | if ((*pos)->length > size || !known_spec((*pos)->length)) | |
514 | return 0; /* Unknown. Assume start of file */ | |
515 | ||
516 | current = size - (*pos)->length; | |
517 | } | |
518 | ||
519 | if (current < offset || !known_spec(offset)) | |
520 | offset = current; | |
521 | ||
522 | ++pos; | |
cfbf5373 | 523 | } |
62e76326 | 524 | |
cfbf5373 | 525 | return known_spec(offset) ? offset : 0; |
526 | } | |
527 | ||
62e76326 | 528 | /* |
7b1e21ff | 529 | * Return true if the first range offset is larger than the configured |
530 | * limit. | |
7f1b1350 | 531 | * Note that exceeding the limit (returning true) results in only |
532 | * grabbing the needed range elements from the origin. | |
7b1e21ff | 533 | */ |
528b2c61 | 534 | bool |
535 | HttpHdrRange::offsetLimitExceeded() const | |
7b1e21ff | 536 | { |
528b2c61 | 537 | if (NULL == this) |
62e76326 | 538 | /* not a range request */ |
539 | return false; | |
540 | ||
47f6e231 | 541 | if (-1 == Config.rangeOffsetLimit) |
62e76326 | 542 | /* disabled */ |
543 | return false; | |
544 | ||
7f1b1350 | 545 | if (firstOffset() == -1) |
546 | /* tail request */ | |
8c362252 | 547 | return true; |
7f1b1350 | 548 | |
47f6e231 | 549 | if (Config.rangeOffsetLimit >= firstOffset()) |
62e76326 | 550 | /* below the limit */ |
551 | return false; | |
552 | ||
528b2c61 | 553 | return true; |
554 | } | |
555 | ||
fedd1531 | 556 | bool |
557 | HttpHdrRange::contains(HttpHdrRangeSpec& r) const | |
558 | { | |
559 | assert(r.length >= 0); | |
560 | HttpHdrRangeSpec::HttpRange rrange(r.offset, r.offset + r.length); | |
561 | ||
562 | for (const_iterator i = begin(); i != end(); ++i) { | |
563 | HttpHdrRangeSpec::HttpRange irange((*i)->offset, (*i)->offset + (*i)->length); | |
564 | HttpHdrRangeSpec::HttpRange intersection = rrange.intersection(irange); | |
565 | ||
566 | if (intersection.start == irange.start && intersection.size() == irange.size()) | |
567 | return true; | |
568 | } | |
569 | ||
570 | return false; | |
571 | } | |
572 | ||
528b2c61 | 573 | const HttpHdrRangeSpec * |
574 | HttpHdrRangeIter::currentSpec() const | |
575 | { | |
576 | if (pos.incrementable()) | |
62e76326 | 577 | return *pos; |
578 | ||
528b2c61 | 579 | return NULL; |
580 | } | |
581 | ||
582 | void | |
583 | HttpHdrRangeIter::updateSpec() | |
584 | { | |
585 | assert (debt_size == 0); | |
b6012c1a | 586 | assert (valid); |
62e76326 | 587 | |
528b2c61 | 588 | if (pos.incrementable()) { |
62e76326 | 589 | debt(currentSpec()->length); |
528b2c61 | 590 | } |
591 | } | |
592 | ||
47f6e231 | 593 | int64_t |
528b2c61 | 594 | HttpHdrRangeIter::debt() const |
595 | { | |
4a7a3d56 | 596 | debugs(64, 3, "HttpHdrRangeIter::debt: debt is " << debt_size); |
528b2c61 | 597 | return debt_size; |
598 | } | |
599 | ||
47f6e231 | 600 | void HttpHdrRangeIter::debt(int64_t newDebt) |
528b2c61 | 601 | { |
4a7a3d56 | 602 | debugs(64, 3, "HttpHdrRangeIter::debt: was " << debt_size << " now " << newDebt); |
528b2c61 | 603 | debt_size = newDebt; |
7b1e21ff | 604 | } |