]>
Commit | Line | Data |
---|---|---|
b5107edb | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 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. | |
b5107edb | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 64 HTTP Range Header */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
528b2c61 | 12 | #include "client_side_request.h" |
d3dddfb5 | 13 | #include "http/Stream.h" |
602d9612 | 14 | #include "HttpHeaderRange.h" |
c6983ec7 | 15 | #include "HttpHeaderTools.h" |
602d9612 A |
16 | #include "HttpReply.h" |
17 | #include "Store.h" | |
28204b3b | 18 | #include "StrList.h" |
b5107edb | 19 | |
b644367b | 20 | /* |
21 | * Currently only byte ranges are supported | |
22 | * | |
23 | * Essentially, there are three types of byte ranges: | |
24 | * | |
25 | * 1) first-byte-pos "-" last-byte-pos // range | |
26 | * 2) first-byte-pos "-" // trailer | |
27 | * 3) "-" suffix-length // suffix (last length bytes) | |
28 | * | |
29 | * | |
30 | * When Range field is parsed, we have no clue about the content | |
31 | * length of the document. Thus, we simply code an "absent" part | |
528b2c61 | 32 | * using HttpHdrRangeSpec::UnknownPosition constant. |
b644367b | 33 | * |
34 | * Note: when response length becomes known, we convert any range | |
35 | * spec into type one above. (Canonization process). | |
36 | */ | |
b5107edb | 37 | |
b5107edb | 38 | /* local routines */ |
528b2c61 | 39 | #define known_spec(s) ((s) > HttpHdrRangeSpec::UnknownPosition) |
b5107edb | 40 | |
41 | /* globals */ | |
528b2c61 | 42 | size_t HttpHdrRange::ParsedCount = 0; |
47f6e231 | 43 | int64_t const HttpHdrRangeSpec::UnknownPosition = -1; |
b5107edb | 44 | |
45 | /* | |
46 | * Range-Spec | |
47 | */ | |
48 | ||
26ac0430 | 49 | HttpHdrRangeSpec::HttpHdrRangeSpec() : offset(UnknownPosition), length(UnknownPosition) {} |
528b2c61 | 50 | |
b5107edb | 51 | /* parses range-spec and returns new object on success */ |
528b2c61 | 52 | HttpHdrRangeSpec * |
53 | HttpHdrRangeSpec::Create(const char *field, int flen) | |
54 | { | |
55 | HttpHdrRangeSpec spec; | |
62e76326 | 56 | |
528b2c61 | 57 | if (!spec.parseInit(field, flen)) |
aee3523a | 58 | return nullptr; |
62e76326 | 59 | |
528b2c61 | 60 | return new HttpHdrRangeSpec(spec); |
61 | } | |
62 | ||
63 | bool | |
64 | HttpHdrRangeSpec::parseInit(const char *field, int flen) | |
b5107edb | 65 | { |
b5107edb | 66 | const char *p; |
62e76326 | 67 | |
b5107edb | 68 | if (flen < 2) |
62e76326 | 69 | return false; |
70 | ||
b5107edb | 71 | /* is it a suffix-byte-range-spec ? */ |
72 | if (*field == '-') { | |
3a645003 | 73 | if (!httpHeaderParseOffset(field + 1, &length) || !known_spec(length)) |
62e76326 | 74 | return false; |
b5107edb | 75 | } else |
62e76326 | 76 | /* must have a '-' somewhere in _this_ field */ |
2ae98e09 | 77 | if (!((p = strchr(field, '-')) && (p - field < flen))) { |
8beb3224 | 78 | debugs(64, 2, "invalid (missing '-') range-spec near: '" << field << "'"); |
62e76326 | 79 | return false; |
80 | } else { | |
3a645003 | 81 | if (!httpHeaderParseOffset(field, &offset) || !known_spec(offset)) |
62e76326 | 82 | return false; |
83 | ||
95dc7ff4 | 84 | ++p; |
62e76326 | 85 | |
86 | /* do we have last-pos ? */ | |
87 | if (p - field < flen) { | |
47f6e231 | 88 | int64_t last_pos; |
62e76326 | 89 | |
3a645003 | 90 | if (!httpHeaderParseOffset(p, &last_pos) || !known_spec(last_pos)) |
62e76326 | 91 | return false; |
92 | ||
8beb3224 AR |
93 | // RFC 2616 s14.35.1 MUST: last-byte-pos >= first-byte-pos |
94 | if (last_pos < offset) { | |
95 | debugs(64, 2, "invalid (last-byte-pos < first-byte-pos) range-spec near: " << field); | |
96 | return false; | |
97 | } | |
98 | ||
62e76326 | 99 | HttpHdrRangeSpec::HttpRange aSpec (offset, last_pos + 1); |
100 | ||
101 | length = aSpec.size(); | |
102 | } | |
103 | } | |
104 | ||
528b2c61 | 105 | return true; |
b5107edb | 106 | } |
107 | ||
528b2c61 | 108 | void |
4391cd15 | 109 | HttpHdrRangeSpec::packInto(Packable * p) const |
02922e76 | 110 | { |
f53969cc | 111 | if (!known_spec(offset)) /* suffix */ |
4391cd15 | 112 | p->appendf("-%" PRId64, length); |
f53969cc | 113 | else if (!known_spec(length)) /* trailer */ |
4391cd15 | 114 | p->appendf("%" PRId64 "-", offset); |
f53969cc | 115 | else /* range */ |
4391cd15 | 116 | p->appendf("%" PRId64 "-%" PRId64, offset, offset + length - 1); |
02922e76 | 117 | } |
118 | ||
528b2c61 | 119 | void |
120 | HttpHdrRangeSpec::outputInfo( char const *note) const | |
d76fcfa7 | 121 | { |
bf8fe701 | 122 | debugs(64, 5, "HttpHdrRangeSpec::canonize: " << note << ": [" << |
47f6e231 | 123 | offset << ", " << offset + length << |
124 | ") len: " << length); | |
d76fcfa7 | 125 | } |
126 | ||
62e76326 | 127 | /* fills "absent" positions in range specification based on response body size |
b644367b | 128 | * returns true if the range is still valid |
129 | * range is valid if its intersection with [0,length-1] is not empty | |
130 | */ | |
528b2c61 | 131 | int |
47f6e231 | 132 | HttpHdrRangeSpec::canonize(int64_t clen) |
528b2c61 | 133 | { |
134 | outputInfo ("have"); | |
135 | HttpRange object(0, clen); | |
62e76326 | 136 | |
f53969cc | 137 | if (!known_spec(offset)) { /* suffix */ |
62e76326 | 138 | assert(known_spec(length)); |
139 | offset = object.intersection(HttpRange (clen - length, clen)).start; | |
f53969cc | 140 | } else if (!known_spec(length)) { /* trailer */ |
62e76326 | 141 | assert(known_spec(offset)); |
142 | HttpRange newRange = object.intersection(HttpRange (offset, clen)); | |
143 | length = newRange.size(); | |
528b2c61 | 144 | } |
b5107edb | 145 | /* we have a "range" now, adjust length if needed */ |
528b2c61 | 146 | assert(known_spec(length)); |
62e76326 | 147 | |
528b2c61 | 148 | assert(known_spec(offset)); |
62e76326 | 149 | |
528b2c61 | 150 | HttpRange newRange = object.intersection (HttpRange (offset, offset + length)); |
62e76326 | 151 | |
528b2c61 | 152 | length = newRange.size(); |
62e76326 | 153 | |
528b2c61 | 154 | outputInfo ("done"); |
62e76326 | 155 | |
528b2c61 | 156 | return length > 0; |
b5107edb | 157 | } |
158 | ||
2f8abb64 | 159 | /* merges recipient with donor if possible; returns true on success |
889b534a | 160 | * both specs must be canonized prior to merger, of course */ |
62e76326 | 161 | bool |
528b2c61 | 162 | HttpHdrRangeSpec::mergeWith(const HttpHdrRangeSpec * donor) |
889b534a | 163 | { |
528b2c61 | 164 | bool merged (false); |
67bff3c8 | 165 | #if MERGING_BREAKS_NOTHING |
166 | /* Note: this code works, but some clients may not like its effects */ | |
f53969cc SM |
167 | int64_t rhs = offset + length; /* no -1 ! */ |
168 | const int64_t donor_rhs = donor->offset + donor->length; /* no -1 ! */ | |
528b2c61 | 169 | assert(known_spec(offset)); |
889b534a | 170 | assert(known_spec(donor->offset)); |
528b2c61 | 171 | assert(length > 0); |
889b534a | 172 | assert(donor->length > 0); |
173 | /* do we have a left hand side overlap? */ | |
62e76326 | 174 | |
528b2c61 | 175 | if (donor->offset < offset && offset <= donor_rhs) { |
f53969cc | 176 | offset = donor->offset; /* decrease left offset */ |
62e76326 | 177 | merged = 1; |
889b534a | 178 | } |
62e76326 | 179 | |
889b534a | 180 | /* do we have a right hand side overlap? */ |
181 | if (donor->offset <= rhs && rhs < donor_rhs) { | |
f53969cc | 182 | rhs = donor_rhs; /* increase right offset */ |
62e76326 | 183 | merged = 1; |
889b534a | 184 | } |
62e76326 | 185 | |
889b534a | 186 | /* adjust length if offsets have been changed */ |
187 | if (merged) { | |
62e76326 | 188 | assert(rhs > offset); |
189 | length = rhs - offset; | |
889b534a | 190 | } else { |
2f8abb64 | 191 | /* does recipient contain donor? */ |
62e76326 | 192 | merged = |
193 | offset <= donor->offset && donor->offset < rhs; | |
889b534a | 194 | } |
62e76326 | 195 | |
8b082ed9 FC |
196 | #else |
197 | (void)donor; | |
67bff3c8 | 198 | #endif |
889b534a | 199 | return merged; |
200 | } | |
201 | ||
b5107edb | 202 | /* |
203 | * Range | |
204 | */ | |
205 | ||
593d3cdb | 206 | HttpHdrRange::HttpHdrRange() : clen(HttpHdrRangeSpec::UnknownPosition) |
62e76326 | 207 | {} |
b5107edb | 208 | |
209 | HttpHdrRange * | |
30abd221 | 210 | HttpHdrRange::ParseCreate(const String * range_spec) |
b5107edb | 211 | { |
528b2c61 | 212 | HttpHdrRange *r = new HttpHdrRange; |
62e76326 | 213 | |
528b2c61 | 214 | if (!r->parseInit(range_spec)) { |
00d77d6b | 215 | delete r; |
aee3523a | 216 | r = nullptr; |
b5107edb | 217 | } |
62e76326 | 218 | |
b5107edb | 219 | return r; |
220 | } | |
221 | ||
222 | /* returns true if ranges are valid; inits HttpHdrRange */ | |
528b2c61 | 223 | bool |
30abd221 | 224 | HttpHdrRange::parseInit(const String * range_spec) |
b5107edb | 225 | { |
226 | const char *item; | |
aee3523a | 227 | const char *pos = nullptr; |
b5107edb | 228 | int ilen; |
328a07ab | 229 | assert(range_spec); |
528b2c61 | 230 | ++ParsedCount; |
7ec92ef0 | 231 | debugs(64, 8, "parsing range field: '" << *range_spec << "'"); |
d0700d54 | 232 | /* check range type */ |
62e76326 | 233 | |
30abd221 | 234 | if (range_spec->caseCmp("bytes=", 6)) |
62e76326 | 235 | return 0; |
236 | ||
99edd1c3 | 237 | /* skip "bytes="; hack! */ |
550cc09e | 238 | pos = range_spec->termedBuf() + 6; |
62e76326 | 239 | |
b5107edb | 240 | /* iterate through comma separated list */ |
528b2c61 | 241 | while (strListGetItem(range_spec, ',', &item, &ilen, &pos)) { |
62e76326 | 242 | HttpHdrRangeSpec *spec = HttpHdrRangeSpec::Create(item, ilen); |
243 | /* | |
8beb3224 AR |
244 | * RFC 2616 section 14.35.1: MUST ignore Range with |
245 | * at least one syntactically invalid byte-range-specs. | |
62e76326 | 246 | */ |
8beb3224 | 247 | if (!spec) { |
38c22baf FC |
248 | while (!specs.empty()) { |
249 | delete specs.back(); | |
250 | specs.pop_back(); | |
251 | } | |
7ec92ef0 | 252 | debugs(64, 2, "ignoring invalid range field: '" << *range_spec << "'"); |
8beb3224 AR |
253 | break; |
254 | } | |
62e76326 | 255 | |
8beb3224 | 256 | specs.push_back(spec); |
b5107edb | 257 | } |
62e76326 | 258 | |
8beb3224 AR |
259 | debugs(64, 8, "got range specs: " << specs.size()); |
260 | return !specs.empty(); | |
528b2c61 | 261 | } |
262 | ||
263 | HttpHdrRange::~HttpHdrRange() | |
264 | { | |
385acf91 | 265 | while (!specs.empty()) { |
38c22baf FC |
266 | delete specs.back(); |
267 | specs.pop_back(); | |
268 | } | |
528b2c61 | 269 | } |
270 | ||
593d3cdb | 271 | HttpHdrRange::HttpHdrRange(HttpHdrRange const &old) : |
f53969cc SM |
272 | specs(), |
273 | clen(HttpHdrRangeSpec::UnknownPosition) | |
528b2c61 | 274 | { |
275 | specs.reserve(old.specs.size()); | |
62e76326 | 276 | |
528b2c61 | 277 | for (const_iterator i = old.begin(); i != old.end(); ++i) |
62e76326 | 278 | specs.push_back(new HttpHdrRangeSpec ( **i)); |
279 | ||
528b2c61 | 280 | assert(old.specs.size() == specs.size()); |
281 | } | |
282 | ||
283 | HttpHdrRange::iterator | |
284 | HttpHdrRange::begin() | |
285 | { | |
286 | return specs.begin(); | |
287 | } | |
288 | ||
289 | HttpHdrRange::iterator | |
290 | HttpHdrRange::end() | |
291 | { | |
292 | return specs.end(); | |
293 | } | |
294 | ||
295 | HttpHdrRange::const_iterator | |
296 | HttpHdrRange::begin() const | |
297 | { | |
298 | return specs.begin(); | |
299 | } | |
300 | ||
301 | HttpHdrRange::const_iterator | |
302 | HttpHdrRange::end() const | |
303 | { | |
304 | return specs.end(); | |
b5107edb | 305 | } |
306 | ||
307 | void | |
17802cf1 | 308 | HttpHdrRange::packInto(Packable * packer) const |
b5107edb | 309 | { |
528b2c61 | 310 | const_iterator pos = begin(); |
62e76326 | 311 | |
528b2c61 | 312 | while (pos != end()) { |
62e76326 | 313 | if (pos != begin()) |
785b508d | 314 | packer->append(",", 1); |
62e76326 | 315 | |
316 | (*pos)->packInto(packer); | |
317 | ||
318 | ++pos; | |
528b2c61 | 319 | } |
b5107edb | 320 | } |
321 | ||
528b2c61 | 322 | void |
24a8eaae | 323 | HttpHdrRange::merge (std::vector<HttpHdrRangeSpec *> &basis) |
02922e76 | 324 | { |
528b2c61 | 325 | /* reset old array */ |
c33a88ca | 326 | specs.clear(); |
528b2c61 | 327 | /* merge specs: |
26ac0430 | 328 | * take one spec from "goods" and merge it with specs from |
528b2c61 | 329 | * "specs" (if any) until there is no overlap */ |
330 | iterator i = basis.begin(); | |
62e76326 | 331 | |
528b2c61 | 332 | while (i != basis.end()) { |
62e76326 | 333 | if (specs.size() && (*i)->mergeWith(specs.back())) { |
334 | /* merged with current so get rid of the prev one */ | |
38c22baf FC |
335 | delete specs.back(); |
336 | specs.pop_back(); | |
f53969cc | 337 | continue; /* re-iterate */ |
62e76326 | 338 | } |
339 | ||
340 | specs.push_back (*i); | |
f53969cc | 341 | ++i; /* progress */ |
528b2c61 | 342 | } |
62e76326 | 343 | |
e4049756 | 344 | debugs(64, 3, "HttpHdrRange::merge: had " << basis.size() << |
345 | " specs, merged " << basis.size() - specs.size() << " specs"); | |
02922e76 | 346 | } |
347 | ||
348 | void | |
19f2a2ee | 349 | HttpHdrRange::getCanonizedSpecs(std::vector<HttpHdrRangeSpec *> ©) |
528b2c61 | 350 | { |
351 | /* canonize each entry and destroy bad ones if any */ | |
62e76326 | 352 | |
528b2c61 | 353 | for (iterator pos (begin()); pos != end(); ++pos) { |
62e76326 | 354 | if ((*pos)->canonize(clen)) |
355 | copy.push_back (*pos); | |
356 | else | |
00d77d6b | 357 | delete (*pos); |
02922e76 | 358 | } |
62e76326 | 359 | |
19f2a2ee | 360 | debugs(64, 3, "found " << specs.size() - copy.size() << " bad specs"); |
02922e76 | 361 | } |
362 | ||
528b2c61 | 363 | #include "HttpHdrContRange.h" |
364 | ||
b5107edb | 365 | /* |
366 | * canonizes all range specs within a set preserving the order | |
26ac0430 AJ |
367 | * returns true if the set is valid after canonization; |
368 | * the set is valid if | |
369 | * - all range specs are valid and | |
b5107edb | 370 | * - there is at least one range spec |
371 | */ | |
372 | int | |
528b2c61 | 373 | HttpHdrRange::canonize(HttpReply *rep) |
b5107edb | 374 | { |
328a07ab | 375 | assert(rep); |
62e76326 | 376 | |
8341f96d EB |
377 | if (rep->contentRange()) |
378 | clen = rep->contentRange()->elength; | |
528b2c61 | 379 | else |
62e76326 | 380 | clen = rep->content_length; |
381 | ||
528b2c61 | 382 | return canonize (clen); |
b5107edb | 383 | } |
384 | ||
528b2c61 | 385 | int |
47f6e231 | 386 | HttpHdrRange::canonize (int64_t newClen) |
b5107edb | 387 | { |
528b2c61 | 388 | clen = newClen; |
4c9eadc2 | 389 | debugs(64, 3, "HttpHdrRange::canonize: started with " << specs.size() << |
e4049756 | 390 | " specs, clen: " << clen); |
24a8eaae | 391 | std::vector<HttpHdrRangeSpec*> goods; |
528b2c61 | 392 | getCanonizedSpecs(goods); |
393 | merge (goods); | |
4c9eadc2 | 394 | debugs(64, 3, "HttpHdrRange::canonize: finished with " << specs.size() << |
e4049756 | 395 | " specs"); |
9837567d | 396 | return specs.size() > 0; // TODO: should return bool |
b5107edb | 397 | } |
d192d11f | 398 | |
399 | /* hack: returns true if range specs are too "complex" for Squid to handle */ | |
67bff3c8 | 400 | /* requires that specs are "canonized" first! */ |
528b2c61 | 401 | bool |
402 | HttpHdrRange::isComplex() const | |
d192d11f | 403 | { |
47f6e231 | 404 | int64_t offset = 0; |
d192d11f | 405 | /* check that all rangers are in "strong" order */ |
528b2c61 | 406 | const_iterator pos (begin()); |
62e76326 | 407 | |
528b2c61 | 408 | while (pos != end()) { |
62e76326 | 409 | /* Ensure typecasts is safe */ |
410 | assert ((*pos)->offset >= 0); | |
411 | ||
47f6e231 | 412 | if ((*pos)->offset < offset) |
62e76326 | 413 | return 1; |
414 | ||
415 | offset = (*pos)->offset + (*pos)->length; | |
416 | ||
417 | ++pos; | |
d192d11f | 418 | } |
62e76326 | 419 | |
d192d11f | 420 | return 0; |
421 | } | |
422 | ||
9bc73deb | 423 | /* |
424 | * hack: returns true if range specs may be too "complex" when "canonized". | |
528b2c61 | 425 | * see also: HttpHdrRange::isComplex. |
9bc73deb | 426 | */ |
528b2c61 | 427 | bool |
428 | HttpHdrRange::willBeComplex() const | |
67bff3c8 | 429 | { |
67bff3c8 | 430 | /* check that all rangers are in "strong" order, */ |
431 | /* as far as we can tell without the content length */ | |
47f6e231 | 432 | int64_t offset = 0; |
62e76326 | 433 | |
528b2c61 | 434 | for (const_iterator pos (begin()); pos != end(); ++pos) { |
f53969cc | 435 | if (!known_spec((*pos)->offset)) /* ignore unknowns */ |
62e76326 | 436 | continue; |
437 | ||
438 | /* Ensure typecasts is safe */ | |
439 | assert ((*pos)->offset >= 0); | |
440 | ||
47f6e231 | 441 | if ((*pos)->offset < offset) |
62e76326 | 442 | return true; |
443 | ||
444 | offset = (*pos)->offset; | |
445 | ||
f53969cc | 446 | if (known_spec((*pos)->length)) /* avoid unknowns */ |
62e76326 | 447 | offset += (*pos)->length; |
67bff3c8 | 448 | } |
62e76326 | 449 | |
528b2c61 | 450 | return false; |
67bff3c8 | 451 | } |
452 | ||
9bc73deb | 453 | /* |
528b2c61 | 454 | * Returns lowest known offset in range spec(s), |
455 | * or HttpHdrRangeSpec::UnknownPosition | |
9bc73deb | 456 | * this is used for size limiting |
457 | */ | |
47f6e231 | 458 | int64_t |
528b2c61 | 459 | HttpHdrRange::firstOffset() const |
460 | { | |
47f6e231 | 461 | int64_t offset = HttpHdrRangeSpec::UnknownPosition; |
528b2c61 | 462 | const_iterator pos = begin(); |
62e76326 | 463 | |
528b2c61 | 464 | while (pos != end()) { |
62e76326 | 465 | if ((*pos)->offset < offset || !known_spec(offset)) |
466 | offset = (*pos)->offset; | |
467 | ||
468 | ++pos; | |
c68e9c6b | 469 | } |
62e76326 | 470 | |
cfbf5373 | 471 | return offset; |
c68e9c6b | 472 | } |
473 | ||
9bc73deb | 474 | /* |
475 | * Returns lowest offset in range spec(s), 0 if unknown. | |
476 | * This is used for finding out where we need to start if all | |
cfbf5373 | 477 | * ranges are combined into one, for example FTP REST. |
478 | * Use 0 for size if unknown | |
479 | */ | |
47f6e231 | 480 | int64_t |
481 | HttpHdrRange::lowestOffset(int64_t size) const | |
528b2c61 | 482 | { |
47f6e231 | 483 | int64_t offset = HttpHdrRangeSpec::UnknownPosition; |
528b2c61 | 484 | const_iterator pos = begin(); |
62e76326 | 485 | |
528b2c61 | 486 | while (pos != end()) { |
47f6e231 | 487 | int64_t current = (*pos)->offset; |
62e76326 | 488 | |
489 | if (!known_spec(current)) { | |
490 | if ((*pos)->length > size || !known_spec((*pos)->length)) | |
f53969cc | 491 | return 0; /* Unknown. Assume start of file */ |
62e76326 | 492 | |
493 | current = size - (*pos)->length; | |
494 | } | |
495 | ||
496 | if (current < offset || !known_spec(offset)) | |
497 | offset = current; | |
498 | ||
499 | ++pos; | |
cfbf5373 | 500 | } |
62e76326 | 501 | |
cfbf5373 | 502 | return known_spec(offset) ? offset : 0; |
503 | } | |
504 | ||
62e76326 | 505 | /* |
11e3fa1c AJ |
506 | * \retval true Fetch only requested ranges. The first range is larger that configured limit. |
507 | * \retval false Full download. Not a range request, no limit, or the limit is not yet reached. | |
7b1e21ff | 508 | */ |
528b2c61 | 509 | bool |
11e3fa1c | 510 | HttpHdrRange::offsetLimitExceeded(const int64_t limit) const |
7b1e21ff | 511 | { |
11e3fa1c AJ |
512 | if (limit == 0) |
513 | /* 0 == disabled */ | |
26ac0430 | 514 | return true; |
f82874c4 | 515 | |
11e3fa1c AJ |
516 | if (-1 == limit) |
517 | /* 'none' == forced */ | |
62e76326 | 518 | return false; |
519 | ||
7f1b1350 | 520 | if (firstOffset() == -1) |
521 | /* tail request */ | |
8c362252 | 522 | return true; |
7f1b1350 | 523 | |
11e3fa1c | 524 | if (limit >= firstOffset()) |
62e76326 | 525 | /* below the limit */ |
526 | return false; | |
527 | ||
528b2c61 | 528 | return true; |
529 | } | |
530 | ||
531 | const HttpHdrRangeSpec * | |
532 | HttpHdrRangeIter::currentSpec() const | |
533 | { | |
24a8eaae | 534 | if (pos != end) |
62e76326 | 535 | return *pos; |
536 | ||
aee3523a | 537 | return nullptr; |
528b2c61 | 538 | } |
539 | ||
540 | void | |
541 | HttpHdrRangeIter::updateSpec() | |
542 | { | |
543 | assert (debt_size == 0); | |
b6012c1a | 544 | assert (valid); |
62e76326 | 545 | |
24a8eaae | 546 | if (pos != end) { |
62e76326 | 547 | debt(currentSpec()->length); |
528b2c61 | 548 | } |
549 | } | |
550 | ||
47f6e231 | 551 | int64_t |
528b2c61 | 552 | HttpHdrRangeIter::debt() const |
553 | { | |
4a7a3d56 | 554 | debugs(64, 3, "HttpHdrRangeIter::debt: debt is " << debt_size); |
528b2c61 | 555 | return debt_size; |
556 | } | |
557 | ||
47f6e231 | 558 | void HttpHdrRangeIter::debt(int64_t newDebt) |
528b2c61 | 559 | { |
4a7a3d56 | 560 | debugs(64, 3, "HttpHdrRangeIter::debt: was " << debt_size << " now " << newDebt); |
528b2c61 | 561 | debt_size = newDebt; |
7b1e21ff | 562 | } |
f53969cc | 563 |