void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type id, time_t htime) { assert_eid(id); assert(Headers[id].type == ftDate_1123); /* must be of an appropriate type */ assert(htime >= 0); httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, mkrfc1123(htime))); }
void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type id, const char *str) { assert_eid(id); assert(Headers[id].type == ftStr); /* must be of an appropriate type */ assert(str); httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, str)); }
void httpHeaderPutInt(HttpHeader * hdr, http_hdr_type id, int number) { assert_eid(id); assert(Headers[id].type == ftInt); /* must be of an appropriate type */ assert(number >= 0); httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, xitoa(number))); }
/* test if a field is present */ int httpHeaderHas(const HttpHeader * hdr, http_hdr_type id) { assert(hdr); assert_eid(id); assert(id != HDR_OTHER); debug(55, 7) ("%p lookup for %d\n", hdr, id); return CBIT_TEST(hdr->mask, id); }
void httpHeaderPutSize(HttpHeader * hdr, http_hdr_type id, squid_off_t number) { char size[64]; assert_eid(id); assert(Headers[id].type == ftSize); /* must be of an appropriate type */ assert(number >= 0); snprintf(size, sizeof(size), "%" PRINTF_OFF_T, number); httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, size)); }
/* parses and inits header entry, returns new entry on success */ static HttpHeaderEntry * httpHeaderEntryParseCreate(const char *field_start, const char *field_end) { HttpHeaderEntry *e; int id; /* note: name_start == field_start */ const char *name_end = strchr(field_start, ':'); const int name_len = name_end ? name_end - field_start : 0; const char *value_start = field_start + name_len + 1; /* skip ':' */ /* note: value_end == field_end */ HeaderEntryParsedCount++; /* do we have a valid field name within this field? */ if (!name_len || name_end > field_end) return NULL; if (name_len > 65536) { /* String has a 64K limit */ debug(55, 1) ("WARNING: ignoring header name of %d bytes\n", name_len); return NULL; } /* now we know we can parse it */ e = memAllocate(MEM_HTTP_HDR_ENTRY); debug(55, 9) ("creating entry %p: near '%s'\n", e, getStringPrefix(field_start, field_end)); /* is it a "known" field? */ id = httpHeaderIdByName(field_start, name_len, Headers, HDR_ENUM_END); if (id < 0) id = HDR_OTHER; assert_eid(id); e->id = id; /* set field name */ if (id == HDR_OTHER) stringLimitInit(&e->name, field_start, name_len); else e->name = Headers[id].name; /* trim field value */ while (value_start < field_end && xisspace(*value_start)) value_start++; if (field_end - value_start > 65536) { /* String has a 64K limit */ debug(55, 1) ("WARNING: ignoring '%s' header of %d bytes\n", strBuf(e->name), (int) (field_end - value_start)); if (e->id == HDR_OTHER) stringClean(&e->name); memFree(e, MEM_HTTP_HDR_ENTRY); return NULL; } /* set field value */ stringLimitInit(&e->value, value_start, field_end - value_start); Headers[id].stat.seenCount++; Headers[id].stat.aliveCount++; debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); return e; }
/* unusual */ const char * httpHeaderGetLastStr(const HttpHeader * hdr, http_hdr_type id) { HttpHeaderEntry *e; assert_eid(id); assert(Headers[id].type == ftStr); /* must be of an appropriate type */ if ((e = httpHeaderFindLastEntry(hdr, id))) { httpHeaderNoteParsedEntry(e->id, e->value, 0); /* no errors are possible */ return strBuf(e->value); } return NULL; }
time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id) { HttpHeaderEntry *e; time_t value = -1; assert_eid(id); assert(Headers[id].type == ftDate_1123); /* must be of an appropriate type */ if ((e = httpHeaderFindEntry(hdr, id))) { value = parse_rfc1123(strBuf(e->value)); httpHeaderNoteParsedEntry(e->id, e->value, value < 0); } return value; }
int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id) { HttpHeaderEntry *e; int value = -1; int ok; assert_eid(id); assert(Headers[id].type == ftInt); /* must be of an appropriate type */ if ((e = httpHeaderFindEntry(hdr, id))) { ok = httpHeaderParseInt(strBuf(e->value), &value); httpHeaderNoteParsedEntry(e->id, e->value, !ok); } return value; }
static void httpHeaderEntryDestroy(HttpHeaderEntry * e) { assert(e); assert_eid(e->id); debug(55, 9) ("destroying entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); /* clean name if needed */ if (e->id == HDR_OTHER) stringClean(&e->name); stringClean(&e->value); assert(Headers[e->id].stat.aliveCount); Headers[e->id].stat.aliveCount--; e->id = -1; memFree(e, MEM_HTTP_HDR_ENTRY); }
static HttpHeaderEntry * httpHeaderEntryCreate(http_hdr_type id, const char *name, const char *value) { HttpHeaderEntry *e; assert_eid(id); e = memAllocate(MEM_HTTP_HDR_ENTRY); e->id = id; if (id != HDR_OTHER) e->name = Headers[id].name; else stringInit(&e->name, name); stringInit(&e->value, value); Headers[id].stat.aliveCount++; debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); return e; }
/* appends an entry; * does not call httpHeaderEntryClone() so one should not reuse "*e" */ void httpHeaderAddEntry(HttpHeader * hdr, HttpHeaderEntry * e) { assert(hdr && e); assert_eid(e->id); debug(55, 7) ("%p adding entry: %d at %d\n", hdr, e->id, hdr->entries.count); if (CBIT_TEST(hdr->mask, e->id)) Headers[e->id].stat.repCount++; else CBIT_SET(hdr->mask, e->id); arrayAppend(&hdr->entries, e); /* increment header length, allow for ": " and crlf */ hdr->len += strLen(e->name) + 2 + strLen(e->value) + 2; }
/* * returns a pointer to a specified entry if any * note that we return one entry so it does not make much sense to ask for * "list" headers */ HttpHeaderEntry * httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id) { HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; assert(hdr); assert_eid(id); assert(!CBIT_TEST(ListHeadersMask, id)); /* check mask first */ if (!CBIT_TEST(hdr->mask, id)) return NULL; /* looks like we must have it, do linear search */ while ((e = httpHeaderGetEntry(hdr, &pos))) { if (e->id == id) return e; } /* hm.. we thought it was there, but it was not found */ assert(0); return NULL; /* not reached */ }
/* * same as httpHeaderFindEntry */ static HttpHeaderEntry * httpHeaderFindLastEntry(const HttpHeader * hdr, http_hdr_type id) { HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; HttpHeaderEntry *result = NULL; assert(hdr); assert_eid(id); assert(!CBIT_TEST(ListHeadersMask, id)); /* check mask first */ if (!CBIT_TEST(hdr->mask, id)) return NULL; /* looks like we must have it, do linear search */ while ((e = httpHeaderGetEntry(hdr, &pos))) { if (e->id == id) result = e; } assert(result); /* must be there! */ return result; }
/* deletes all entries with a given id, returns the #entries deleted */ int httpHeaderDelById(HttpHeader * hdr, http_hdr_type id) { int count = 0; HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; debug(55, 8) ("%p del-by-id %d\n", hdr, id); assert(hdr); assert_eid(id); assert(id != HDR_OTHER); /* does not make sense */ if (!CBIT_TEST(hdr->mask, id)) return 0; while ((e = httpHeaderGetEntry(hdr, &pos))) { if (e->id == id) { httpHeaderDelAt(hdr, pos); count++; } } CBIT_CLR(hdr->mask, id); assert(count); return count; }
/* * returns a the value of the specified list member, if any. */ String httpHeaderGetListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator) { String result = StringNull; String header; const char *pos = NULL; const char *item; int ilen; int mlen = strlen(member); assert(hdr); assert_eid(id); header = httpHeaderGetStrOrList(hdr, id); while (strListGetItem(&header, separator, &item, &ilen, &pos)) { if (strncmp(item, member, mlen) == 0 && item[mlen] == '=') { stringAppend(&result, item + mlen + 1, ilen - mlen - 1); break; } } stringClean(&header); return result; }
/* parses and inits header entry, returns new entry on success */ static HttpHeaderEntry * httpHeaderEntryParseCreate(const char *field_start, const char *field_end) { HttpHeaderEntry *e; int id; /* note: name_start == field_start */ const char *name_end = memchr(field_start, ':', field_end - field_start); int name_len = name_end ? name_end - field_start : 0; const char *value_start = field_start + name_len + 1; /* skip ':' */ /* note: value_end == field_end */ HeaderEntryParsedCount++; /* do we have a valid field name within this field? */ if (!name_len || name_end > field_end) return NULL; if (name_len > 65534) { /* String must be LESS THAN 64K and it adds a terminating NULL */ debug(55, 1) ("WARNING: ignoring header name of %d bytes\n", name_len); return NULL; } if (Config.onoff.relaxed_header_parser && xisspace(field_start[name_len - 1])) { debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2) ("NOTICE: Whitespace after header name in '%s'\n", getStringPrefix(field_start, field_end)); while (name_len > 0 && xisspace(field_start[name_len - 1])) name_len--; if (!name_len) return NULL; } /* now we know we can parse it */ e = memAllocate(MEM_HTTP_HDR_ENTRY); debug(55, 9) ("creating entry %p: near '%s'\n", e, getStringPrefix(field_start, field_end)); /* is it a "known" field? */ id = httpHeaderIdByName(field_start, name_len, Headers, HDR_ENUM_END); if (id < 0) id = HDR_OTHER; assert_eid(id); e->id = id; /* set field name */ if (id == HDR_OTHER) stringLimitInit(&e->name, field_start, name_len); else e->name = Headers[id].name; /* trim field value */ while (value_start < field_end && xisspace(*value_start)) value_start++; while (value_start < field_end && xisspace(field_end[-1])) field_end--; if (field_end - value_start > 65534) { /* String must be LESS THAN 64K and it adds a terminating NULL */ debug(55, 1) ("WARNING: ignoring '%s' header of %d bytes\n", strBuf(e->name), (int) (field_end - value_start)); if (e->id == HDR_OTHER) stringClean(&e->name); memFree(e, MEM_HTTP_HDR_ENTRY); return NULL; } /* set field value */ stringLimitInit(&e->value, value_start, field_end - value_start); Headers[id].stat.seenCount++; Headers[id].stat.aliveCount++; debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); return e; }