]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
- Added HttpHdrRange; the code is not yet tested and not used by other
authorrousskov <>
Fri, 6 Mar 1998 03:55:55 +0000 (03:55 +0000)
committerrousskov <>
Fri, 6 Mar 1998 03:55:55 +0000 (03:55 +0000)
  commited modules.

src/HttpHdrCc.cc
src/HttpHdrRange.cc [new file with mode: 0644]
src/HttpHeader.cc
src/HttpHeaderTools.cc
src/Makefile.in
src/enums.h
src/protos.h
src/squid.h
src/structs.h
src/typedefs.h

index d5333a744478b131f5f14d1f50c4929d5757e767..5181f37962d0cda920cdb031bbb7b89329bb6975 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpHdrCc.cc,v 1.2 1998/03/05 00:45:36 rousskov Exp $
+ * $Id: HttpHdrCc.cc,v 1.3 1998/03/05 20:55:55 rousskov Exp $
  *
  * DEBUG: section 65    HTTP Cache Control Header
  * AUTHOR: Alex Rousskov
@@ -46,7 +46,10 @@ static field_attrs_t CcAttrs[CC_ENUM_END] =
 
 
 /* counters */
-static int CcPasredCount = 0;
+static int CcParsedCount = 0;
+
+/* local prototypes */
+static int httpHdrCcParseInit(HttpHdrCc * cc, const char *str);
 
 
 /* module initialization */
@@ -72,12 +75,15 @@ HttpHdrCc *
 httpHdrCcParseCreate(const char *str)
 {
     HttpHdrCc *cc = httpHdrCcCreate();
-    httpHdrCcParseInit(cc, str);
+    if (!httpHdrCcParseInit(cc, str)) {
+       httpHdrCcDestroy(cc);
+       cc = NULL;
+    }
     return cc;
 }
 
 /* parses a 0-terminating string and inits cc */
-void
+static int
 httpHdrCcParseInit(HttpHdrCc * cc, const char *str)
 {
     const char *item;
@@ -87,7 +93,7 @@ httpHdrCcParseInit(HttpHdrCc * cc, const char *str)
     int ilen;
     assert(cc && str);
 
-    CcPasredCount++;
+    CcParsedCount++;
     /* iterate through comma separated list */
     while (strListGetItem(str, ',', &item, &ilen, &pos)) {
        /* strip '=' statements @?@ */
@@ -123,7 +129,7 @@ httpHdrCcParseInit(HttpHdrCc * cc, const char *str)
            break;
        }
     }
-    return;
+    return cc->mask != 0;
 }
 
 void
@@ -189,5 +195,5 @@ httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int c
     const char *name = valid_id ? CcAttrs[id].name : "INVALID";
     if (count || valid_id)
        storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
-           id, name, count, xdiv(count, CcPasredCount));
+           id, name, count, xdiv(count, CcParsedCount));
 }
