2 * DEBUG: section 93 ICAP (RFC 3507) Client
8 #include "HttpRequest.h"
10 #include "ICAPServiceRep.h"
11 #include "ICAPInitiator.h"
12 #include "ICAPLauncher.h"
13 #include "ICAPModXact.h"
14 #include "ICAPClient.h"
15 #include "ChunkedCodingParser.h"
16 #include "TextException.h"
17 #include "AuthUserRequest.h"
18 #include "ICAPConfig.h"
19 #include "SquidTime.h"
21 // flow and terminology:
22 // HTTP| --> receive --> encode --> write --> |network
23 // end | <-- send <-- parse <-- read <-- |end
25 // TODO: replace gotEncapsulated() with something faster; we call it often
27 CBDATA_CLASS_INIT(ICAPModXact
);
28 CBDATA_CLASS_INIT(ICAPModXactLauncher
);
30 static const size_t TheBackupLimit
= BodyPipe::MaxCapacity
;
32 extern ICAPConfig TheICAPConfig
;
35 ICAPModXact::State::State()
37 memset(this, sizeof(*this), 0);
40 ICAPModXact::ICAPModXact(ICAPInitiator
*anInitiator
, HttpMsg
*virginHeader
,
41 HttpRequest
*virginCause
, ICAPServiceRep::Pointer
&aService
):
42 ICAPXaction("ICAPModXact", anInitiator
, aService
),
46 canStartBypass(false) // too early
50 virgin
.setHeader(virginHeader
); // sets virgin.body_pipe if needed
51 virgin
.setCause(virginCause
); // may be NULL
53 // adapted header and body are initialized when we parse them
55 // writing and reading ends are handled by ICAPXaction
58 // nothing to do because we are using temporary buffers
61 icapReply
= new HttpReply
;
62 icapReply
->protoPrefix
= "ICAP/"; // TODO: make an IcapReply class?
64 debugs(93,7, "ICAPModXact initialized." << status());
67 // initiator wants us to start
68 void ICAPModXact::start()
72 estimateVirginBody(); // before virgin disappears!
74 canStartBypass
= service().bypass
;
76 // it is an ICAP violation to send request to a service w/o known OPTIONS
83 // XXX: If commConnectStart in startWriting fails, we may get here
84 //_after_ the object got destroyed. Somebody please fix commConnectStart!
85 // TODO: Does re-entrance protection in callStart() solve the above?
89 void ICAPModXact_noteServiceReady(void *data
, ICAPServiceRep::Pointer
&)
91 ICAPModXact
*x
= static_cast<ICAPModXact
*>(data
);
93 x
->noteServiceReady();
96 void ICAPModXact::waitForService()
98 Must(!state
.serviceWaiting
);
99 debugs(93, 7, "ICAPModXact will wait for the ICAP service" << status());
100 state
.serviceWaiting
= true;
101 service().callWhenReady(&ICAPModXact_noteServiceReady
, this);
104 void ICAPModXact::noteServiceReady()
106 ICAPXaction_Enter(noteServiceReady
);
108 Must(state
.serviceWaiting
);
109 state
.serviceWaiting
= false;
111 if (service().up()) {
115 throw TexcHere("ICAP service is unusable");
121 void ICAPModXact::startWriting()
123 state
.writing
= State::writingConnect
;
125 decideOnPreview(); // must be decided before we decideOnRetries
129 // put nothing here as openConnection calls commConnectStart
130 // and that may call us back without waiting for the next select loop
133 // connection with the ICAP service established
134 void ICAPModXact::handleCommConnected()
136 Must(state
.writing
== State::writingConnect
);
138 startReading(); // wait for early errors from the ICAP server
143 makeRequestHeaders(requestBuf
);
144 debugs(93, 9, "ICAPModXact ICAP will write" << status() << ":\n" <<
145 (requestBuf
.terminate(), requestBuf
.content()));
148 state
.writing
= State::writingHeaders
;
149 scheduleWrite(requestBuf
);
152 void ICAPModXact::handleCommWrote(size_t sz
)
154 debugs(93, 5, HERE
<< "Wrote " << sz
<< " bytes");
156 if (state
.writing
== State::writingHeaders
)
157 handleCommWroteHeaders();
159 handleCommWroteBody();
162 void ICAPModXact::handleCommWroteHeaders()
164 Must(state
.writing
== State::writingHeaders
);
166 // determine next step
167 if (preview
.enabled())
168 state
.writing
= preview
.done() ? State::writingPaused
: State::writingPreview
;
170 if (virginBody
.expected())
171 state
.writing
= State::writingPrime
;
180 void ICAPModXact::writeMore()
182 debugs(93, 5, HERE
<< "checking whether to write more" << status());
184 if (writer
) // already writing something
187 switch (state
.writing
) {
189 case State::writingInit
: // waiting for service OPTIONS
190 Must(state
.serviceWaiting
);
192 case State::writingConnect
: // waiting for the connection to establish
194 case State::writingHeaders
: // waiting for the headers to be written
196 case State::writingPaused
: // waiting for the ICAP server response
198 case State::writingReallyDone
: // nothing more to write
201 case State::writingAlmostDone
: // was waiting for the last write
205 case State::writingPreview
:
209 case State::writingPrime
:
214 throw TexcHere("ICAPModXact in bad writing state");
218 void ICAPModXact::writePreviewBody()
220 debugs(93, 8, HERE
<< "will write Preview body from " <<
221 virgin
.body_pipe
<< status());
222 Must(state
.writing
== State::writingPreview
);
223 Must(virgin
.body_pipe
!= NULL
);
225 const size_t sizeMax
= (size_t)virgin
.body_pipe
->buf().contentSize();
226 const size_t size
= XMIN(preview
.debt(), sizeMax
);
227 writeSomeBody("preview body", size
);
229 // change state once preview is written
231 if (preview
.done()) {
232 debugs(93, 7, "ICAPModXact wrote entire Preview body" << status());
237 state
.writing
= State::writingPaused
;
241 void ICAPModXact::writePrimeBody()
243 Must(state
.writing
== State::writingPrime
);
244 Must(virginBodyWriting
.active());
246 const size_t size
= (size_t)virgin
.body_pipe
->buf().contentSize();
247 writeSomeBody("prime virgin body", size
);
249 if (virginBodyEndReached(virginBodyWriting
)) {
250 debugs(93, 5, HERE
<< "wrote entire body");
255 void ICAPModXact::writeSomeBody(const char *label
, size_t size
)
257 Must(!writer
&& state
.writing
< state
.writingAlmostDone
);
258 Must(virgin
.body_pipe
!= NULL
);
259 debugs(93, 8, HERE
<< "will write up to " << size
<< " bytes of " <<
262 MemBuf writeBuf
; // TODO: suggest a min size based on size and lastChunk
264 writeBuf
.init(); // note: we assume that last-chunk will fit
266 const size_t writableSize
= virginContentSize(virginBodyWriting
);
267 const size_t chunkSize
= XMIN(writableSize
, size
);
270 debugs(93, 7, HERE
<< "will write " << chunkSize
<<
271 "-byte chunk of " << label
);
273 openChunk(writeBuf
, chunkSize
, false);
274 writeBuf
.append(virginContentData(virginBodyWriting
), chunkSize
);
275 closeChunk(writeBuf
);
277 virginBodyWriting
.progress(chunkSize
);
280 debugs(93, 7, "ICAPModXact has no writable " << label
<< " content");
283 const bool wroteEof
= virginBodyEndReached(virginBodyWriting
);
284 bool lastChunk
= wroteEof
;
285 if (state
.writing
== State::writingPreview
) {
286 preview
.wrote(chunkSize
, wroteEof
); // even if wrote nothing
287 lastChunk
= lastChunk
|| preview
.done();
291 debugs(93, 8, HERE
<< "will write last-chunk of " << label
);
292 addLastRequestChunk(writeBuf
);
295 debugs(93, 7, HERE
<< "will write " << writeBuf
.contentSize()
296 << " raw bytes of " << label
);
298 if (writeBuf
.hasContent()) {
299 scheduleWrite(writeBuf
); // comm will free the chunk
305 void ICAPModXact::addLastRequestChunk(MemBuf
&buf
)
307 const bool ieof
= state
.writing
== State::writingPreview
&& preview
.ieof();
308 openChunk(buf
, 0, ieof
);
312 void ICAPModXact::openChunk(MemBuf
&buf
, size_t chunkSize
, bool ieof
)
314 buf
.Printf((ieof
? "%x; ieof\r\n" : "%x\r\n"), (int) chunkSize
);
317 void ICAPModXact::closeChunk(MemBuf
&buf
)
319 buf
.append(ICAP::crlf
, 2); // chunk-terminating CRLF
322 // did the activity reached the end of the virgin body?
323 bool ICAPModXact::virginBodyEndReached(const VirginBodyAct
&act
) const
326 !act
.active() || // did all (assuming it was originally planned)
327 !virgin
.body_pipe
->expectMoreAfter(act
.offset()); // wont have more
330 // the size of buffered virgin body data available for the specified activity
331 // if this size is zero, we may be done or may be waiting for more data
332 size_t ICAPModXact::virginContentSize(const VirginBodyAct
&act
) const
335 // asbolute start of unprocessed data
336 const size_t start
= act
.offset();
337 // absolute end of buffered data
338 const size_t end
= virginConsumed
+ virgin
.body_pipe
->buf().contentSize();
339 Must(virginConsumed
<= start
&& start
<= end
);
343 // pointer to buffered virgin body data available for the specified activity
344 const char *ICAPModXact::virginContentData(const VirginBodyAct
&act
) const
347 const size_t start
= act
.offset();
348 Must(virginConsumed
<= start
);
349 return virgin
.body_pipe
->buf().content() + (start
-virginConsumed
);
352 void ICAPModXact::virginConsume()
354 debugs(93, 9, "consumption guards: " << !virgin
.body_pipe
<< isRetriable
);
356 if (!virgin
.body_pipe
)
357 return; // nothing to consume
360 return; // do not consume if we may have to retry later
362 BodyPipe
&bp
= *virgin
.body_pipe
;
364 // Why > 2? HttpState does not use the last bytes in the buffer
365 // because delayAwareRead() is arguably broken. See
366 // HttpStateData::maybeReadVirginBody for more details.
367 if (canStartBypass
&& bp
.buf().spaceSize() > 2) {
368 // Postponing may increase memory footprint and slow the HTTP side
369 // down. Not postponing may increase the number of ICAP errors
370 // if the ICAP service fails. We may also use "potential" space to
371 // postpone more aggressively. Should the trade-off be configurable?
372 debugs(93, 8, HERE
<< "postponing consumption from " << bp
.status());
376 const size_t have
= static_cast<size_t>(bp
.buf().contentSize());
377 const size_t end
= virginConsumed
+ have
;
380 debugs(93, 9, HERE
<< "max virgin consumption offset=" << offset
<<
381 " acts " << virginBodyWriting
.active() << virginBodySending
.active() <<
382 " consumed=" << virginConsumed
<<
383 " from " << virgin
.body_pipe
->status());
385 if (virginBodyWriting
.active())
386 offset
= XMIN(virginBodyWriting
.offset(), offset
);
388 if (virginBodySending
.active())
389 offset
= XMIN(virginBodySending
.offset(), offset
);
391 Must(virginConsumed
<= offset
&& offset
<= end
);
393 if (const size_t size
= offset
- virginConsumed
) {
394 debugs(93, 8, HERE
<< "consuming " << size
<< " out of " << have
<<
395 " virgin body bytes");
397 virginConsumed
+= size
;
398 Must(!isRetriable
); // or we should not be consuming
399 disableBypass("consumed content");
403 void ICAPModXact::handleCommWroteBody()
408 // Called when we do not expect to call comm_write anymore.
409 // We may have a pending write though.
410 // If stopping nicely, we will just wait for that pending write, if any.
411 void ICAPModXact::stopWriting(bool nicely
)
413 if (state
.writing
== State::writingReallyDone
)
418 debugs(93, 7, HERE
<< "will wait for the last write" << status());
419 state
.writing
= State::writingAlmostDone
; // may already be set
423 debugs(93, 3, HERE
<< "will NOT wait for the last write" << status());
425 // Comm does not have an interface to clear the writer callback nicely,
426 // but without clearing the writer we cannot recycle the connection.
427 // We prevent connection reuse and hope that we can handle a callback
428 // call at any time, usually in the middle of the destruction sequence!
429 // Somebody should add comm_remove_write_handler() to comm API.
430 reuseConnection
= false;
431 ignoreLastWrite
= true;
434 debugs(93, 7, HERE
<< "will no longer write" << status());
435 if (virginBodyWriting
.active()) {
436 virginBodyWriting
.disable();
439 state
.writing
= State::writingReallyDone
;
443 void ICAPModXact::stopBackup()
445 if (!virginBodySending
.active())
448 debugs(93, 7, "ICAPModXact will no longer backup" << status());
449 virginBodySending
.disable();
453 bool ICAPModXact::doneAll() const
455 return ICAPXaction::doneAll() && !state
.serviceWaiting
&&
457 doneReading() && state
.doneWriting();
460 void ICAPModXact::startReading()
462 Must(connection
>= 0);
464 Must(!adapted
.header
);
465 Must(!adapted
.body_pipe
);
467 // we use the same buffer for headers and body and then consume headers
471 void ICAPModXact::readMore()
473 if (reader
|| doneReading()) {
474 debugs(93,3,HERE
<< "returning from readMore because reader or doneReading()");
478 // do not fill readBuf if we have no space to store the result
479 if (adapted
.body_pipe
!= NULL
&&
480 !adapted
.body_pipe
->buf().hasPotentialSpace()) {
481 debugs(93,3,HERE
<< "not reading because ICAP reply pipe is full");
485 if (readBuf
.hasSpace())
488 debugs(93,3,HERE
<< "nothing to do because !readBuf.hasSpace()");
491 // comm module read a portion of the ICAP response for us
492 void ICAPModXact::handleCommRead(size_t)
494 Must(!state
.doneParsing());
499 void ICAPModXact::echoMore()
501 Must(state
.sending
== State::sendingVirgin
);
502 Must(adapted
.body_pipe
!= NULL
);
503 Must(virginBodySending
.active());
505 const size_t sizeMax
= virginContentSize(virginBodySending
);
506 debugs(93,5, HERE
<< "will echo up to " << sizeMax
<< " bytes from " <<
507 virgin
.body_pipe
->status());
508 debugs(93,5, HERE
<< "will echo up to " << sizeMax
<< " bytes to " <<
509 adapted
.body_pipe
->status());
512 const size_t size
= adapted
.body_pipe
->putMoreData(virginContentData(virginBodySending
), sizeMax
);
513 debugs(93,5, HERE
<< "echoed " << size
<< " out of " << sizeMax
<<
515 virginBodySending
.progress(size
);
517 disableBypass("echoed content");
520 if (virginBodyEndReached(virginBodySending
)) {
521 debugs(93, 5, "ICAPModXact echoed all" << status());
524 debugs(93, 5, "ICAPModXact has " <<
525 virgin
.body_pipe
->buf().contentSize() << " bytes " <<
526 "and expects more to echo" << status());
527 // TODO: timeout if virgin or adapted pipes are broken
531 bool ICAPModXact::doneSending() const
533 return state
.sending
== State::sendingDone
;
536 // stop (or do not start) sending adapted message body
537 void ICAPModXact::stopSending(bool nicely
)
542 if (state
.sending
!= State::sendingUndecided
) {
543 debugs(93, 7, "ICAPModXact will no longer send" << status());
544 if (adapted
.body_pipe
!= NULL
) {
545 virginBodySending
.disable();
546 // we may leave debts if we were echoing and the virgin
547 // body_pipe got exhausted before we echoed all planned bytes
548 const bool leftDebts
= adapted
.body_pipe
->needsMoreData();
549 stopProducingFor(adapted
.body_pipe
, nicely
&& !leftDebts
);
552 debugs(93, 7, "ICAPModXact will not start sending" << status());
553 Must(!adapted
.body_pipe
);
556 state
.sending
= State::sendingDone
;
560 // should be called after certain state.writing or state.sending changes
561 void ICAPModXact::checkConsuming()
563 // quit if we already stopped or are still using the pipe
564 if (!virgin
.body_pipe
|| !state
.doneConsumingVirgin())
567 debugs(93, 7, HERE
<< "will stop consuming" << status());
568 stopConsumingFrom(virgin
.body_pipe
);
571 void ICAPModXact::parseMore()
573 debugs(93, 5, HERE
<< "have " << readBuf
.contentSize() << " bytes to parse" <<
575 debugs(93, 5, HERE
<< "\n" << readBuf
.content());
577 if (state
.parsingHeaders())
580 if (state
.parsing
== State::psBody
)
584 void ICAPModXact::callException(const TextException
&e
)
586 if (!canStartBypass
|| isRetriable
) {
587 ICAPXaction::callException(e
);
592 debugs(93, 3, "bypassing ICAPModXact::" << inCall
<< " exception: " <<
593 e
.message
<< ' ' << status());
596 catch (const TextException
&bypassE
) {
597 ICAPXaction::callException(bypassE
);
601 void ICAPModXact::bypassFailure()
603 disableBypass("already started to bypass");
605 Must(!isRetriable
); // or we should not be bypassing
611 // end all activities associated with the ICAP server
615 stopWriting(true); // or should we force it?
616 if (connection
>= 0) {
617 reuseConnection
= false; // be conservative
618 cancelRead(); // may not work; and we cannot stop connecting either
620 debugs(93, 7, "Warning: bypass failed to stop I/O" << status());
624 void ICAPModXact::disableBypass(const char *reason
)
626 if (canStartBypass
) {
627 debugs(93,7, HERE
<< "will never start bypass because " << reason
);
628 canStartBypass
= false;
634 // note that allocation for echoing is done in handle204NoContent()
635 void ICAPModXact::maybeAllocateHttpMsg()
637 if (adapted
.header
) // already allocated
640 if (gotEncapsulated("res-hdr")) {
641 adapted
.setHeader(new HttpReply
);
642 } else if (gotEncapsulated("req-hdr")) {
643 adapted
.setHeader(new HttpRequest
);
645 throw TexcHere("Neither res-hdr nor req-hdr in maybeAllocateHttpMsg()");
648 void ICAPModXact::parseHeaders()
650 Must(state
.parsingHeaders());
652 if (state
.parsing
== State::psIcapHeader
) {
653 debugs(93, 5, HERE
<< "parse ICAP headers");
657 if (state
.parsing
== State::psHttpHeader
) {
658 debugs(93, 5, HERE
<< "parse HTTP headers");
662 if (state
.parsingHeaders()) { // need more data
670 // called after parsing all headers or when bypassing an exception
671 void ICAPModXact::startSending()
673 disableBypass("sent headers");
674 sendAnswer(adapted
.header
);
676 if (state
.sending
== State::sendingVirgin
)
680 void ICAPModXact::parseIcapHead()
682 Must(state
.sending
== State::sendingUndecided
);
684 if (!parseHead(icapReply
))
687 if (httpHeaderHasConnDir(&icapReply
->header
, "close")) {
688 debugs(93, 5, HERE
<< "found connection close");
689 reuseConnection
= false;
692 switch (icapReply
->sline
.status
) {
700 if (!validate200Ok()) {
701 throw TexcHere("Invalid ICAP Response");
709 handle204NoContent();
713 debugs(93, 5, HERE
<< "ICAP status " << icapReply
->sline
.status
);
714 handleUnknownScode();
718 // handle100Continue() manages state.writing on its own.
719 // Non-100 status means the server needs no postPreview data from us.
720 if (state
.writing
== State::writingPaused
)
723 // TODO: Consider applying a Squid 2.5 patch to recognize 201 responses
726 bool ICAPModXact::validate200Ok()
728 if (ICAP::methodRespmod
== service().method
) {
729 if (!gotEncapsulated("res-hdr"))
735 if (ICAP::methodReqmod
== service().method
) {
736 if (!gotEncapsulated("res-hdr") && !gotEncapsulated("req-hdr"))
745 void ICAPModXact::handle100Continue()
747 Must(state
.writing
== State::writingPaused
);
748 // server must not respond before the end of preview: we may send ieof
749 Must(preview
.enabled() && preview
.done() && !preview
.ieof());
751 // 100 "Continue" cancels our preview commitment, not 204s outside preview
752 if (!state
.allowedPostview204
)
755 state
.parsing
= State::psIcapHeader
; // eventually
758 state
.writing
= State::writingPrime
;
763 void ICAPModXact::handle200Ok()
765 state
.parsing
= State::psHttpHeader
;
766 state
.sending
= State::sendingAdapted
;
771 void ICAPModXact::handle204NoContent()
777 // Called when we receive a 204 No Content response and
778 // when we are trying to bypass a service failure.
779 // We actually start sending (echoig or not) in startSending.
780 void ICAPModXact::prepEchoing()
782 disableBypass("preparing to echo content");
784 // We want to clone the HTTP message, but we do not want
785 // to copy some non-HTTP state parts that HttpMsg kids carry in them.
786 // Thus, we cannot use a smart pointer, copy constructor, or equivalent.
787 // Instead, we simply write the HTTP message and "clone" it by parsing.
789 HttpMsg
*oldHead
= virgin
.header
;
790 debugs(93, 7, "ICAPModXact cloning virgin message " << oldHead
);
794 // write the virgin message into a memory buffer
796 packHead(httpBuf
, oldHead
);
798 // allocate the adapted message and copy metainfo
799 Must(!adapted
.header
);
800 HttpMsg
*newHead
= NULL
;
801 if (const HttpRequest
*oldR
= dynamic_cast<const HttpRequest
*>(oldHead
)) {
802 HttpRequest
*newR
= new HttpRequest
;
803 inheritVirginProperties(*newR
, *oldR
);
806 if (dynamic_cast<const HttpReply
*>(oldHead
))
807 newHead
= new HttpReply
;
810 adapted
.setHeader(newHead
);
812 // parse the buffer back
813 http_status error
= HTTP_STATUS_NONE
;
815 Must(newHead
->parse(&httpBuf
, true, &error
));
817 Must(newHead
->hdr_sz
== httpBuf
.contentSize()); // no leftovers
821 debugs(93, 7, "ICAPModXact cloned virgin message " << oldHead
<< " to " <<
824 // setup adapted body pipe if needed
825 if (oldHead
->body_pipe
!= NULL
) {
826 debugs(93, 7, HERE
<< "will echo virgin body from " <<
828 if (!virginBodySending
.active())
829 virginBodySending
.plan(); // will throw if not possible
830 state
.sending
= State::sendingVirgin
;
833 // TODO: optimize: is it possible to just use the oldHead pipe and
834 // remove ICAP from the loop? This echoing is probably a common case!
835 makeAdaptedBodyPipe("echoed virgin response");
836 if (oldHead
->body_pipe
->bodySizeKnown())
837 adapted
.body_pipe
->setBodySize(oldHead
->body_pipe
->bodySize());
838 debugs(93, 7, HERE
<< "will echo virgin body to " <<
841 debugs(93, 7, HERE
<< "no virgin body to echo");
846 void ICAPModXact::handleUnknownScode()
850 // TODO: mark connection as "bad"
852 // Terminate the transaction; we do not know how to handle this response.
853 throw TexcHere("Unsupported ICAP status code");
856 void ICAPModXact::parseHttpHead()
858 if (gotEncapsulated("res-hdr") || gotEncapsulated("req-hdr")) {
859 maybeAllocateHttpMsg();
861 if (!parseHead(adapted
.header
))
862 return; // need more header data
864 if (HttpRequest
*newHead
= dynamic_cast<HttpRequest
*>(adapted
.header
)) {
865 const HttpRequest
*oldR
= dynamic_cast<const HttpRequest
*>(virgin
.header
);
867 // TODO: the adapted request did not really originate from the
868 // client; give proxy admin an option to prevent copying of
869 // sensitive client information here. See the following thread:
870 // http://www.squid-cache.org/mail-archive/squid-dev/200703/0040.html
871 inheritVirginProperties(*newHead
, *oldR
);
875 decideOnParsingBody();
878 // parses both HTTP and ICAP headers
879 bool ICAPModXact::parseHead(HttpMsg
*head
)
882 debugs(93, 5, HERE
<< "have " << readBuf
.contentSize() << " head bytes to parse" <<
883 "; state: " << state
.parsing
);
885 http_status error
= HTTP_STATUS_NONE
;
886 const bool parsed
= head
->parse(&readBuf
, commEof
, &error
);
887 Must(parsed
|| !error
); // success or need more data
889 if (!parsed
) { // need more data
890 debugs(93, 5, HERE
<< "parse failed, need more data, return false");
895 debugs(93, 5, HERE
<< "parse success, consume " << head
->hdr_sz
<< " bytes, return true");
896 readBuf
.consume(head
->hdr_sz
);
900 // TODO: Move this method to HttpRequest?
901 void ICAPModXact::inheritVirginProperties(HttpRequest
&newR
, const HttpRequest
&oldR
) {
903 newR
.client_addr
= oldR
.client_addr
;
904 newR
.client_port
= oldR
.client_port
;
906 newR
.my_addr
= oldR
.my_addr
;
907 newR
.my_port
= oldR
.my_port
;
909 // This may be too conservative for the 204 No Content case
910 // may eventually need cloneNullAdaptationImmune() for that.
911 newR
.flags
= oldR
.flags
.cloneAdaptationImmune();
913 if (oldR
.auth_user_request
) {
914 newR
.auth_user_request
= oldR
.auth_user_request
;
915 AUTHUSERREQUESTLOCK(newR
.auth_user_request
, "newR in ICAPModXact");
919 void ICAPModXact::decideOnParsingBody() {
920 if (gotEncapsulated("res-body") || gotEncapsulated("req-body")) {
921 debugs(93, 5, HERE
<< "expecting a body");
922 state
.parsing
= State::psBody
;
923 bodyParser
= new ChunkedCodingParser
;
924 makeAdaptedBodyPipe("adapted response from the ICAP server");
925 Must(state
.sending
== State::sendingAdapted
);
927 debugs(93, 5, HERE
<< "not expecting a body");
933 void ICAPModXact::parseBody()
935 Must(state
.parsing
== State::psBody
);
938 debugs(93, 5, HERE
<< "have " << readBuf
.contentSize() << " body bytes to parse");
940 // the parser will throw on errors
941 BodyPipeCheckout
bpc(*adapted
.body_pipe
);
942 const bool parsed
= bodyParser
->parse(&readBuf
, &bpc
.buf
);
945 debugs(93, 5, HERE
<< "have " << readBuf
.contentSize() << " body bytes after " <<
946 "parse; parsed all: " << parsed
);
948 // TODO: expose BodyPipe::putSize() to make this check simpler and clearer
949 if (adapted
.body_pipe
->buf().contentSize() > 0) // parsed something sometime
950 disableBypass("sent adapted content");
954 stopSending(true); // the parser succeeds only if all parsed data fits
958 debugs(93,3,HERE
<< this << " needsMoreData = " << bodyParser
->needsMoreData());
960 if (bodyParser
->needsMoreData()) {
961 debugs(93,3,HERE
<< this);
966 if (bodyParser
->needsMoreSpace()) {
967 Must(!doneSending()); // can hope for more space
968 Must(adapted
.body_pipe
->buf().contentSize() > 0); // paranoid
969 // TODO: there should be a timeout in case the sink is broken
970 // or cannot consume partial content (while we need more space)
974 void ICAPModXact::stopParsing()
976 if (state
.parsing
== State::psDone
)
979 debugs(93, 7, "ICAPModXact will no longer parse" << status());
985 state
.parsing
= State::psDone
;
988 // HTTP side added virgin body data
989 void ICAPModXact::noteMoreBodyDataAvailable(BodyPipe
&)
991 ICAPXaction_Enter(noteMoreBodyDataAvailable
);
995 if (state
.sending
== State::sendingVirgin
)
1001 // HTTP side sent us all virgin info
1002 void ICAPModXact::noteBodyProductionEnded(BodyPipe
&)
1004 ICAPXaction_Enter(noteBodyProductionEnded
);
1006 Must(virgin
.body_pipe
->productionEnded());
1008 // push writer and sender in case we were waiting for the last-chunk
1011 if (state
.sending
== State::sendingVirgin
)
1017 // body producer aborted, but the initiator may still want to know
1018 // the answer, even though the HTTP message has been truncated
1019 void ICAPModXact::noteBodyProducerAborted(BodyPipe
&)
1021 ICAPXaction_Enter(noteBodyProducerAborted
);
1023 Must(virgin
.body_pipe
->productionEnded());
1025 // push writer and sender in case we were waiting for the last-chunk
1028 if (state
.sending
== State::sendingVirgin
)
1034 // adapted body consumer wants more adapted data and
1035 // possibly freed some buffer space
1036 void ICAPModXact::noteMoreBodySpaceAvailable(BodyPipe
&)
1038 ICAPXaction_Enter(noteMoreBodySpaceAvailable
);
1040 if (state
.sending
== State::sendingVirgin
)
1042 else if (state
.sending
== State::sendingAdapted
)
1045 Must(state
.sending
== State::sendingUndecided
);
1050 // adapted body consumer aborted
1051 void ICAPModXact::noteBodyConsumerAborted(BodyPipe
&)
1053 ICAPXaction_Enter(noteBodyConsumerAborted
);
1055 mustStop("adapted body consumer aborted");
1061 void ICAPModXact::swanSong()
1063 debugs(93, 5, HERE
<< "swan sings" << status());
1073 ICAPXaction::swanSong();
1076 void ICAPModXact::makeRequestHeaders(MemBuf
&buf
)
1079 * XXX These should use HttpHdr interfaces instead of Printfs
1081 const ICAPServiceRep
&s
= service();
1082 buf
.Printf("%s %s ICAP/1.0\r\n", s
.methodStr(), s
.uri
.buf());
1083 buf
.Printf("Host: %s:%d\r\n", s
.host
.buf(), s
.port
);
1084 buf
.Printf("Date: %s\r\n", mkrfc1123(squid_curtime
));
1086 if (!TheICAPConfig
.reuse_connections
)
1087 buf
.Printf("Connection: close\r\n");
1089 buf
.Printf("Encapsulated: ");
1095 // build HTTP request header, if any
1096 ICAP::Method m
= s
.method
;
1098 const HttpRequest
*request
= virgin
.cause
?
1100 dynamic_cast<const HttpRequest
*>(virgin
.header
);
1102 // to simplify, we could assume that request is always available
1106 urlPath
= request
->urlpath
;
1107 if (ICAP::methodRespmod
== m
)
1108 encapsulateHead(buf
, "req-hdr", httpBuf
, request
);
1110 if (ICAP::methodReqmod
== m
)
1111 encapsulateHead(buf
, "req-hdr", httpBuf
, virgin
.header
);
1114 if (ICAP::methodRespmod
== m
)
1115 if (const HttpMsg
*prime
= virgin
.header
)
1116 encapsulateHead(buf
, "res-hdr", httpBuf
, prime
);
1118 if (!virginBody
.expected())
1119 buf
.Printf("null-body=%d", (int) httpBuf
.contentSize());
1120 else if (ICAP::methodReqmod
== m
)
1121 buf
.Printf("req-body=%d", (int) httpBuf
.contentSize());
1123 buf
.Printf("res-body=%d", (int) httpBuf
.contentSize());
1125 buf
.append(ICAP::crlf
, 2); // terminate Encapsulated line
1127 if (preview
.enabled()) {
1128 buf
.Printf("Preview: %d\r\n", (int)preview
.ad());
1129 if (virginBody
.expected()) // there is a body to preview
1130 virginBodySending
.plan();
1132 finishNullOrEmptyBodyPreview(httpBuf
);
1135 if (shouldAllow204()) {
1136 debugs(93,5, HERE
<< "will allow 204s outside of preview");
1137 state
.allowedPostview204
= true;
1138 buf
.Printf("Allow: 204\r\n");
1139 if (virginBody
.expected()) // there is a body to echo
1140 virginBodySending
.plan();
1143 if (TheICAPConfig
.send_client_ip
&& request
)
1144 if (request
->client_addr
.s_addr
!= any_addr
.s_addr
&&
1145 request
->client_addr
.s_addr
!= no_addr
.s_addr
)
1146 buf
.Printf("X-Client-IP: %s\r\n", inet_ntoa(request
->client_addr
));
1148 if (TheICAPConfig
.send_client_username
&& request
)
1149 makeUsernameHeader(request
, buf
);
1151 // fprintf(stderr, "%s\n", buf.content());
1153 buf
.append(ICAP::crlf
, 2); // terminate ICAP header
1155 // start ICAP request body with encapsulated HTTP headers
1156 buf
.append(httpBuf
.content(), httpBuf
.contentSize());
1161 void ICAPModXact::makeUsernameHeader(const HttpRequest
*request
, MemBuf
&buf
) {
1162 if (const AuthUserRequest
*auth
= request
->auth_user_request
) {
1163 if (char const *name
= auth
->username()) {
1164 const char *value
= TheICAPConfig
.client_username_encode
?
1165 base64_encode(name
) : name
;
1166 buf
.Printf("%s: %s\r\n", TheICAPConfig
.client_username_header
,
1172 void ICAPModXact::encapsulateHead(MemBuf
&icapBuf
, const char *section
, MemBuf
&httpBuf
, const HttpMsg
*head
)
1174 // update ICAP header
1175 icapBuf
.Printf("%s=%d, ", section
, (int) httpBuf
.contentSize());
1178 packHead(httpBuf
, head
);
1181 void ICAPModXact::packHead(MemBuf
&httpBuf
, const HttpMsg
*head
)
1184 packerToMemInit(&p
, &httpBuf
);
1185 head
->packInto(&p
, true);
1189 // decides whether to offer a preview and calculates its size
1190 void ICAPModXact::decideOnPreview()
1192 if (!TheICAPConfig
.preview_enable
) {
1193 debugs(93, 5, HERE
<< "preview disabled by squid.conf");
1197 const HttpRequest
*request
= virgin
.cause
?
1199 dynamic_cast<const HttpRequest
*>(virgin
.header
);
1200 const String urlPath
= request
? request
->urlpath
: String();
1202 if (!service().wantsPreview(urlPath
, wantedSize
)) {
1203 debugs(93, 5, "ICAPModXact should not offer preview for " << urlPath
);
1207 // we decided to do preview, now compute its size
1209 Must(wantedSize
>= 0);
1211 // cannot preview more than we can backup
1212 size_t ad
= XMIN(wantedSize
, TheBackupLimit
);
1214 if (!virginBody
.expected())
1217 if (virginBody
.knownSize())
1218 ad
= XMIN(ad
, virginBody
.size()); // not more than we have
1220 debugs(93, 5, "ICAPModXact should offer " << ad
<< "-byte preview " <<
1221 "(service wanted " << wantedSize
<< ")");
1224 Must(preview
.enabled());
1227 // decides whether to allow 204 responses
1228 bool ICAPModXact::shouldAllow204()
1230 if (!service().allows204())
1233 return canBackupEverything();
1236 // used by shouldAllow204 and decideOnRetries
1237 bool ICAPModXact::canBackupEverything() const
1239 if (!virginBody
.expected())
1240 return true; // no body means no problems with backup
1242 // if there is a body, check whether we can backup it all
1244 if (!virginBody
.knownSize())
1247 // or should we have a different backup limit?
1248 // note that '<' allows for 0-termination of the "full" backup buffer
1249 return virginBody
.size() < TheBackupLimit
;
1252 // Decide whether this transaction can be retried if pconn fails
1253 // Must be called after decideOnPreview and before openConnection()
1254 void ICAPModXact::decideOnRetries()
1257 return; // no, already decided
1259 if (preview
.enabled())
1260 return; // yes, because preview provides enough guarantees
1262 if (canBackupEverything())
1263 return; // yes, because we can back everything up
1265 disableRetries(); // no, because we cannot back everything up
1268 // Normally, the body-writing code handles preview body. It can deal with
1269 // bodies of unexpected size, including those that turn out to be empty.
1270 // However, that code assumes that the body was expected and body control
1271 // structures were initialized. This is not the case when there is no body
1272 // or the body is known to be empty, because the virgin message will lack a
1273 // body_pipe. So we handle preview of null-body and zero-size bodies here.
1274 void ICAPModXact::finishNullOrEmptyBodyPreview(MemBuf
&buf
)
1276 Must(!virginBodyWriting
.active()); // one reason we handle it here
1277 Must(!virgin
.body_pipe
); // another reason we handle it here
1278 Must(!preview
.ad());
1280 // do not add last-chunk because our Encapsulated header says null-body
1281 // addLastRequestChunk(buf);
1282 preview
.wrote(0, true);
1284 Must(preview
.done());
1285 Must(preview
.ieof());
1288 void ICAPModXact::fillPendingStatus(MemBuf
&buf
) const
1290 ICAPXaction::fillPendingStatus(buf
);
1292 if (state
.serviceWaiting
)
1295 if (virgin
.body_pipe
!= NULL
)
1298 if (connection
> 0 && !doneReading())
1301 if (!state
.doneWriting() && state
.writing
!= State::writingInit
)
1302 buf
.Printf("w(%d)", state
.writing
);
1304 if (preview
.enabled()) {
1305 if (!preview
.done())
1306 buf
.Printf("P(%d)", (int) preview
.debt());
1309 if (virginBodySending
.active())
1312 if (!state
.doneParsing() && state
.parsing
!= State::psIcapHeader
)
1313 buf
.Printf("p(%d)", state
.parsing
);
1315 if (!doneSending() && state
.sending
!= State::sendingUndecided
)
1316 buf
.Printf("S(%d)", state
.sending
);
1322 void ICAPModXact::fillDoneStatus(MemBuf
&buf
) const
1324 ICAPXaction::fillDoneStatus(buf
);
1326 if (!virgin
.body_pipe
)
1329 if (state
.doneWriting())
1332 if (preview
.enabled()) {
1334 buf
.Printf("P%s", preview
.ieof() ? "(ieof)" : "");
1340 if (state
.doneParsing())
1347 bool ICAPModXact::gotEncapsulated(const char *section
) const
1349 return icapReply
->header
.getByNameListMember("Encapsulated",
1350 section
, ',').size() > 0;
1353 // calculate whether there is a virgin HTTP body and
1354 // whether its expected size is known
1355 // TODO: rename because we do not just estimate
1356 void ICAPModXact::estimateVirginBody()
1358 // note: lack of size info may disable previews and 204s
1360 HttpMsg
*msg
= virgin
.header
;
1366 method
= virgin
.cause
->method
;
1368 if (HttpRequest
*req
= dynamic_cast<HttpRequest
*>(msg
))
1369 method
= req
->method
;
1371 method
= METHOD_NONE
;
1374 // expectingBody returns true for zero-sized bodies, but we will not
1375 // get a pipe for that body, so we treat the message as bodyless
1376 if (method
!= METHOD_NONE
&& msg
->expectingBody(method
, size
) && size
) {
1377 debugs(93, 6, "ICAPModXact expects virgin body from " <<
1378 virgin
.body_pipe
<< "; size: " << size
);
1380 virginBody
.expect(size
);
1381 virginBodyWriting
.plan();
1383 // sign up as a body consumer
1384 Must(msg
->body_pipe
!= NULL
);
1385 Must(msg
->body_pipe
== virgin
.body_pipe
);
1386 Must(virgin
.body_pipe
->setConsumerIfNotLate(this));
1388 // make sure TheBackupLimit is in-sync with the buffer size
1389 Must(TheBackupLimit
<= static_cast<size_t>(msg
->body_pipe
->buf().max_capacity
));
1391 debugs(93, 6, "ICAPModXact does not expect virgin body");
1392 Must(msg
->body_pipe
== NULL
);
1397 void ICAPModXact::makeAdaptedBodyPipe(const char *what
) {
1398 Must(!adapted
.body_pipe
);
1399 Must(!adapted
.header
->body_pipe
);
1400 adapted
.header
->body_pipe
= new BodyPipe(this);
1401 adapted
.body_pipe
= adapted
.header
->body_pipe
;
1402 debugs(93, 7, HERE
<< "will supply " << what
<< " via " <<
1403 adapted
.body_pipe
<< " pipe");
1407 // TODO: Move SizedEstimate, MemBufBackup, and ICAPPreview elsewhere
1409 SizedEstimate::SizedEstimate()
1410 : theData(dtUnexpected
)
1413 void SizedEstimate::expect(ssize_t aSize
)
1415 theData
= (aSize
>= 0) ? aSize
: (ssize_t
)dtUnknown
;
1418 bool SizedEstimate::expected() const
1420 return theData
!= dtUnexpected
;
1423 bool SizedEstimate::knownSize() const
1426 return theData
!= dtUnknown
;
1429 size_t SizedEstimate::size() const
1432 return static_cast<size_t>(theData
);
1437 VirginBodyAct::VirginBodyAct(): theStart(0), theState(stUndecided
)
1440 void VirginBodyAct::plan()
1443 Must(!theStart
); // not started
1444 theState
= stActive
;
1447 void VirginBodyAct::disable()
1449 theState
= stDisabled
;
1452 void VirginBodyAct::progress(size_t size
)
1459 size_t VirginBodyAct::offset() const
1466 ICAPPreview::ICAPPreview(): theWritten(0), theAd(0), theState(stDisabled
)
1469 void ICAPPreview::enable(size_t anAd
)
1471 // TODO: check for anAd not exceeding preview size limit
1475 theState
= stWriting
;
1478 bool ICAPPreview::enabled() const
1480 return theState
!= stDisabled
;
1483 size_t ICAPPreview::ad() const
1489 bool ICAPPreview::done() const
1492 return theState
>= stIeof
;
1495 bool ICAPPreview::ieof() const
1498 return theState
== stIeof
;
1501 size_t ICAPPreview::debt() const
1504 return done() ? 0 : (theAd
- theWritten
);
1507 void ICAPPreview::wrote(size_t size
, bool wroteEof
)
1513 Must(theWritten
<= theAd
);
1516 theState
= stIeof
; // written size is irrelevant
1518 if (theWritten
>= theAd
)
1522 bool ICAPModXact::fillVirginHttpHeader(MemBuf
&mb
) const
1524 if (virgin
.header
== NULL
)
1527 virgin
.header
->firstLineBuf(mb
);
1533 /* ICAPModXactLauncher */
1535 ICAPModXactLauncher::ICAPModXactLauncher(ICAPInitiator
*anInitiator
, HttpMsg
*virginHeader
, HttpRequest
*virginCause
, ICAPServiceRep::Pointer
&aService
):
1536 ICAPLauncher("ICAPModXactLauncher", anInitiator
, aService
)
1538 virgin
.setHeader(virginHeader
);
1539 virgin
.setCause(virginCause
);
1542 ICAPXaction
*ICAPModXactLauncher::createXaction()
1544 return new ICAPModXact(this, virgin
.header
, virgin
.cause
, theService
);