potentially cachable Range request for a not cached object, Squid
requests the whole object from origin server and then replies with
specified range(s) to the client. Multi-range requests are
- supported. Limitations: If-Range header is not supported and
- ignored; Multi-range requests with out of order or overlapping
- ranges are not supported.
+ supported. If-Range requests are supported. Limitations:
+ Multi-range requests with out of order or overlapping ranges are not
+ supported.
+ - Made md5.c use standard memcpy and memset if they are avaliable.
+ - Memory pools will now shrink if Squid is run-time reconfigured with
+ smaller value of memory_pools_limit tag.
Changes to squid-1.2.beta22 (June 1, 1998):
--- /dev/null
+
+/*
+ * $Id: ETag.cc,v 1.1 1998/06/03 22:32:57 rousskov Exp $
+ *
+ * DEBUG: section 7? HTTP ETag
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "squid.h"
+
+/*
+ * Note: ETag is not an http "field" like, for example HttpHdrRange. ETag is a
+ * field-value that maybe used in many http fields.
+ */
+
+/* parses a string as weak or strong entity-tag; returns true on success */
+/* note: we do not duplicate "str"! */
+int
+etagParseInit(ETag *etag, const char *str)
+{
+ int len;
+ assert(etag && str);
+ etag->str = NULL;
+ etag->weak = !strncmp(str, "W/", 2);
+ if (etag->weak)
+ str += 2;
+ /* check format (quoted-string) */
+ len = strlen(str);
+ if (len >= 2 && str[0] == '"' && str[len-1] == '"')
+ etag->str = str;
+ return etag->str != NULL;
+}
+
+/* returns true if etags are equal */
+int
+etagIsEqual(const ETag *tag1, const ETag *tag2)
+{
+ assert(tag1 && tag2);
+ assert(!tag1->weak && !tag2->weak); /* weak comparison not implemented yet */
+ return !strcmp(tag1->str, tag2->str);
+}
/*
- * $Id: HttpHeader.cc,v 1.42 1998/06/03 15:52:15 rousskov Exp $
+ * $Id: HttpHeader.cc,v 1.43 1998/06/03 22:32:58 rousskov Exp $
*
* DEBUG: section 55 HTTP Header
* AUTHOR: Alex Rousskov
{"Content-Range", HDR_CONTENT_RANGE, ftPContRange},
{"Content-Type", HDR_CONTENT_TYPE, ftStr},
{"Date", HDR_DATE, ftDate_1123},
- {"ETag", HDR_ETAG, ftStr}, /* for now */
+ {"ETag", HDR_ETAG, ftETag},
{"Expires", HDR_EXPIRES, ftDate_1123},
{"From", HDR_FROM, ftStr},
{"Host", HDR_HOST, ftStr},
{"If-Modified-Since", HDR_IF_MODIFIED_SINCE, ftDate_1123},
- {"If-Range", HDR_IF_RANGE, ftDate_1123}, /* for now (ftDate_1123 or ftStr!) */
+ {"If-Range", HDR_IF_RANGE, ftDate_1123_or_ETag},
{"Last-Modified", HDR_LAST_MODIFIED, ftDate_1123},
{"Link", HDR_LINK, ftStr},
{"Location", HDR_LOCATION, ftStr},
return base64_decode(field);
}
+ETag
+httpHeaderGetETag(const HttpHeader * hdr, http_hdr_type id)
+{
+ ETag etag = { NULL, -1 };
+ HttpHeaderEntry *e;
+ assert(Headers[id].type == ftETag); /* must be of an appropriate type */
+ if ((e = httpHeaderFindEntry(hdr, id)))
+ etagParseInit(&etag, strBuf(e->value));
+ return etag;
+}
+
+TimeOrTag
+httpHeaderGetTimeOrTag(const HttpHeader * hdr, http_hdr_type id)
+{
+ TimeOrTag tot;
+ HttpHeaderEntry *e;
+ assert(Headers[id].type == ftDate_1123_or_ETag); /* must be of an appropriate type */
+ memset(&tot, 0, sizeof(tot));
+ if ((e = httpHeaderFindEntry(hdr, id))) {
+ const char *str = strBuf(e->value);
+ /* try as an ETag */
+ if (etagParseInit(&tot.tag, str)) {
+ tot.valid = tot.tag.str != NULL;
+ tot.time = -1;
+ } else {
+ /* or maybe it is time? */
+ tot.time = parse_rfc1123(str);
+ tot.valid = tot.time >= 0;
+ tot.tag.str = NULL;
+ }
+ }
+ assert(tot.time < 0 || !tot.tag.str); /* paranoid */
+ return tot;
+}
+
/*
* HttpHeaderEntry
*/
/*
- * $Id: HttpHeaderTools.cc,v 1.18 1998/06/02 21:38:06 rousskov Exp $
+ * $Id: HttpHeaderTools.cc,v 1.19 1998/06/03 22:32:59 rousskov Exp $
*
* DEBUG: section 66 HTTP Header Tools
* AUTHOR: Alex Rousskov
httpHdrContRangeDestroy(cr);
}
+
/*
* return true if a given directive is found in at least one of the "connection" header-fields
* note: if HDR_PROXY_CONNECTION is present we ignore HDR_CONNECTION
#
# Makefile for the Squid Object Cache server
#
-# $Id: Makefile.in,v 1.151 1998/05/28 22:57:55 wessels Exp $
+# $Id: Makefile.in,v 1.152 1998/06/03 22:32:59 rousskov Exp $
#
# Uncomment and customize the following to suit your needs:
#
disk.o \
dns.o \
errorpage.o \
+ ETag.o \
event.o \
fd.o \
filemap.o \
/*
- * $Id: client_side.cc,v 1.327 1998/06/02 23:29:03 rousskov Exp $
+ * $Id: client_side.cc,v 1.328 1998/06/03 22:33:00 rousskov Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
}
#endif
+/* 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.str) {
+ ETag rep_tag = httpHeaderGetETag(&rep->header, HDR_ETAG);
+ debug(33,3) ("clientIfRangeMatch: ETags: %s and %s\n",
+ spec.tag.str, rep_tag.str ? rep_tag.str : "<none>");
+ if (!rep_tag.str)
+ return 0; /* entity has no etag to compare with! */
+ if (spec.tag.weak || rep_tag.weak) {
+ debug(33,1) ("clientIfRangeMatch: Weak ETags are not in If-Range: %s ? %s\n",
+ spec.tag.str, rep_tag.str);
+ return 0; /* must use strong validator for sub-range requests */
+ }
+ return etagIsEqual(&rep_tag, &spec.tag);
+ }
+ /* got modification time? */
+ if (spec.time >= 0) {
+ return http->entry->lastmod <= spec.time;
+ }
+ assert(0); /* should not happen */
+ return 0;
+}
+
/* adds appropriate Range headers if needed */
static void
clientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep)
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";
if (!httpHdrRangeCanonize(http->request->range, rep->content_length))
range_err = "canonization failed";
else
debug(33, 2) ("clientBuildRangeHeader: range spec count: %d clen: %d\n",
spec_count, rep->content_length);
assert(spec_count > 0);
+ /* ETags should not be returned with Partial Content replies? */
+ httpHeaderDelById(hdr, HDR_ETAG);
/* append appropriate header(s) */
if (spec_count == 1) {
HttpHdrRangePos pos = HttpHdrRangeInitPos;
ftInt,
ftStr,
ftDate_1123,
+ ftETag,
ftPCc,
+ ftPContRange,
ftPRange,
- ftPContRange
+ ftDate_1123_or_ETag
} field_type;
/* possible owners of http header */
/*
- * $Id: http.cc,v 1.280 1998/06/02 21:46:02 rousskov Exp $
+ * $Id: http.cc,v 1.281 1998/06/03 22:33:02 rousskov Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
}
break;
case HDR_RANGE:
+ case HDR_IF_RANGE:
if (!filter_range)
httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
break;
extern int httpAnonHdrDenied(http_hdr_type hdr_id);
extern void httpBuildRequestHeader(request_t *, request_t *, StoreEntry *, HttpHeader *, int, int);
+/* ETag */
+extern int etagParseInit(ETag *etag, const char *str);
+extern int etagIsEqual(const ETag *tag1, const ETag *tag2);
+
/* Http Status Line */
/* init/clean */
extern void httpStatusLineInit(HttpStatusLine * sline);
extern void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type type, const char *str);
extern void httpHeaderPutAuth(HttpHeader * hdr, const char *authScheme, const char *realm);
extern void httpHeaderPutCc(HttpHeader * hdr, const HttpHdrCc * cc);
-extern void httpHeaderPutContRange(HttpHeader * hdr, const HttpHdrContRange * cr);
-extern void httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange * range);
+extern void httpHeaderPutContRange(HttpHeader * hdr, const HttpHdrContRange *cr);
+extern void httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange *range);
extern void httpHeaderPutExt(HttpHeader * hdr, const char *name, const char *value);
extern int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id);
extern time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id);
+extern TimeOrTag httpHeaderGetTimeOrTag(const HttpHeader * hdr, http_hdr_type id);
extern HttpHdrCc *httpHeaderGetCc(const HttpHeader * hdr);
+extern ETag httpHeaderGetETag(const HttpHeader * hdr, http_hdr_type id);
extern HttpHdrRange *httpHeaderGetRange(const HttpHeader * hdr);
extern HttpHdrContRange *httpHeaderGetContRange(const HttpHeader * hdr);
extern const char *httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id);
FREE *free_func;
};
+
+/* ETag support is rudimantal;
+ * this struct is likely to change
+ * Note: "str" points to memory in HttpHeaderEntry (for now)
+ * so ETags should be used as tmp variables only (for now) */
+struct _ETag {
+ const char *str; /* quoted-string */
+ int weak; /* true if it is a weak validator */
+};
+
struct _fde {
unsigned int type;
unsigned int open;
size_t elength; /* entity length, not content length */
};
+/* some fields can hold either time or etag specs (e.g. If-Range) */
+struct _TimeOrTag {
+ ETag tag; /* entity tag */
+ time_t time;
+ int valid; /* true if struct is usable */
+};
+
/* data for iterating thru range specs */
struct _HttpHdrRangeIter {
HttpHdrRangeSpec spec;
typedef struct _dnsserver_t dnsserver_t;
typedef struct _dnsStatData dnsStatData;
typedef struct _dwrite_q dwrite_q;
+typedef struct _ETag ETag;
typedef struct _fde fde;
typedef struct _fileMap fileMap;
typedef struct _fqdncache_entry fqdncache_entry;
typedef struct _HttpHdrRange HttpHdrRange;
typedef struct _HttpHdrRangeIter HttpHdrRangeIter;
typedef struct _HttpHdrContRange HttpHdrContRange;
+typedef struct _TimeOrTag TimeOrTag;
typedef struct _HttpHeaderEntry HttpHeaderEntry;
typedef struct _HttpHeaderFieldStat HttpHeaderFieldStat;
typedef struct _HttpBody HttpBody;