--------------------- PatchSet 4798 Date: 2002/08/28 02:31:44 Author: rbcollins Branch: esi Tag: (none) Log: correct a reentrancy issue on hits with expat Members: src/ESI.c:1.1.2.30->1.1.2.31 src/clientStream.c:1.1.2.5->1.1.2.6 Index: squid/src/ESI.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/ESI.c,v retrieving revision 1.1.2.30 retrieving revision 1.1.2.31 diff -u -r1.1.2.30 -r1.1.2.31 --- squid/src/ESI.c 26 Aug 2002 13:20:36 -0000 1.1.2.30 +++ squid/src/ESI.c 28 Aug 2002 02:31:44 -0000 1.1.2.31 @@ -1,6 +1,6 @@ /* - * $Id: ESI.c,v 1.1.2.30 2002/08/26 13:20:36 rbcollins Exp $ + * $Id: ESI.c,v 1.1.2.31 2002/08/28 02:31:44 rbcollins Exp $ * * DEBUG: section 86 ESI processing * AUTHOR: Robert Collins @@ -368,7 +368,8 @@ int finishedtemplate:1; /* we've read the entire template */ int parserinited:1; int clientwantsdata:1; /* we need to satisfy a read request */ - int kicked:1; /* don't reenter the kick routine */ + int kicked:1; /* note on reentering the kick routine */ + int parsing:1; /* libexpat is not reentrant on the same context */ } flags; err_type errorpage; /* if we error what page to use */ http_status errorstatus; /* if we error, what code to return */ @@ -455,7 +456,7 @@ case ESI_PROCESS_PENDING_MAYFAIL: debug (86,5)("esiKick: esiProcess PENDING UNKNOWN\n");break; case ESI_PROCESS_FAILED: - debug (86,0)("esiKick: esiProcess FAILED\n"); + debug (86,0)("esiKick: esiProcess %p FAILED\n", context); /* this can not happen - processing can't fail until we have data, * and when we come here we have sent data to the client */ @@ -636,9 +637,11 @@ /* Yes! Send it without asking for more upstream */ /* memcopying because the client provided the buffer */ /* TODO: skip data until pos == next->readoff; */ - clientStreamNode *next = this->node.next->data; + clientStreamNode *next; size_t len = 0; HttpReply *rep; + assert (this->data == context); + next = this->node.next->data; cbdataReference (context); if (context->outbound) len = next->readlen < (context->outbound->len - context->outbound_offset) ? @@ -671,7 +674,7 @@ /* Deal with re-entrancy */ rep = context->rep; context->rep = NULL; /* freed downstream */ - if (rep) + if (rep && context->varState) esiVarBuildVary (context->varState, rep); clientStreamCallback (this, http, rep, next->readbuf, len); if (len == 0) @@ -728,6 +731,7 @@ clientStreamCallback (this, http, rep, body_data, body_size); return; } + debug (86, 3)("esiProcessStream: Processing this %p context %p\n",this, context); /* once we finish the template, we *cannot* return here */ assert (!context->flags.finishedtemplate); @@ -783,7 +787,7 @@ if (rep == NULL && body_data == NULL && body_size == 0 && !context->flags.finishedtemplate) { /* TODO: get stream status to test the entry for aborts */ /* else flush the esi processor */ - debug (86,5)("Finished reading upstream data\n"); + debug (86,5)("esiProcess: %p Finished reading upstream data\n", context); /* This is correct */ context->flags.finishedtemplate = 1; } @@ -854,6 +858,7 @@ rv->varState = esiVarStateNew (&http->request->header, http->uri); debug (86,5)("esiContextNew: Client wants data (always created during reply cycle\n"); } + debug (86,5)("esiContextNew: Create context %p\n",rv); return rv; } @@ -1142,6 +1147,10 @@ * when it's found, hand an esiLiteral of the preceeding data to our current * context */ + if (context->flags.parsing) { + /* in middle of parsing - finish here */ + return ESI_PROCESS_PENDING_MAYFAIL; + } assert (context->flags.finished == 0); @@ -1164,6 +1173,7 @@ /* we have data */ if (context->buffered) { + context->flags.parsing = 1; /* we don't keep any data around */ while (context->buffered) { @@ -1194,6 +1204,7 @@ } /* Tel the read code to allocate a new buffer */ context->incoming = NULL; + context->flags.parsing = 0; } /* ok, we've done all we can with the data. What can we process now? @@ -1208,7 +1219,7 @@ debug (86,5)("esiProcess: tree Processed PENDING OK\n"); break; case ESI_PROCESS_PENDING_MAYFAIL: - debug (86,5)("eseProcess: tree Processed PENDING UNKNOWN\n"); + debug (86,5)("esiProcess: tree Processed PENDING UNKNOWN\n"); break; case ESI_PROCESS_FAILED: debug (86,0)("esiProcess: tree Processed FAILED\n"); @@ -1233,13 +1244,14 @@ context->flags.finished = 1; } - } + - if (!context->flags.finishedtemplate && !context->incoming) { + if (!context->flags.finishedtemplate && !context->incoming) { context->incoming = context->buffered = cbdataAlloc (esiSegment); - } + } - return ESI_PROCESS_COMPLETE; /* because we have no callbacks */ + return status; /* because we have no callbacks */ + } } /* esiSegment */ @@ -1428,6 +1440,7 @@ if (rep->sline.status != HTTP_OK) { httpReplyDestroy(rep); rep = NULL; + assert (cbdataReferenceValid (esiStream->include)); esiIncludeSubRequestDone (esiStream->include, esiStream, 0); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1464,6 +1477,7 @@ if (rep == NULL && body_data == NULL && body_size == 0) { /* TODO: get stream status to test the entry for aborts */ debug (86,5)("Finished reading upstream data in subrequest\n"); + assert (cbdataReferenceValid (esiStream->include)); esiIncludeSubRequestDone (esiStream->include, esiStream, 1); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1477,6 +1491,7 @@ if (clientHttpRequestStatus(-1, http)) { /* TODO: Does this if block leak htto ? */ esiStreamContext *temp = esiStream; + assert (cbdataReferenceValid (esiStream->include)); esiIncludeSubRequestDone (esiStream->include, esiStream, 0); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1487,6 +1502,7 @@ case STREAM_UNPLANNED_COMPLETE: /* fallthru ok */ case STREAM_COMPLETE: /* ok */ debug (86,1)("ESI subrequest finished OK\n"); + assert (cbdataReferenceValid (esiStream->include)); esiIncludeSubRequestDone (esiStream->include, esiStream, 1); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1494,6 +1510,7 @@ return; case STREAM_FAILED: debug (86,1)("ESI subrequest failed transfer\n"); + assert (cbdataReferenceValid (esiStream->include)); esiIncludeSubRequestDone (esiStream->include, esiStream, 0); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -2868,9 +2885,20 @@ int esiEnableProcessing (HttpReply *rep) { - if (httpHeaderHas(&rep->header, HDR_SURROGATE_CONTROL)) - return 0; - return 0; + int rv = 0; + if (httpHeaderHas(&rep->header, HDR_SURROGATE_CONTROL)) { + HttpHdrScTarget *sctusable = httpHdrScGetMergedTarget (rep->surrogate_control, + Config.Accel.surrogate_id); + if (!sctusable || strLen (sctusable->content) == 0) + /* Nothing generic or targeted at us, or no + * content processing requested + */ + return 0; + if (strstr (strBuf(sctusable->content), "ESI/1.0")) + rv = 1; + httpHdrScTargetDestroy (sctusable); + } + return rv; } Index: squid/src/clientStream.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/clientStream.c,v retrieving revision 1.1.2.5 retrieving revision 1.1.2.6 diff -u -r1.1.2.5 -r1.1.2.6 --- squid/src/clientStream.c 15 Aug 2002 09:17:15 -0000 1.1.2.5 +++ squid/src/clientStream.c 28 Aug 2002 02:31:44 -0000 1.1.2.6 @@ -1,6 +1,6 @@ /* - * $Id: clientStream.c,v 1.1.2.5 2002/08/15 09:17:15 rbcollins Exp $ + * $Id: clientStream.c,v 1.1.2.6 2002/08/28 02:31:44 rbcollins Exp $ * * DEBUG: section 87 Client-side Strean routines. * AUTHOR: Robert Collins @@ -140,6 +140,7 @@ assert (list->head); temp = clientStreamNew(func, callback, status, data); temp->head = list; + debug (87,3)("clientStreamInsertHead: Inserted node %p with data %p after head\n", temp, data); dlinkAddAfter (temp, &temp->node, list->head, list); /* FIXME (clientStreamDelete */ cbdataReference (temp); @@ -152,6 +153,7 @@ { /* No asserts for speed. This could even be a #define if needed */ clientStreamNode *next = this->node.next->data; + debug (87,3)("clientStreamCallback: Calling %p with cbdata %p from node %p\n",next->callback,next->data,this); next->callback (next, http, rep, body_data, body_size); } @@ -162,6 +164,7 @@ /* no asserts for speed. This could even be a #define if needed */ /* place the parameters on the 'stack' */ clientStreamNode *prev = this->node.prev->data; + debug (87,3)("clientStreamRead: Calling %p with cbdata %p from node %p\n",prev->readfunc,prev->data,this); this->readoff = readoff; this->readlen = readlen; this->readbuf = readbuf; @@ -183,7 +186,7 @@ clientStreamFree (void *foo) { clientStreamNode *this = foo; - debug (87, 9) ("Freeing clientStreamNode %p\n", this); + debug (87, 3) ("Freeing clientStreamNode %p\n", this); /* ESI TODO: push refcount class through to head */ if (this->data) { cbdataFree (this->data);