Revision: 14399
Author: adrian.chadd
Date: Thu Feb 11 08:12:47 2010
Log: Migrate more of the client-side range request handling code out.
http://code.google.com/p/lusca-cache/source/detail?r=14399
Modified:
/branches/LUSCA_HEAD/src/client_side.c
/branches/LUSCA_HEAD/src/client_side_ranges.c
/branches/LUSCA_HEAD/src/client_side_ranges.h
=======================================
--- /branches/LUSCA_HEAD/src/client_side.c Thu Feb 11 02:08:09 2010
+++ /branches/LUSCA_HEAD/src/client_side.c Thu Feb 11 08:12:47 2010
@@ -1208,152 +1208,6 @@
return 1;
return 0;
}
-
-/*
- * returns true if If-Range specs match reply, false otherwise
- */
-static int
-clientIfRangeMatch(clientHttpRequest * http, HttpReply * rep)
-{
- const TimeOrTag spec = httpHeaderGetTimeOrTag(&http->request->header,
HDR_IF_RANGE);
- /* check for parsing falure */
- if (!spec.valid)
- return 0;
- /* got an ETag? */
- if (spec.tag) {
- const char *rep_tag = httpHeaderGetStr(&rep->header, HDR_ETAG);
- debug(33, 3) ("clientIfRangeMatch: ETags: %s and %s\n",
- spec.tag, rep_tag ? rep_tag : "<none>");
- if (!rep_tag)
- return 0; /* entity has no etag to compare with! */
- if (spec.tag[0] == 'W' || rep_tag[0] == 'W') {
- debug(33, 1) ("clientIfRangeMatch: Weak ETags are not allowed in
If-Range: %s ? %s\n",
- spec.tag, rep_tag);
- return 0; /* must use strong validator for sub-range
requests */
- }
- return strcmp(rep_tag, spec.tag) == 0;
- }
- /* got modification time? */
- else if (spec.time >= 0) {
- return http->entry->lastmod == spec.time;
- }
- assert(0); /* should not happen */
- return 0;
-}
-
-/* returns expected content length for multi-range replies
- * note: assumes that httpHdrRangeCanonize has already been called
- * warning: assumes that HTTP headers for individual ranges at the
- * time of the actuall assembly will be exactly the same as
- * the headers when clientMRangeCLen() is called */
-static squid_off_t
-clientMRangeCLen(clientHttpRequest * http)
-{
- squid_off_t clen = 0;
- HttpHdrRangePos pos = HttpHdrRangeInitPos;
- const HttpHdrRangeSpec *spec;
- MemBuf mb;
-
- assert(http->entry->mem_obj);
-
- memBufDefInit(&mb);
- while ((spec = httpHdrRangeGetSpec(http->request->range, &pos))) {
-
- /* account for headers for this range */
- memBufReset(&mb);
- clientPackRangeHdr(http->entry->mem_obj->reply,
- spec, http->range_iter.boundary, &mb);
- clen += mb.size;
-
- /* account for range content */
- clen += spec->length;
-
- debug(33, 6) ("clientMRangeCLen: (clen += %ld + %" PRINTF_OFF_T ") == %"
PRINTF_OFF_T "\n",
- (long int) mb.size, spec->length, clen);
- }
- /* account for the terminating boundary */
- memBufReset(&mb);
- clientPackTermBound(http->range_iter.boundary, &mb);
- clen += mb.size;
-
- memBufClean(&mb);
- return clen;
-}
-
-/* adds appropriate Range headers if needed */
-static void
-clientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep)
-{
- HttpHeader *hdr = rep ? &rep->header : 0;
- const char *range_err = NULL;
- request_t *request = http->request;
- assert(request->range);
- /* check if we still want to do ranges */
- if (!rep)
- range_err = "no [parse-able] reply";
- else if (rep->sline.status != HTTP_OK)
- range_err = "wrong status code";
- else if (httpHeaderHas(hdr, HDR_CONTENT_RANGE))
- range_err = "origin server does ranges";
- else if (rep->content_length < 0)
- range_err = "unknown length";
- else if (rep->content_length !=
http->entry->mem_obj->reply->content_length)
- range_err = "INCONSISTENT length"; /* a bug? */
- else if (httpHeaderHas(&http->request->header, HDR_IF_RANGE)
&& !clientIfRangeMatch(http, rep))
- range_err = "If-Range match failed";
- else if (!httpHdrRangeCanonize(http->request->range,
rep->content_length))
- range_err = "canonization failed";
- else if (httpHdrRangeIsComplex(http->request->range))
- range_err = "too complex range header";
- else if (!request->flags.cachable) /* from we_do_ranges in http.c */
- range_err = "non-cachable request";
- else if (!http->flags.hit &&
httpHdrRangeOffsetLimit(http->request->range))
- range_err = "range outside range_offset_limit";
- /* get rid of our range specs on error */
- if (range_err) {
- debug(33, 3) ("clientBuildRangeHeader: will not do ranges: %s.\n",
range_err);
- httpHdrRangeDestroy(http->request->range);
- http->request->range = NULL;
- } else {
- const int spec_count = http->request->range->specs.count;
- squid_off_t actual_clen = -1;
-
- debug(33, 3) ("clientBuildRangeHeader: range spec count: %d virgin
clen: %" PRINTF_OFF_T "\n",
- spec_count, rep->content_length);
- assert(spec_count > 0);
- /* append appropriate header(s) */
- if (spec_count == 1) {
- HttpHdrRangePos pos = HttpHdrRangeInitPos;
- const HttpHdrRangeSpec *spec =
httpHdrRangeGetSpec(http->request->range, &pos);
- assert(spec);
- /* append Content-Range */
- httpHeaderAddContRange(hdr, *spec, rep->content_length);
- /* set new Content-Length to the actual number of bytes
- * transmitted in the message-body */
- actual_clen = spec->length;
- } else {
- /* multipart! */
- /* generate boundary string */
- http->range_iter.boundary = httpHdrRangeBoundaryStr(http);
- /* delete old Content-Type, add ours */
- httpHeaderDelById(hdr, HDR_CONTENT_TYPE);
- httpHeaderPutStrf(hdr, HDR_CONTENT_TYPE,
- "multipart/byteranges; boundary=\"%.*s\"",
- strLen2(http->range_iter.boundary),
- strBuf2(http->range_iter.boundary));
- /* Content-Length is not required in multipart responses
- * but it is always nice to have one */
- actual_clen = clientMRangeCLen(http);
- }
-
- /* replace Content-Length header */
- assert(actual_clen >= 0);
- httpHeaderDelById(hdr, HDR_CONTENT_LENGTH);
- httpHeaderPutSize(hdr, HDR_CONTENT_LENGTH, actual_clen);
- rep->content_length = actual_clen;
- debug(33, 3) ("clientBuildRangeHeader: actual content length: %"
PRINTF_OFF_T "\n", actual_clen);
- }
-}
/*
* filters out unwanted entries from original reply header
=======================================
--- /branches/LUSCA_HEAD/src/client_side_ranges.c Wed Feb 10 23:10:44 2010
+++ /branches/LUSCA_HEAD/src/client_side_ranges.c Thu Feb 11 08:12:47 2010
@@ -168,3 +168,150 @@
http->out.offset = body_off + i->prefix_size; /* sync */
return i->debt_size > 0;
}
+
+/* returns expected content length for multi-range replies
+ * note: assumes that httpHdrRangeCanonize has already been called
+ * warning: assumes that HTTP headers for individual ranges at the
+ * time of the actuall assembly will be exactly the same as
+ * the headers when clientMRangeCLen() is called */
+static squid_off_t
+clientMRangeCLen(clientHttpRequest * http)
+{
+ squid_off_t clen = 0;
+ HttpHdrRangePos pos = HttpHdrRangeInitPos;
+ const HttpHdrRangeSpec *spec;
+ MemBuf mb;
+
+ assert(http->entry->mem_obj);
+
+ memBufDefInit(&mb);
+ while ((spec = httpHdrRangeGetSpec(http->request->range, &pos))) {
+
+ /* account for headers for this range */
+ memBufReset(&mb);
+ clientPackRangeHdr(http->entry->mem_obj->reply,
+ spec, http->range_iter.boundary, &mb);
+ clen += mb.size;
+
+ /* account for range content */
+ clen += spec->length;
+
+ debug(33, 6) ("clientMRangeCLen: (clen += %ld + %" PRINTF_OFF_T ")
== %" PRINTF_OFF_T "\n",
+ (long int) mb.size, spec->length, clen);
+ }
+ /* account for the terminating boundary */
+ memBufReset(&mb);
+ clientPackTermBound(http->range_iter.boundary, &mb);
+ clen += mb.size;
+
+ memBufClean(&mb);
+ return clen;
+}
+
+/*
+ * returns true if If-Range specs match reply, false otherwise
+ */
+static int
+clientIfRangeMatch(clientHttpRequest * http, HttpReply * rep)
+{
+ const TimeOrTag spec = httpHeaderGetTimeOrTag(&http->request->header,
HDR_IF_RANGE);
+ /* check for parsing falure */
+ if (!spec.valid)
+ return 0;
+ /* got an ETag? */
+ if (spec.tag) {
+ const char *rep_tag = httpHeaderGetStr(&rep->header, HDR_ETAG);
+ debug(33, 3) ("clientIfRangeMatch: ETags: %s and %s\n",
+ spec.tag, rep_tag ? rep_tag : "<none>");
+ if (!rep_tag)
+ return 0; /* entity has no etag to compare with! */
+ if (spec.tag[0] == 'W' || rep_tag[0] == 'W') {
+ debug(33, 1) ("clientIfRangeMatch: Weak ETags are not allowed
in If-Range: %s ? %s\n",
+ spec.tag, rep_tag);
+ return 0; /* must use strong validator for sub-range
requests */
+ }
+ return strcmp(rep_tag, spec.tag) == 0;
+ }
+ /* got modification time? */
+ else if (spec.time >= 0) {
+ return http->entry->lastmod == spec.time;
+ }
+ assert(0); /* should not happen */
+ return 0;
+}
+
+/* adds appropriate Range headers if needed */
+void
+clientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep)
+{
+ HttpHeader *hdr = rep ? &rep->header : 0;
+ const char *range_err = NULL;
+ request_t *request = http->request;
+ assert(request->range);
+ /* check if we still want to do ranges */
+ if (!rep)
+ range_err = "no [parse-able] reply";
+ else if (rep->sline.status != HTTP_OK)
+ range_err = "wrong status code";
+ else if (httpHeaderHas(hdr, HDR_CONTENT_RANGE))
+ range_err = "origin server does ranges";
+ else if (rep->content_length < 0)
+ range_err = "unknown length";
+ else if (rep->content_length !=
http->entry->mem_obj->reply->content_length)
+ range_err = "INCONSISTENT length"; /* a bug? */
+ else if (httpHeaderHas(&http->request->header, HDR_IF_RANGE)
&& !clientIfRangeMatch(http, rep))
+ range_err = "If-Range match failed";
+ else if (!httpHdrRangeCanonize(http->request->range,
rep->content_length))
+ range_err = "canonization failed";
+ else if (httpHdrRangeIsComplex(http->request->range))
+ range_err = "too complex range header";
+ else if (!request->flags.cachable) /* from we_do_ranges in http.c */
+ range_err = "non-cachable request";
+ else if (!http->flags.hit &&
httpHdrRangeOffsetLimit(http->request->range))
+ range_err = "range outside range_offset_limit";
+ /* get rid of our range specs on error */
+ if (range_err) {
+ debug(33, 3) ("clientBuildRangeHeader: will not do ranges: %s.\n",
range_err);
+ httpHdrRangeDestroy(http->request->range);
+ http->request->range = NULL;
+ } else {
+ const int spec_count = http->request->range->specs.count;
+ squid_off_t actual_clen = -1;
+
+ debug(33, 3) ("clientBuildRangeHeader: range spec count: %d virgin
clen: %" PRINTF_OFF_T "\n",
+ spec_count, rep->content_length);
+ assert(spec_count > 0);
+ /* append appropriate header(s) */
+ if (spec_count == 1) {
+ HttpHdrRangePos pos = HttpHdrRangeInitPos;
+ const HttpHdrRangeSpec *spec =
httpHdrRangeGetSpec(http->request->range, &pos);
+ assert(spec);
+ /* append Content-Range */
+ httpHeaderAddContRange(hdr, *spec, rep->content_length);
+ /* set new Content-Length to the actual number of bytes
+ * transmitted in the message-body */
+ actual_clen = spec->length;
+ } else {
+ /* multipart! */
+ /* generate boundary string */
+ http->range_iter.boundary = httpHdrRangeBoundaryStr(http);
+ /* delete old Content-Type, add ours */
+ httpHeaderDelById(hdr, HDR_CONTENT_TYPE);
+ httpHeaderPutStrf(hdr, HDR_CONTENT_TYPE,
+ "multipart/byteranges; boundary=\"%.*s\"",
+ strLen2(http->range_iter.boundary),
+ strBuf2(http->range_iter.boundary));
+ /* Content-Length is not required in multipart responses
+ * but it is always nice to have one */
+ actual_clen = clientMRangeCLen(http);
+ }
+
+ /* replace Content-Length header */
+ assert(actual_clen >= 0);
+ httpHeaderDelById(hdr, HDR_CONTENT_LENGTH);
+ httpHeaderPutSize(hdr, HDR_CONTENT_LENGTH, actual_clen);
+ rep->content_length = actual_clen;
+ debug(33, 3) ("clientBuildRangeHeader: actual content length: %"
PRINTF_OFF_T "\n", actual_clen);
+ }
+}
+
=======================================
--- /branches/LUSCA_HEAD/src/client_side_ranges.h Wed Feb 10 23:10:44 2010
+++ /branches/LUSCA_HEAD/src/client_side_ranges.h Thu Feb 11 08:12:47 2010
@@ -7,5 +7,6 @@
MemBuf * mb);
extern int clientCanPackMoreRanges(const clientHttpRequest * http,
HttpHdrRangeIter * i, size_t size);
extern int clientPackMoreRanges(clientHttpRequest * http, const char *buf,
size_t size, MemBuf * mb);
+extern void clientBuildRangeHeader(clientHttpRequest * http, HttpReply *
rep);
#endif
--
You received this message because you are subscribed to the Google Groups
"lusca-commit" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/lusca-commit?hl=en.