]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
- added ETag.c
authorrousskov <>
Thu, 4 Jun 1998 04:32:56 +0000 (04:32 +0000)
committerrousskov <>
Thu, 4 Jun 1998 04:32:56 +0000 (04:32 +0000)
- added processing of If-Range headers

ChangeLog
src/ETag.cc [new file with mode: 0644]
src/HttpHeader.cc
src/HttpHeaderTools.cc
src/Makefile.in
src/client_side.cc
src/enums.h
src/http.cc
src/protos.h
src/structs.h
src/typedefs.h

index c71a0a27d095f902137dec2781ce91e0a73bad29..ab8fb0f982f8a62c0b07a6b6bab1129650ac3d1c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,9 +3,12 @@
          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):
 
diff --git a/src/ETag.cc b/src/ETag.cc
new file mode 100644 (file)
index 0000000..f197e20
--- /dev/null
@@ -0,0 +1,64 @@
+
+/*
+ * $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);
+}
index 6d566f3391b4eb6b4b4748021948d569bc34804d..ee456cd34b60a33509e247f7b769553fb841f734 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $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
@@ -94,12 +94,12 @@ static const HttpHeaderFieldAttrs HeadersAttrs[] =
     {"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},
@@ -824,6 +824,41 @@ httpHeaderGetAuth(const HttpHeader * hdr, http_hdr_type id, const char *authSche
     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
  */
index 801e0b730edbbe0bb9c33a1ce55a6c6ba60b8dd6..efefb5fb5d692d7b92f56a31ad5d69643e9d3dc4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $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
@@ -154,6 +154,7 @@ httpHeaderAddContRange(HttpHeader * hdr, HttpHdrRangeSpec spec, size_t ent_len)
     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
index f2ae25a6f825b485e43df07b29cfc406acaa63e4..07a2146cfed36c753c92b9592edf32ea5c541ec0 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  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:
 #
@@ -92,6 +92,7 @@ OBJS          = \
                disk.o \
                dns.o \
                errorpage.o \
+               ETag.o \
                event.o \
                fd.o \
                filemap.o \
index a2a0078a3f3dd9776fdf692e44901bc6fdb3b927..3d44d58989bd9e2e6e58dda824467d4c1cd59631 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $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
@@ -1057,6 +1057,36 @@ clientBuildReplyHeader(clientHttpRequest * http,
 }
 #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)
@@ -1077,6 +1107,8 @@ 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
@@ -1092,6 +1124,8 @@ clientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep)
        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;
index a3780bbdab5afa9ed82f8caa02e81b8db48178f9..acffe8b553e618415452acf1f4fa2758bc48f936 100644 (file)
@@ -258,9 +258,11 @@ typedef enum {
     ftInt,
     ftStr,
     ftDate_1123,
+    ftETag,
     ftPCc,
+    ftPContRange,
     ftPRange,
-    ftPContRange
+    ftDate_1123_or_ETag
 } field_type;
 
 /* possible owners of http header */
index ed7e7a0cee685964350fc4aa68d63401e8a1751b..318ceb5a2a71f9e588606b2cc2bb895134e560a9 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $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
@@ -658,6 +658,7 @@ httpBuildRequestHeader(request_t * request,
            }
            break;
        case HDR_RANGE:
+       case HDR_IF_RANGE:
            if (!filter_range)
                httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
            break;
index 3d562af27fe4a713fb8456ca527cb2156a2bf7e9..7a88ca9a73ff4e571665411ce285361419726c12 100644 (file)
@@ -240,6 +240,10 @@ extern int httpAnonHdrAllowed(http_hdr_type hdr_id);
 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);
@@ -350,12 +354,14 @@ extern void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type type, time_t time)
 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);
index d421fe808d161820f12e43b0baa2e2a877ff1b3a..f5aa4158f624925df065275887962e7f9216362b 100644 (file)
@@ -409,6 +409,16 @@ struct _dwrite_q {
     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;
@@ -522,6 +532,13 @@ struct _HttpHdrContRange {
     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;
index b88b17fd542a7a78d827fd17c916795595454243..a82a2ae3d756828afbbf3e08c0026d67eee3a403 100644 (file)
@@ -44,6 +44,7 @@ typedef struct _dread_ctrl dread_ctrl;
 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;
@@ -60,6 +61,7 @@ typedef struct _HttpHdrRangeSpec HttpHdrRangeSpec;
 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;