From: rousskov <> Date: Fri, 6 Mar 1998 03:55:55 +0000 (+0000) Subject: - Added HttpHdrRange; the code is not yet tested and not used by other X-Git-Tag: SQUID_3_0_PRE1~3907 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5107edb27b3fb36a26c7bf675a401dfdef1b1ca;p=thirdparty%2Fsquid.git - Added HttpHdrRange; the code is not yet tested and not used by other commited modules. --- diff --git a/src/HttpHdrCc.cc b/src/HttpHdrCc.cc index d5333a7444..5181f37962 100644 --- a/src/HttpHdrCc.cc +++ b/src/HttpHdrCc.cc @@ -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 index 0000000000..36a9054728 --- /dev/null +++ b/src/HttpHdrRange.cc @@ -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; +} diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index 15a6d5a850..15717ff69c 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -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; } diff --git a/src/HttpHeaderTools.cc b/src/HttpHeaderTools.cc index 7cf32c0562..1747dd8c37 100644 --- a/src/HttpHeaderTools.cc +++ b/src/HttpHeaderTools.cc @@ -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; +} diff --git a/src/Makefile.in b/src/Makefile.in index 8ef7e82231..b89919fe55 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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 \ diff --git a/src/enums.h b/src/enums.h index e27d379d3b..8d41de1669 100644 --- a/src/enums.h +++ b/src/enums.h @@ -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, diff --git a/src/protos.h b/src/protos.h index 5c5ead0476..4f27cf9bd1 100644 --- a/src/protos.h +++ b/src/protos.h @@ -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(); diff --git a/src/squid.h b/src/squid.h index 02fc553322..2cd8d07a99 100644 --- a/src/squid.h +++ b/src/squid.h @@ -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 diff --git a/src/structs.h b/src/structs.h index f4b2b55f7e..f19b938d33 100644 --- a/src/structs.h +++ b/src/structs.h @@ -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; }; diff --git a/src/typedefs.h b/src/typedefs.h index 7be1c8e1cc..befb8ec8b8 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -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;