diff --git a/src/HttpHdrRange.cc b/src/HttpHdrRange.cc
new file mode 100644 (file)
index 0000000..36a9054
--- /dev/null
@@ -0,0 +1,226 @@
+
+/*
+ * $Id: HttpHdrRange.cc,v 1.1 1998/03/05 20:55:55 rousskov Exp $
+ *
+ * DEBUG: section 64    HTTP Content-Range Header
+ * 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"
+
+#if 0
+    Currently only byte ranges are supported
+
+    Essentially, there are three types of byte ranges:
+
+       1) first-byte-pos "-" last-byte-pos  // range
+       2) first-byte-pos "-"                // trailer
+       3)                "-" suffix-length  // suffix (last length bytes)
+
+
+    When Range field is parsed, we have no clue about the content length of
+    the document. Thus, we simply code an "absent" part using range_spec_unknown
+    constant.
+
+    Note: when response length becomes known, we convert any range spec into
+    type one above. (Canonization process).
+
+#endif
+
+
+/* local constants */
+#define range_spec_unknown ((size_t)-1)
+
+/* local routines */
+#define known_spec(s) ((s) != range_spec_unknown)
+#define size_min(a,b) ((a) <= (b) ? (a) : (b))
+#define size_diff(a,b) ((a) >= (b) ? ((a)-(b)) : 0)
+static int httpHdrRangeSpecCanonize(HttpHdrRangeSpec *spec, size_t clen);
+
+/* globals */
+static int RangeParsedCount = 0;
+
+/*
+ * Range-Spec
+ */
+
+
+/* parses range-spec and returns new object on success */
+static HttpHdrRangeSpec *
+httpHdrRangeSpecParseCreate(const char *field, int flen)
+{
+    HttpHdrRangeSpec *sp = NULL;
+    HttpHdrRangeSpec spec = { range_spec_unknown, range_spec_unknown };
+    const char *p;
+    if (flen < 2)
+       return NULL;
+    /* is it a suffix-byte-range-spec ? */
+    if (*field == '-') {
+       if (!httpHeaderParseSize(field+1, &spec.length))
+           return NULL;
+    } else
+    /* must have a '-' somewhere in _this_ field */
+    if (!((p = strchr(field, '-')) && (p-field < flen))) {
+       debug(64, 2) ("ignoring invalid range-spec near: '%s'\n", field);
+       return NULL;
+    } else {
+       if (!httpHeaderParseSize(field+1, &spec.offset))
+           return NULL;
+       p++;
+       /* do we have last-pos ? */
+       if (p - field < flen) {
+           size_t last_pos;
+           if (!httpHeaderParseSize(p, &last_pos))
+               return NULL;
+           spec.length = size_diff(last_pos, spec.offset);
+       }
+    }
+    /* we managed to parse, check if the result makes sence */
+    if (known_spec(spec.length) && !spec.length) {
+       debug(64, 2) ("ignoring invalid range-spec near: '%s'\n", field);
+       return NULL;
+    }
+    sp = memAllocate(MEM_HTTP_HDR_RANGE_SPEC);
+    *sp = spec;
+    return sp;
+}
+
+static void
+httpHdrRangeSpecDestroy(HttpHdrRangeSpec *spec)
+{
+    memFree(MEM_HTTP_HDR_RANGE_SPEC, spec);
+}
+
+/* fills "absent" positions in range specification based on response body size 
+   returns true if the range is still valid
+   range is valid if its intersection with [0,length-1] is not empty
+*/
+static int
+httpHdrRangeSpecCanonize(HttpHdrRangeSpec *spec, size_t clen)
+{
+    if (!known_spec(spec->offset)) /* suffix */
+       spec->offset = size_diff(clen, spec->length);
+    else
+    if (!known_spec(spec->length)) /* trailer */
+       spec->length = size_diff(clen, spec->offset);
+    /* we have a "range" now, adjust length if needed */
+    assert(known_spec(spec->length));
+    assert(known_spec(spec->offset));
+    spec->length = size_min(size_diff(clen, spec->offset), spec->length);
+    /* check range validity */
+    return spec->length > 0;
+}
+
+/*
+ * Range
+ */
+
+HttpHdrRange *
+httpHdrRangeCreate()
+{
+    HttpHdrRange *r = memAllocate(MEM_HTTP_HDR_RANGE);
+    stackInit(&r->specs);
+    return r;
+}
+
+HttpHdrRange *
+httpHdrRangeParseCreate(const char *str)
+{
+    HttpHdrRange *r = httpHdrRangeCreate();
+    if (!httpHdrRangeParseInit(r, str)) {
+       httpHdrRangeDestroy(r);
+       r = NULL;
+    }
+    return r;
+}
+
+/* returns true if ranges are valid; inits HttpHdrRange */
+int
+httpHdrRangeParseInit(HttpHdrRange *range, const char *str)
+{
+    const char *item;
+    const char *pos = NULL;
+    int ilen;
+    assert(range && str);
+    RangeParsedCount++;
+    /* iterate through comma separated list */
+    while (strListGetItem(str, ',', &item, &ilen, &pos)) {
+       HttpHdrRangeSpec *spec = httpHdrRangeSpecParseCreate(item, ilen);
+       /*
+        * HTTP/1.1 draft says we must ignore the whole header field if one spec
+        * is invalid. However, RFC 2068 just says that we must ignore that spec.
+        */
+       if (spec)
+           stackPush(&range->specs, spec);
+    }
+    return range->specs.count;
+}
+
+void
+httpHdrRangeDestroy(HttpHdrRange *range)
+{
+    assert(range);
+    while (range->specs.count)
+       httpHdrRangeSpecDestroy(stackPop(&range->specs));
+    stackClean(&range->specs);
+    memFree(MEM_HTTP_HDR_RANGE, range);
+}
+
+/*
+ * canonizes all range specs within a set preserving the order
+ * returns true if the set is valid after canonization; 
+ * the set is valid if 
+ *   - all range specs are valid and 
+ *   - there is at least one range spec
+ */
+int
+httpHdrRangeCanonize(HttpHdrRange *range, size_t clen)
+{
+    int i;
+    assert(range);
+    for (i = 0; i < range->specs.count; i++)
+        if (!httpHdrRangeSpecCanonize(range->specs.items[i], clen))
+           return 0;
+    return range->specs.count;
+}
+
+/* searches for next (unseen) range, returns true if found */
+int
+httpHdrRangeGetNext(const HttpHdrRange *range, HttpHdrRangeSpec *spec, size_t seen_len)
+{
+    int i;
+    assert(range && spec);
+    /* simple linear search */
+    for (i = 0; i < range->specs.count; i++) {
+       *spec = *(HttpHdrRangeSpec*)range->specs.items[i];
+       if (spec->offset < seen_len) {
+           assert(spec->offset + spec->length <= seen_len);
+       } else
+           return 1;
+    }
+    spec->offset = spec->length = 0;
+    return 0;
+}
index 15a6d5a85065f7ae5a7ab9213bcc8910a47998e5..15717ff69c0b7dbdfb46bf2cc1b63971066db6ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: HttpHeader.cc,v 1.16 1998/03/05 00:45:37 rousskov Exp $
+ * $Id: HttpHeader.cc,v 1.17 1998/03/05 20:55:56 rousskov Exp $
  *
  * DEBUG: section 55    HTTP Header
  * AUTHOR: Alex Rousskov
