--------------------- PatchSet 1940 Date: 2005/10/06 05:31:26 Author: rousskov Branch: squid3-icap Tag: (none) Log: - Revised ICAP parsing code to accomodate 100 and 204 responses. - Added initial support for 100 Continue ICAP responses. Untested. - Added a stub to eventually support 204 No Content ICAP responses. The stub raises the exception, aborting the ICAP transaction. Tested. Members: src/ICAPXaction.cc:1.1.2.45->1.1.2.46 src/ICAPXaction.h:1.1.2.22->1.1.2.23 Index: squid3/src/ICAPXaction.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/ICAPXaction.cc,v retrieving revision 1.1.2.45 retrieving revision 1.1.2.46 diff -u -r1.1.2.45 -r1.1.2.46 --- squid3/src/ICAPXaction.cc 5 Oct 2005 22:34:56 -0000 1.1.2.45 +++ squid3/src/ICAPXaction.cc 6 Oct 2005 05:31:26 -0000 1.1.2.46 @@ -218,6 +218,7 @@ debug(93,3)("ICAPXaction::noteCommConnected() called\n"); ICAPXaction_Enter(noteCommConnected); + Must(state.writing == State::writingConnect); Must(status == COMM_OK); startReading(); // wait for early errors from the ICAP server @@ -226,6 +227,7 @@ requestBuf.init(); makeRequestHeaders(&requestBuf); // write headers only; comm module will free the requestBuf + state.writing = State::writingHeaders; writer = &ICAPXaction_noteCommWroteHeaders; comm_old_write_mbuf(connection, &requestBuf, writer, this); @@ -532,15 +534,10 @@ Must(state.parsingHeaders()); if (state.parsing == State::psIcapHeader) - parseHead(icapReply); + parseIcapHead(); - if (state.parsing == State::psHttpHeader) { - if (gotEncapsulated("res-hdr") || gotEncapsulated("req-hdr")) { - maybeAllocateHttpMsg(); - parseHead(adapted->data->header); - } else - state.parsing = State::psBody; - } + if (state.parsing == State::psHttpHeader) + parseHttpHead(); if (state.parsingHeaders()) // need more data Must(!state.doneReading); @@ -548,7 +545,81 @@ adapted->sendSourceStart(); } -void ICAPXaction::parseHead(HttpMsg *head) +void ICAPXaction::parseIcapHead() +{ + if (!parseHead(icapReply)) + return; + + switch (icapReply->sline.status) { + + case 100: + handle100Continue(); + break; + + case 200: + handle200Ok(); + break; + + case 204: + handle204NoContent(); + break; + + default: + handleUnknownScode(); + break; + } + + // handle100Continue() manages state.writing on its own. + // Non-100 status means the server needs no more data from us. + if (state.writing == State::writingPaused) + state.writing = State::writingDone; + + // TODO: Consider applying a Squid 2.5 patch to recognize 201 responses +} + +void ICAPXaction::handle100Continue() +{ + Must(state.writing == State::writingPaused); + Must(preview.enabled() && preview.done() && !preview.ieof()); + + state.parsing = State::psHttpHeader; // eventually + state.writing = State::writingPrime; + writeMore(); +} + +void ICAPXaction::handle200Ok() +{ + state.parsing = State::psHttpHeader; +} + +void ICAPXaction::handle204NoContent() +{ + state.parsing = State::psDone; + Must(false); // implement! +} + +void ICAPXaction::handleUnknownScode() +{ + state.parsing = State::psDone; + // TODO: mark connection as "bad" + + // Terminate the transaction; we do not know how to handle this response. + Must(false); +} + +void ICAPXaction::parseHttpHead() +{ + if (gotEncapsulated("res-hdr") || gotEncapsulated("req-hdr")) { + maybeAllocateHttpMsg(); + + if (!parseHead(adapted->data->header)) + return; + } + + state.parsing = State::psBody; +} + +bool ICAPXaction::parseHead(HttpMsg *head) { assert(head); debugs(93, 5, "have " << readBuf.contentSize() << " head bytes to parse" << @@ -556,23 +627,15 @@ http_status error = HTTP_STATUS_NONE; const bool parsed = head->parse(&readBuf, state.doneReading, &error); - - // TODO: replace the if below with Must(parsed || !error); - - if (!parsed && error > 0) { // unrecoverable parsing error - debugs(11, 1, "ICAPXaction::parseHead: failed to parse ICAP header: '" << readBuf.content() << "'"); - notify = notifyHttp; - doStop(); - return; - } + Must(parsed || !error); // success or need more data if (!parsed) { // need more data head->reset(); - return; + return false; } readBuf.consume(head->hdr_sz); - state.parsing = (State::Parsing)(state.parsing + 1); + return true; } void ICAPXaction::parseBody() Index: squid3/src/ICAPXaction.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/ICAPXaction.h,v retrieving revision 1.1.2.22 retrieving revision 1.1.2.23 diff -u -r1.1.2.22 -r1.1.2.23 --- squid3/src/ICAPXaction.h 5 Oct 2005 22:34:56 -0000 1.1.2.22 +++ squid3/src/ICAPXaction.h 6 Oct 2005 05:31:26 -0000 1.1.2.23 @@ -1,6 +1,6 @@ /* - * $Id: ICAPXaction.h,v 1.1.2.22 2005/10/05 22:34:56 rousskov Exp $ + * $Id: ICAPXaction.h,v 1.1.2.23 2005/10/06 05:31:26 rousskov Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -177,13 +177,22 @@ void backup(const MemBuf &buf); void parseMore(); + void parseHeaders(); - void parseHead(HttpMsg *head); + void parseIcapHead(); + void parseHttpHead(); + bool parseHead(HttpMsg *head); + void parseBody(); bool parsePresentBody(); void maybeAllocateHttpMsg(); bool expectVirginBody() const; + void handle100Continue(); + void handle200Ok(); + void handle204NoContent(); + void handleUnknownScode(); + bool done() const; typedef enum { notifyUnknown, notifyNone, notifyService, notifyHttp,