int errorMapStart(const errormap * map, request_t * client_req, HttpReply * reply, const char *aclname, ERRMAPCB * callback, void *callback_data) { char squid_error[100]; int len = 0; const char *errorUrl; ErrorMapState *state; const char *tmp; http_status status; request_t *req; HttpHeaderPos hdrpos; HttpHeaderEntry *hdr; if (!client_req || !reply) return 0; status = reply->sline.status; tmp = httpHeaderGetStr(&reply->header, HDR_X_SQUID_ERROR); squid_error[0] = '\0'; if (tmp) { xstrncpy(squid_error, tmp, sizeof(squid_error)); len = strcspn(squid_error, " "); } squid_error[len] = '\0'; errorUrl = getErrorMap(map, status, squid_error, aclname); if (!errorUrl) return 0; req = urlParse(urlMethodGetKnownByCode(METHOD_GET), (char *) errorUrl); if (!req) { debug(0, 0) ("errorMapStart: Invalid error URL '%s'\n", errorUrl); return 0; } req->urlgroup = xstrdup("error"); state = cbdataAlloc(ErrorMapState); state->req = requestLink(req); state->e = storeCreateEntry(errorUrl, req->flags, req->method); state->sc = storeClientRegister(state->e, state); state->callback = callback; state->callback_data = callback_data; cbdataLock(callback_data); hdrpos = HttpHeaderInitPos; while ((hdr = httpHeaderGetEntry(&client_req->header, &hdrpos)) != NULL) { if (CBIT_TEST(client_headers, hdr->id)) httpHeaderAddClone(&req->header, hdr); } hdrpos = HttpHeaderInitPos; while ((hdr = httpHeaderGetEntry(&reply->header, &hdrpos)) != NULL) { if (CBIT_TEST(server_headers, hdr->id)) httpHeaderAddClone(&req->header, hdr); } httpHeaderPutInt(&req->header, HDR_X_ERROR_STATUS, (int) reply->sline.status); httpHeaderPutStr(&req->header, HDR_X_REQUEST_URI, urlCanonical(client_req)); fwdStart(-1, state->e, req); storeClientRef(state->sc, state->e, 0, 0, SM_PAGE_SIZE, errorMapFetchHeaders, state); return 1; }
/* use fresh entries to replace old ones */ void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask) { const HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; assert(old && fresh); assert(old != fresh); debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh); while ((e = httpHeaderGetEntry(fresh, &pos))) { /* deny bad guys (ok to check for HDR_OTHER) here */ if (denied_mask && CBIT_TEST(*denied_mask, e->id)) continue; if (e->id != HDR_OTHER) httpHeaderDelById(old, e->id); else httpHeaderDelByName(old, strBuf(e->name)); } pos = HttpHeaderInitPos; while ((e = httpHeaderGetEntry(fresh, &pos))) { /* deny bad guys (ok to check for HDR_OTHER) here */ if (denied_mask && CBIT_TEST(*denied_mask, e->id)) continue; httpHeaderAddClone(old, e); } /* And now, repack the array to "fill in the holes" */ httpHeaderRepack(old); }
/* return a list of entries with the same id separated by ',' and ws */ String httpHeaderGetList(const HttpHeader * hdr, http_hdr_type id) { String s = StringNull; HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; debug(55, 6) ("%p: joining for id %d\n", hdr, id); /* only fields from ListHeaders array can be "listed" */ assert(CBIT_TEST(ListHeadersMask, id)); if (!CBIT_TEST(hdr->mask, id)) return s; while ((e = httpHeaderGetEntry(hdr, &pos))) { if (e->id == id) strListAdd(&s, strBuf(e->value), ','); } /* * note: we might get an empty (len==0) string if there was an "empty" * header; we must not get a NULL string though. */ assert(strBuf(s)); /* temporary warning: remove it! @?@ @?@ @?@ */ if (!strLen(s)) debug(55, 3) ("empty list header: %s (%d)\n", strBuf(Headers[id].name), id); debug(55, 6) ("%p: joined for id %d: %s\n", hdr, id, strBuf(s)); return s; }
static const char* httpHeaderGetValue(HttpHeader *h, const char *name) { HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *curHE; while ((curHE = httpHeaderGetEntry(h, &pos))) { if(!strcasecmp(strBuf(curHE->name), name)) { return strBuf(curHE->value); } } return NULL; }
/* packs all the entries using supplied packer */ void httpHeaderPackInto(const HttpHeader * hdr, Packer * p) { HttpHeaderPos pos = HttpHeaderInitPos; const HttpHeaderEntry *e; assert(hdr && p); debug(55, 7) ("packing hdr: (%p)\n", hdr); /* pack all entries one by one */ while ((e = httpHeaderGetEntry(hdr, &pos))) httpHeaderEntryPackInto(e, p); }
/* * Refreshes the header mask. Useful after httpHeaderDelAt constructs */ void httpHeaderRefreshMask(HttpHeader * hdr) { HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; httpHeaderMaskInit(&hdr->mask, 0); debug(55, 7) ("refreshing the mask in hdr %p\n", hdr); while ((e = httpHeaderGetEntry(hdr, &pos))) { CBIT_SET(hdr->mask, e->id); } }
/* append entries (also see httpHeaderUpdate) */ void httpHeaderAppend(HttpHeader * dest, const HttpHeader * src) { const HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; assert(src && dest); assert(src != dest); debug(55, 7) ("appending hdr: %p += %p\n", dest, src); while ((e = httpHeaderGetEntry(src, &pos))) { httpHeaderAddEntry(dest, httpHeaderEntryClone(e)); } }
/* Mangles headers for a list of headers. */ void httpHdrMangleList(HttpHeader * l, request_t * request) { HttpHeaderEntry *e; HttpHeaderPos p = HttpHeaderInitPos; int removed_headers = 0; while ((e = httpHeaderGetEntry(l, &p))) { if (0 == httpHdrMangle(e, request)) { httpHeaderDelAt(l, p); removed_headers++; } } if (removed_headers) httpHeaderRefreshMask(l); }
/* *This line is to modify the header */ static int mod_modify_s2o_header(HttpStateData* data, HttpHeader* hdr) { assert(data); int fd = data->fd; int i, len; struct mod_conf_param *param = (struct mod_conf_param *)cc_get_mod_param(fd, mod); assert(param); debug(107, 3)("param->orig_name=%s, param->new_name=%s\n", strBuf(param->orig_name), strBuf(param->new_name)); HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *myheader; HttpHeaderEntry e; while ((myheader = httpHeaderGetEntry(hdr, &pos))) { debug(107, 3)("myheader=%s, param->new_name=%s\n", strBuf(myheader->name), strBuf(param->new_name)); if (strCaseCmp(myheader->name, strBuf(param->orig_name)) == 0) { debug(107, 3)("%s is myheader->value,%s is param->orig_name\n",strBuf(myheader->value), strBuf(param->orig_name)); if(strLen(myheader->value) >= 4095) { debug(107, 3)("A too long header value!!\n"); return -1; } stringInit(&e.name, strBuf(param->new_name)); stringInit(&e.value, myheader->value.buf); len=strlen(strBuf(e.name)); i=httpHeaderIdByNameDef(strBuf(e.name), len); if(-1 == i) e.id = HDR_OTHER; else e.id = i; httpHeaderDelByName(hdr, strBuf(param->orig_name)); httpHeaderAddEntry(hdr, httpHeaderEntryClone(&e)); //httpHeaderDelAt(&request->header, pos); //httpHeaderRefreshMask(&request->header); //httpHeaderInsertEntry(&request->header, httpHeaderEntryClone(&e), pos); stringClean(&e.name); stringClean(&e.value); break; } } return 0; }
/* * deletes all fields with a given name if any, returns #fields deleted; */ int httpHeaderDelByName(HttpHeader * hdr, const char *name) { int count = 0; HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; httpHeaderMaskInit(&hdr->mask, 0); /* temporal inconsistency */ debug(55, 7) ("deleting '%s' fields in hdr %p\n", name, hdr); while ((e = httpHeaderGetEntry(hdr, &pos))) { if (!strCaseCmp(e->name, name)) { httpHeaderDelAt(hdr, pos); count++; } else CBIT_SET(hdr->mask, e->id); } return count; }
/* use fresh entries to replace old ones */ void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask) { const HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; assert(old && fresh); assert(old != fresh); debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh); while ((e = httpHeaderGetEntry(fresh, &pos))) { /* deny bad guys (ok to check for HDR_OTHER) here */ if (denied_mask && CBIT_TEST(*denied_mask, e->id)) continue; httpHeaderDelByName(old, strBuf(e->name)); httpHeaderAddEntry(old, httpHeaderEntryClone(e)); } }
/* * 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; }
/* * 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 */ }
/* 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; }
void httpHeaderClean(HttpHeader * hdr) { HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; assert(hdr); assert(hdr->owner > hoNone && hdr->owner <= hoReply); debug(55, 7) ("cleaning hdr: %p owner: %d\n", hdr, hdr->owner); /* * An unfortunate bug. The hdr->entries array is initialized * such that count is set to zero. httpHeaderClean() seems to * be called both when 'hdr' is created, and destroyed. Thus, * we accumulate a large number of zero counts for 'hdr' before * it is ever used. Can't think of a good way to fix it, except * adding a state variable that indicates whether or not 'hdr' * has been used. As a hack, just never count zero-sized header * arrays. */ if (0 != hdr->entries.count) statHistCount(&HttpHeaderStats[hdr->owner].hdrUCountDistr, hdr->entries.count); HttpHeaderStats[hdr->owner].destroyedCount++; HttpHeaderStats[hdr->owner].busyDestroyedCount += hdr->entries.count > 0; while ((e = httpHeaderGetEntry(hdr, &pos))) { /* tmp hack to try to avoid coredumps */ if (e->id >= HDR_ENUM_END) { debug(55, 0) ("httpHeaderClean BUG: entry[%d] is invalid (%d). Ignored.\n", (int) pos, e->id); } else { statHistCount(&HttpHeaderStats[hdr->owner].fieldTypeDistr, e->id); /* yes, this destroy() leaves us in an inconsistent state */ httpHeaderEntryDestroy(e); } } arrayClean(&hdr->entries); }
/* * Returns the value of the specified header. */ String httpHeaderGetByName(const HttpHeader * hdr, const char *name) { http_hdr_type id; HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; String result = StringNull; assert(hdr); assert(name); /* First try the quick path */ id = httpHeaderIdByNameDef(name, strlen(name)); if (id != -1) return httpHeaderGetStrOrList(hdr, id); /* Sorry, an unknown header name. Do linear search */ while ((e = httpHeaderGetEntry(hdr, &pos))) { if (e->id == HDR_OTHER && strCaseCmp(e->name, name) == 0) { strListAdd(&result, strBuf(e->value), ','); } } return result; }