@@ -980,10 +980,7 @@ httpHeaderEntryParseByTypeInit(HttpHeaderEntry * e, int id, const HttpHeaderExtF
     httpHeaderFieldInit(&field);
     switch (type) {
     case ftInt:
-       field.v_int = atoi(f->value);
-       if (!field.v_int && !isdigit(*f->value)) {
-           debug(55, 2) ("cannot parse an int header field: id: %d, field: '%s: %s'\n",
-               id, f->name, f->value);
+       if (!httpHeaderParseInt(f->value, &field.v_int)) {
            Headers[id].stat.errCount++;
            return 0;
        }
index 7cf32c0562da87d1e00ddbcae27645aeee9cd29d..1747dd8c376351960e01bd5218a7e25a100cff58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: HttpHeaderTools.cc,v 1.1 1998/03/05 00:01:08 rousskov Exp $
+ * $Id: HttpHeaderTools.cc,v 1.2 1998/03/05 20:55:56 rousskov Exp $
  *
  * DEBUG: section 66    HTTP Header Tools
  * AUTHOR: Alex Rousskov
@@ -55,7 +55,7 @@ httpHeaderInitAttrTable(field_attrs_t * table, int count)
     for (i = 0; i < count; ++i) {
        assert(table[i].name);
        table[i].name_len = strlen(table[i].name);
-       debug(55, 5) ("hdr table entry[%d]: %s (%d)\n", i, table[i].name, table[i].name_len);
+       debug(66, 5) ("hdr table entry[%d]: %s (%d)\n", i, table[i].name, table[i].name_len);
        assert(table[i].name_len);
        /* init stats */
        memset(&table[i].stat, 0, sizeof(table[i].stat));
@@ -142,3 +142,29 @@ getStringPrefix(const char *str)
     xstrncpy(buf, str, SHORT_PREFIX_SIZE);
     return buf;
 }
+
+/*
+ * parses an int field, complains if soemthing went wrong, returns true on
+ * success
+ */
+int
+httpHeaderParseInt(const char *start, int *value)
+{
+    assert(value);
+    *value = atoi(start);
+    if (!*value && !isdigit(*start)) {
+       debug(66, 2) ("failed to parse an int header field near '%s'\n", start);
+            return 0;
+    }
+    return 1;
+}
+
+int
+httpHeaderParseSize(const char *start, size_t *value)
+{
+    int v;
+    const int res = httpHeaderParseInt(start, &v);
+    assert(value);
+    *value = res ? v : 0;
+    return res;
+}
index 8ef7e82231619e528b9e86c850063f31be92f769..b89919fe5502efce912a600d24501953fd50efca 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.in,v 1.127 1998/03/05 00:01:09 rousskov Exp $
+#  $Id: Makefile.in,v 1.128 1998/03/05 20:55:57 rousskov Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -91,6 +91,7 @@ OBJS          = \
                http-anon.o \
                HttpStatusLine.o \
                HttpHdrCc.o \
+               HttpHdrRange.o \
                HttpHeader.o \
                HttpHeaderTools.o \
                HttpBody.o \
index e27d379d3bb8f727d8e502ef299a7e00948d12e8..8d41de166959067dce28a0c26450c383221cbd0f 100644 (file)
@@ -475,6 +475,8 @@ typedef enum {
     MEM_HTTPREPLY,
 #endif
     MEM_HTTP_HDR_CC,
+    MEM_HTTP_HDR_RANGE_SPEC,
+    MEM_HTTP_HDR_RANGE,
     MEM_HTTPSTATEDATA,
     MEM_ICPUDPDATA,
     MEM_CLIENTHTTPREQUEST,
index 5c5ead0476f8d6761db7147bb339e4566a561040..4f27cf9bd15c7fabf067824891de4efb3b946953 100644 (file)
@@ -261,7 +261,6 @@ extern void httpBodyPackInto(const HttpBody * body, Packer * p);
 extern void httpHdrCcInitModule();
 extern HttpHdrCc *httpHdrCcCreate();
 extern HttpHdrCc *httpHdrCcParseCreate(const char *str);
-extern void httpHdrCcParseInit(HttpHdrCc * scc, const char *str);
 extern void httpHdrCcDestroy(HttpHdrCc * scc);
 extern HttpHdrCc *httpHdrCcDup(HttpHdrCc * scc);
 extern void httpHdrCcPackValueInto(HttpHdrCc * scc, Packer * p);
@@ -269,12 +268,22 @@ extern void httpHdrCcJoinWith(HttpHdrCc * scc, HttpHdrCc * new_scc);
 extern void httpHdrCcUpdateStats(const HttpHdrCc * scc, StatHist * hist);
 extern void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
 
+/* Http Range Header Field */
+extern HttpHdrRange *httpHdrRangeParseCreate(const char *range_spec);
+/* returns true if ranges are valid; inits HttpHdrRange */
+extern int httpHdrRangeParseInit(HttpHdrRange *range, const char *range_spec);
+extern void httpHdrRangeDestroy(HttpHdrRange *range);
+
+
+
 /* Http Header Tools */
 extern int httpHeaderIdByName(const char *name, int name_len, const field_attrs_t * attrs, int end, int mask);
 extern void httpHeaderInitAttrTable(field_attrs_t * table, int count);
 extern int httpHeaderCalcMask(const int *enums, int count);
 extern int strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos);
 extern const char *getStringPrefix(const char *str);
+extern int httpHeaderParseInt(const char *start, int *val);
+extern int httpHeaderParseSize(const char *start, size_t *sz);
 
 /* Http Header */
 extern void httpHeaderInitModule();
index 02fc5533228e5cada6b20b481f1cd8feb94b2803..2cd8d07a99b75427ccef31dcf38e1d62f354380a 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: squid.h,v 1.160 1998/02/26 22:16:31 kostas Exp $
+ * $Id: squid.h,v 1.161 1998/03/05 20:55:59 rousskov Exp $
  *
  * AUTHOR: Duane Wessels
  *
@@ -307,6 +307,8 @@ struct rusage {
 
 #include "md5.h"
 
+#include "Stack.h"
+
 #ifdef SQUID_SNMP
 #include "cache_snmp.h"
 #endif
index f4b2b55f7ec6e24af24fb05bdb1693f528000fb6..f19b938d3327da877e4a0bb424b873bd0bcd481e 100644 (file)
@@ -472,6 +472,19 @@ struct _HttpHdrCc {
     time_t max_age;
 };
 
+/* http byte-range-spec */
+struct _HttpHdrRangeSpec {
+    size_t offset;
+    size_t length;
+};
+
+/* There may be more than one byte range specified in the request.
+   This object holds all range specs in order of their appearence
+   in the request because we SHOULD preserve that order.
+*/
+struct _HttpHdrRange {
+    Stack specs;
+};
 
 /* a storage for an entry of one of possible types (for lower level routines) */
 union _field_store {
@@ -480,6 +493,7 @@ union _field_store {
     char *v_pchar;
     const char *v_pcchar;
     HttpHdrCc *v_pcc;
+    HttpHdrRange *v_prange;
     HttpHeaderExtField *v_pefield;
 };
 
index 7be1c8e1ccce606a134baf7b6b7df89431dc849a..befb8ec8b890060687aa0eb559d076e40ed9a00d 100644 (file)
@@ -53,6 +53,8 @@ typedef struct _HttpStatusLine HttpStatusLine;
 typedef struct _field_attrs_t field_attrs_t;
 typedef struct _HttpHeader HttpHeader;
 typedef struct _HttpHdrCc HttpHdrCc;
+typedef struct _HttpHdrRangeSpec HttpHdrRangeSpec;
+typedef struct _HttpHdrRange HttpHdrRange;
 typedef struct _HttpHeaderExtField HttpHeaderExtField;
 typedef struct _HttpHeaderEntry HttpHeaderEntry;
 typedef struct _HttpHeaderFieldStat HttpHeaderFieldStat;