* iter up at this point.
*/
node->readBuffer.offset = request->range->lowestOffset(0);
- http->range_iter.pos = request->range->begin();
- http->range_iter.end = request->range->end();
- http->range_iter.valid = true;
}
}
al->setVirginUrlForMissingRequest(errorUri);
}
+// XXX: This should not be a _request_ method. Move range_iter elsewhere.
+int64_t
+ClientHttpRequest::prepPartialResponseGeneration()
+{
+ assert(request);
+ assert(request->range);
+
+ range_iter.pos = request->range->begin();
+ range_iter.end = request->range->end();
+ range_iter.debt_size = 0;
+ const auto multipart = request->range->specs.size() > 1;
+ if (multipart)
+ range_iter.boundary = rangeBoundaryStr();
+ range_iter.valid = true; // TODO: Remove.
+ range_iter.updateSpec(); // TODO: Refactor to initialize rather than update.
+
+ assert(range_iter.pos != range_iter.end);
+ const auto &firstRange = *range_iter.pos;
+ assert(firstRange);
+ out.offset = firstRange->offset;
+
+ return multipart ? mRangeCLen() : firstRange->length;
+}
+
#if USE_ADAPTATION
/// Initiate an asynchronous adaptation transaction which will call us back.
void
dlink_node active;
dlink_list client_stream;
- int mRangeCLen();
+ int64_t mRangeCLen() const;
ClientRequestContext *calloutContext;
void doCallouts();
/// neither the current request nor the parsed request URI are known
void setErrorUri(const char *errorUri);
+ /// Prepares to satisfy a Range request with a generated HTTP 206 response.
+ /// Initializes range_iter state to allow raw range_iter access.
+ /// \returns Content-Length value for the future response; never negative
+ int64_t prepPartialResponseGeneration();
+
/// Build an error reply. For use with the callouts.
void calloutsError(const err_type error, const ErrorDetail::Pointer &errDetail);
} else {
/* XXX: TODO: Review, this unconditional set may be wrong. */
rep->sline.set(rep->sline.version, Http::scPartialContent);
- // web server responded with a valid, but unexpected range.
- // will (try-to) forward as-is.
- //TODO: we should cope with multirange request/responses
- // TODO: review, since rep->content_range is always nil here.
- bool replyMatchRequest = contentRange != nullptr ?
- request->range->contains(contentRange->spec) :
- true;
+
+ // before range_iter accesses
+ const auto actual_clen = http->prepPartialResponseGeneration();
+
const int spec_count = http->request->range->specs.size();
- int64_t actual_clen = -1;
debugs(33, 3, "range spec count: " << spec_count <<
" virgin clen: " << rep->content_length);
assert(spec_count > 0);
/* append appropriate header(s) */
if (spec_count == 1) {
- if (!replyMatchRequest) {
- hdr->putContRange(contentRange);
- actual_clen = rep->content_length;
- //http->range_iter.pos = rep->content_range->spec.begin();
- (*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 (!contentRange) {
- /* No content range, so this was a full object we are
- * sending parts of.
- */
- httpHeaderAddContRange(hdr, **pos, rep->content_length);
- }
-
- /* set new Content-Length to the actual number of bytes
- * transmitted in the message-body */
- actual_clen = (*pos)->length;
- }
+ const auto singleSpec = *http->request->range->begin();
+ assert(singleSpec);
+ httpHeaderAddContRange(hdr, *singleSpec, rep->content_length);
} else {
/* multipart! */
- /* generate boundary string */
- http->range_iter.boundary = http->rangeBoundaryStr();
/* delete old Content-Type, add ours */
hdr->delById(Http::HdrType::CONTENT_TYPE);
httpHeaderPutStrf(hdr, Http::HdrType::CONTENT_TYPE,
"multipart/byteranges; boundary=\"" SQUIDSTRINGPH "\"",
SQUIDSTRINGPRINT(http->range_iter.boundary));
- /* Content-Length is not required in multipart responses
- * but it is always nice to have one */
- actual_clen = http->mRangeCLen();
-
- /* http->out needs to start where we want data at */
- http->out.offset = http->range_iter.currentSpec()->offset;
}
/* replace Content-Length header */
hdr->delById(Http::HdrType::CONTENT_LENGTH);
hdr->putInt64(Http::HdrType::CONTENT_LENGTH, actual_clen);
debugs(33, 3, "actual content length: " << actual_clen);
-
- /* And start the range iter off */
- http->range_iter.updateSpec();
}
}