--------------------- PatchSet 1406 Date: 2001/01/28 10:37:35 Author: rbcollins Branch: rbcollins_filters Tag: (none) Log: content filter framework shaping up: modular framework shaping up Members: src/client_side.c:1.1.1.3.4.1.4.15.2.3->1.1.1.3.4.1.4.15.2.4 Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.1.1.3.4.1.4.15.2.3 retrieving revision 1.1.1.3.4.1.4.15.2.4 diff -u -r1.1.1.3.4.1.4.15.2.3 -r1.1.1.3.4.1.4.15.2.4 --- squid/src/client_side.c 27 Jan 2001 02:38:58 -0000 1.1.1.3.4.1.4.15.2.3 +++ squid/src/client_side.c 28 Jan 2001 10:37:35 -0000 1.1.1.3.4.1.4.15.2.4 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.3 2001/01/27 02:38:58 rbcollins Exp $ + * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.4 2001/01/28 10:37:35 rbcollins Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -1154,6 +1154,8 @@ return clen; } +static DATAFILTER clientDoRangeReply; + /* adds appropriate Range headers if needed */ static void clientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep) @@ -1189,6 +1191,7 @@ } else { const int spec_count = http->request->range->specs.count; int actual_clen = -1; + FILTER_list *temp_filter; debug(33, 3) ("clientBuildRangeHeader: range spec count: %d virgin clen: %d\n", spec_count, rep->content_length); @@ -1224,6 +1227,16 @@ httpHeaderDelById(hdr, HDR_CONTENT_LENGTH); httpHeaderPutInt(hdr, HDR_CONTENT_LENGTH, actual_clen); debug(33, 3) ("clientBuildRangeHeader: actual content length: %d\n", actual_clen); + + /* replace the status line */ + httpStatusLineSet(&rep->sline, rep->sline.version, HTTP_PARTIAL_CONTENT, NULL); + + /* add the ranges filter to the list */ + temp_filter=xmalloc(sizeof(FILTER_list)); + temp_filter->filter=clientDoRangeReply; + temp_filter->data=http; + /* cbDataLock(http); ? */ + dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); } } @@ -1264,6 +1277,72 @@ #define TE_BUFFERING_OUTPUT 0x08 #endif + +static DATAFILTER clientDoTEReply; +static DATAFILTER clientWriteReplyHeaders; +static DATAFILTER clientFilterOnUnload; +static DATAFILTER clientDoCommWriteMemBuf; + +void +clientTEReplyheader(clientHttpRequest * http, HttpReply * rep) { + HttpHeader *hdr = &rep->header; + int y, may_apply_tes; + const char *s_ct; + String s_ce; + FILTER_list *temp_filter; + + /* begin list of modules here */ + may_apply_tes = 0; + + if (httpHeaderHas(hdr, HDR_CONTENT_TYPE)) { + s_ct = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE); + y = strlen(s_ct); + /* TODO: allow an acl for encoding by content-type */ + if (((y >= 5) && !strncasecmp(s_ct, "text/", 5)) + || strstr(s_ct, "postscript")) { + may_apply_tes = 1; + debug(33, 8) ("Content-Type of Application: %s\n", s_ct); + } + } + if (httpHeaderHas(hdr, HDR_CONTENT_ENCODING)) { + /* TODO: check logic here & make this an acl test */ + /* oh, base entity might be compressed.. don't want + * to double *that* */ + s_ce = httpHeaderGetList(hdr, HDR_CONTENT_ENCODING); + if ((strListIsMember(&s_ce, "gzip", ',')) || + (strListIsMember(&s_ce, "deflate", ',')) || + (strListIsMember(&s_ce, "x-deflate", ',')) || + (strListIsMember(&s_ce, "x-gzip", ',')) || + (strListIsMember(&s_ce, "x-compress", ',')) || + (strListIsMember(&s_ce, "compress", ','))) + may_apply_tes |= 0x02; /* 02 is the compress exception */ + stringClean(&s_ce); + } + + te_build_encode_xlate_list(&http->request->header, hdr, &http->te_translations, http->request->http_ver, &http->request->flags); + + /* add the filter to the request chain */ + if (http->request->flags.te_encoding) { + /* handle TE */ + temp_filter=xmalloc(sizeof(FILTER_list)); + temp_filter->filter=clientDoTEReply; + temp_filter->data=http; + /* cbDataLock(http); ? */ + dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); + } + +} + +void +clientFilterOnUnload_Add(clientHttpRequest * http, HttpReply * rep) { + FILTER_list *temp_filter; + temp_filter=xmalloc(sizeof(FILTER_list)); + temp_filter->filter=clientFilterOnUnload; + temp_filter->data=NULL; + /* cbDataLock(http); ? */ + dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); +} + /* * filters out unwanted entries from original reply header * adds extra entries if we have more info than origin server @@ -1275,13 +1354,15 @@ HttpHeader *hdr = &rep->header; int is_hit = isTcpHit(http->log_type); request_t *request = http->request; - String s_transfer_encoding, s_te, s_ce; - int y, may_apply_tes; - HttpHeader *ohdr; - const char *s_ct; - char added_te = 0; + FILTER_list *temp_filter; + + /* add the header check & forward filter */ + temp_filter=xmalloc(sizeof(FILTER_list)); + temp_filter->filter=clientWriteReplyHeaders; + temp_filter->data=http; + /* cbDataLock(http); ? */ + dlinkAdd(temp_filter, &temp_filter->node, &http->repfilters); - ohdr = &request->header; #if DONT_FILTER_THESE /* but you might want to if you run Squid as an HTTP accelerator */ @@ -1294,39 +1375,10 @@ /* remove Set-Cookie if a hit */ if (is_hit) httpHeaderDelById(hdr, HDR_SET_COOKIE); - may_apply_tes = 0; - - if (httpHeaderHas(hdr, HDR_CONTENT_TYPE)) { - s_ct = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE); - y = strlen(s_ct); - /* TODO: allow an acl for encoding by content-type */ - if (((y >= 5) && !strncasecmp(s_ct, "text/", 5)) - || strstr(s_ct, "postscript")) { - may_apply_tes = 1; - debug(33, 8) ("Content-Type of Application: %s\n", s_ct); - } - } - if (httpHeaderHas(hdr, HDR_CONTENT_ENCODING)) { - /* TODO: check logic here & make this an acl test */ - /* oh, base entity might be compressed.. don't want - * to double *that* */ - s_ce = httpHeaderGetList(hdr, HDR_CONTENT_ENCODING); - if ((strListIsMember(&s_ce, "gzip", ',')) || - (strListIsMember(&s_ce, "deflate", ',')) || - (strListIsMember(&s_ce, "x-deflate", ',')) || - (strListIsMember(&s_ce, "x-gzip", ',')) || - (strListIsMember(&s_ce, "x-compress", ',')) || - (strListIsMember(&s_ce, "compress", ','))) - may_apply_tes |= 0x02; /* 02 is the compress exception */ - stringClean(&s_ce); - } -/* we see this here in hdr, because WE JUST REPARSE THE HEADERS ?!?! - te_build_decode_xlate_list(hdr, &http->te_translations); - - - we should be handling the connection semantics in http.c -*/ + /* http.c currently does _not_ clean the headers properly before they + * hit the store. Clean them here before we process our downstream layout + */ /* handle Connection header */ if (httpHeaderHas(hdr, HDR_CONNECTION)) { @@ -1352,35 +1404,23 @@ } - te_build_encode_xlate_list(ohdr, hdr, &http->te_translations, request->http_ver, &request->flags); + /* the following should happen: + + if (NB Acl check) + filterRequestAdd(); -#if wrong_order - /* handle Connection header */ - if (httpHeaderHas(hdr, HDR_CONNECTION)) { - /* anything that matches Connection list member will be deleted */ - String strConnection = httpHeaderGetList(hdr, HDR_CONNECTION); - const HttpHeaderEntry *e; - HttpHeaderPos pos = HttpHeaderInitPos; - /* - * think: on-average-best nesting of the two loops (hdrEntry - * and strListItem) @?@ - */ - /* - * maybe we should delete standard stuff ("keep-alive","close") - * from strConnection first? - */ - while ((e = httpHeaderGetEntry(hdr, &pos))) { + */ + /* body based filters: */ + + clientFilterOnUnload_Add(http, rep); - if (strListIsMember(&strConnection, strBuf(e->name), ',')) - httpHeaderDelAt(hdr, pos); - } - httpHeaderDelById(hdr, HDR_CONNECTION); - stringClean(&strConnection); - } -#endif /* Handle Ranges */ if (request->range) clientBuildRangeHeader(http, rep); + + /* handle TE */ + clientTEReplyheader(http,rep); + /* * Add a estimated Age header on cache hits. */ @@ -1453,6 +1493,7 @@ clientBuildReply(clientHttpRequest * http, const char *buf, size_t size) { HttpReply *rep = httpReplyCreate(); + FILTER_list *temp_filter; /* why are we parsing this again ? */ /* we should be given a oldreply with the upstream headers already parsed, * connection header processed, etc etc */ @@ -1460,12 +1501,14 @@ if (k && httpReplyParse(rep, buf, k)) { /* enforce 1.0 reply version */ httpBuildVersion(&rep->sline.version, 1, 1); - /* do header conversions */ + /* build reply header & install filters */ clientBuildReplyHeader(http, rep); - /* if we do ranges, change status to "Partial Content" */ - if (http->request->range) - httpStatusLineSet(&rep->sline, rep->sline.version, - HTTP_PARTIAL_CONTENT, NULL); + /* add the terminating filter */ + temp_filter=xmalloc(sizeof(FILTER_list)); + temp_filter->filter=clientDoCommWriteMemBuf; + temp_filter->data=http; + /* cbDataLock(http); ? */ + dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); } else { /* parsing failure, get rid of the invalid reply */ httpReplyDestroy(rep); @@ -1949,7 +1992,6 @@ static void clientDoCommWriteMemBuf(const char *buf, size_t len, dlink_list *filter_list, FILTER_list *filters, unsigned int flags, void *data) { clientHttpRequest *http = data; - FILTER_list *temp_filter; MemBuf mb; memBufDefInit(&mb); @@ -2009,10 +2051,9 @@ static void clientFilterOnUnload(const char *buf, size_t len, dlink_list *filter_list, FILTER_list *filters, unsigned int flags, void *data) { #define pattern "onunload.*\".*\"" - clientHttpRequest *http = data; FILTER_list *temp_filter; - char *pos, *chr,*startpos, searchstring[]="onunload"; - regex_t comp; + char *chr, searchstring[]="onunload"; + const char *startpos,*pos; /* this looks for browser DOM handlers of the type onunload="..." and * removes them from the data passed to the client @@ -2088,9 +2129,10 @@ } #endif + /* * accepts chunk of a http message in buf, parses prefix, filters headers and - * such, writes processed message to the client's socket + * such, calls filter init routines, and then calls the filters. */ static void clientSendMoreData(void *data, char *buf, ssize_t size) @@ -2129,20 +2171,30 @@ /* call clientWriteComplete so the client socket gets closed */ /* broken for TE - we can simply send a chunk-length of 0, and * a trailer error (I think). */ + + /* TODO borken for filters too. call the filter chain with NULL, and + * FILTER_READ_ERROR + */ clientWriteComplete(fd, NULL, 0, COMM_OK, http); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (size < 0) { /* call clientWriteComplete so the client socket gets closed */ + /* TODO as above */ clientWriteComplete(fd, NULL, 0, COMM_OK, http); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (size == 0) { - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); + if (http->repfilters.head != NULL) { + FILTER_list *temp_filter; + temp_filter=http->repfilters.head->data; + temp_filter->filter(NULL, 0, &http->repfilters, temp_filter, 0, temp_filter->data); + } else + clientWriteComplete(fd, NULL, 0, COMM_OK, http); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } + /* test if we have actually receieved the full headers yet */ if (http->out.offset == 0) { FILTER_list *temp_filter; if (Config.onoff.log_mime_hdrs) { @@ -2186,23 +2238,6 @@ return; } /* setup reply filters */ - /* the first reply filter handles writing the headers - it removes itself from - * the list as a trivial optimisation once that is complete - */ - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientWriteReplyHeaders; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAdd(temp_filter, &temp_filter->node, &http->repfilters); -#if TESTFILTER - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientFilterOnUnload; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); -#endif - - #if 0 /* this can't be done until the process for locking/freeing buffers * is looked into @@ -2217,31 +2252,6 @@ dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); } else #endif - { - /* there is some complicating factor: ranges/transfer encoding */ - if (http->request->range) { - /* handle the range packing stuff */ - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientDoRangeReply; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); - } - if (http->request->flags.te_encoding) { - /* handle the range packing stuff */ - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientDoTEReply; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); - } - /* handle the range packing stuff */ - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientDoCommWriteMemBuf; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); - } /* reset range iterator */ http->range_iter.pos = HttpHdrRangeInitPos; @@ -2277,9 +2287,7 @@ /* init mb; put status line and headers if any */ /* rep is only created when out offset ==0 */ mb = httpReplyPack(rep); - /* this is updated by the write function (it adds mb.size). */ - /* issue 2: the offset should be altered _before_ te size comes into effect - * it's actually the seek position in the input data stream */ + /* offset is actually the seek position in the input data stream */ http->out.offset = rep->hdr_sz; check_size += rep->hdr_sz; #if HEADERS_LOG @@ -2302,7 +2310,6 @@ * so end clients that don't support TE aren't performance affected * For now, because I'm lazy, I'm just disabling this */ - #if hardtodowithfilters_butfilterswhenshortcuttingshouldbethesame } else if (!http->request->range && !(http->request->flags.te_encoding)) { /* Avoid copying to MemBuf for non-range requests */