{
assert(rep);
- if (rep->content_range)
- clen = rep->content_range->elength;
+ if (rep->contentRange())
+ clen = rep->contentRange()->elength;
else
clen = rep->content_length;
}
bool
-HttpHdrRange::contains(HttpHdrRangeSpec& r) const
+HttpHdrRange::contains(const HttpHdrRangeSpec& r) const
{
assert(r.length >= 0);
HttpHdrRangeSpec::HttpRange rrange(r.offset, r.offset + r.length);
int64_t firstOffset() const;
int64_t lowestOffset(int64_t) const;
bool offsetLimitExceeded(const int64_t limit) const;
- bool contains(HttpHdrRangeSpec& r) const;
+ bool contains(const HttpHdrRangeSpec& r) const;
std::vector<HttpHdrRangeSpec *> specs;
private:
#include "Store.h"
#include "StrList.h"
-HttpReply::HttpReply() : Http::Message(hoReply), date (0), last_modified (0),
- expires (0), surrogate_control (NULL), content_range (NULL), keep_alive (0),
- protoPrefix("HTTP/"), bodySizeMax(-2)
+HttpReply::HttpReply():
+ Http::Message(hoReply),
+ date(0),
+ last_modified(0),
+ expires(0),
+ surrogate_control(nullptr),
+ keep_alive(0),
+ protoPrefix("HTTP/"),
+ bodySizeMax(-2),
+ content_range(nullptr)
{
init();
}
date = header.getTime(Http::HdrType::DATE);
last_modified = header.getTime(Http::HdrType::LAST_MODIFIED);
surrogate_control = header.getSc();
- content_range = header.getContRange();
+ content_range = (sline.status() == Http::scPartialContent) ?
+ header.getContRange() : nullptr;
keep_alive = persistent() ? 1 : 0;
const char *str = header.getStr(Http::HdrType::CONTENT_TYPE);
expires = hdrExpirationTime();
}
+const HttpHdrContRange *
+HttpReply::contentRange() const
+{
+ assert(!content_range || sline.status() == Http::scPartialContent);
+ return content_range;
+}
+
/* sync this routine when you update HttpReply struct */
void
HttpReply::hdrCacheClean()
HttpHdrSc *surrogate_control;
- HttpHdrContRange *content_range;
+ /// \returns parsed Content-Range for a 206 response and nil for others
+ const HttpHdrContRange *contentRange() const;
short int keep_alive;
mutable int64_t bodySizeMax; /**< cached result of calcMaxBodySize */
+ HttpHdrContRange *content_range; ///< parsed Content-Range; nil for non-206 responses!
+
protected:
virtual void packFirstLineInto(Packable * p, bool) const { sline.packInto(p); }
maybePurgeOthers();
// adaptation may overwrite old offset computed using the virgin response
- const bool partial = theFinalReply->content_range &&
- theFinalReply->sline.status() == Http::scPartialContent;
- currentOffset = partial ? theFinalReply->content_range->spec.offset : 0;
+ const bool partial = theFinalReply->contentRange();
+ currentOffset = partial ? theFinalReply->contentRange()->spec.offset : 0;
}
/// whether to prevent caching of an otherwise cachable response
return start;
}
- } else if (reply && reply->content_range) {
+ } else if (reply && reply->contentRange()) {
/* request does not have ranges, but reply does */
/** \todo FIXME: should use range_iter_pos on reply, as soon as reply->content_range
* becomes HttpHdrRange rather than HttpHdrRangeSpec.
*/
- return http->out.offset + reply->content_range->spec.offset;
+ return http->out.offset + reply->contentRange()->spec.offset;
}
return http->out.offset;
// we got everything we wanted from the store
return STREAM_COMPLETE;
}
- } else if (reply && reply->content_range) {
+ } else if (reply && reply->contentRange()) {
/* reply has content-range, but Squid is not managing ranges */
const int64_t &bytesSent = http->out.offset;
- const int64_t &bytesExpected = reply->content_range->spec.length;
+ const int64_t &bytesExpected = reply->contentRange()->spec.length;
debugs(33, 7, "body bytes sent vs. expected: " <<
bytesSent << " ? " << bytesExpected << " (+" <<
- reply->content_range->spec.offset << ")");
+ reply->contentRange()->spec.offset << ")");
// did we get at least what we expected, based on range specs?
assert(request->range);
/* check if we still want to do ranges */
int64_t roffLimit = request->getRangeOffsetLimit();
+ auto contentRange = rep ? rep->contentRange() : nullptr;
if (!rep)
range_err = "no [parse-able] reply";
else if ((rep->sline.status() != Http::scOkay) && (rep->sline.status() != Http::scPartialContent))
range_err = "wrong status code";
- else if (hdr->has(Http::HdrType::CONTENT_RANGE))
- range_err = "origin server does ranges";
+ else if (rep->sline.status() == Http::scPartialContent)
+ range_err = "too complex response"; // probably contains what the client needs
+ else if (rep->sline.status() != Http::scOkay)
+ range_err = "wrong status code";
+ else if (hdr->has(Http::HdrType::CONTENT_RANGE)) {
+ Must(!contentRange); // this is a 200, not 206 response
+ range_err = "meaningless response"; // the status code or the header is wrong
+ }
else if (rep->content_length < 0)
range_err = "unknown length";
else if (rep->content_length != http->memObject()->getReply()->content_length)
// web server responded with a valid, but unexpected range.
// will (try-to) forward as-is.
//TODO: we should cope with multirange request/responses
- bool replyMatchRequest = rep->content_range != nullptr ?
- request->range->contains(rep->content_range->spec) :
+ // TODO: review, since rep->content_range is always nil here.
+ bool replyMatchRequest = contentRange != nullptr ?
+ request->range->contains(contentRange->spec) :
true;
const int spec_count = http->request->range->specs.size();
int64_t actual_clen = -1;
/* append appropriate header(s) */
if (spec_count == 1) {
if (!replyMatchRequest) {
- hdr->delById(Http::HdrType::CONTENT_RANGE);
- hdr->putContRange(rep->content_range);
+ hdr->putContRange(contentRange);
actual_clen = rep->content_length;
//http->range_iter.pos = rep->content_range->spec.begin();
- (*http->range_iter.pos)->offset = rep->content_range->spec.offset;
- (*http->range_iter.pos)->length = rep->content_range->spec.length;
+ (*http->range_iter.pos)->offset = contentRange->spec.offset;
+ (*http->range_iter.pos)->length = contentRange->spec.length;
} else {
HttpHdrRange::iterator pos = http->request->range->begin();
assert(*pos);
/* append Content-Range */
- if (!hdr->has(Http::HdrType::CONTENT_RANGE)) {
+ if (!contentRange) {
/* No content range, so this was a full object we are
* sending parts of.
*/
#include "tests/STUB.h"
HttpReply::HttpReply() : Http::Message(hoReply), date (0), last_modified (0),
- expires (0), surrogate_control (NULL), content_range (NULL), keep_alive (0),
- protoPrefix("HTTP/"), do_clean(false), bodySizeMax(-2)
+ expires(0), surrogate_control(nullptr), keep_alive(0),
+ protoPrefix("HTTP/"), do_clean(false), bodySizeMax(-2), content_range(nullptr)
{STUB_NOP}
HttpReply::~HttpReply() STUB
void HttpReply::setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires_) STUB
bool HttpReply::inheritProperties(const Http::Message *aMsg) STUB_RETVAL(false)
bool HttpReply::updateOnNotModified(HttpReply const*) STUB_RETVAL(false)
int64_t HttpReply::bodySize(const HttpRequestMethod&) const STUB_RETVAL(0)
+const HttpHdrContRange *HttpReply::contentRange() const STUB_RETVAL(nullptr)