2 * $Id: Server.cc,v 1.26 2008/02/18 22:51:21 rousskov Exp $
5 * AUTHOR: Duane Wessels
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #include "HttpRequest.h"
39 #include "HttpReply.h"
40 #include "TextException.h"
41 #include "errorpage.h"
44 #include "adaptation/AccessCheck.h"
45 #include "adaptation/Service.h"
48 // implemented in client_side_reply.cc until sides have a common parent
49 extern void purgeEntriesByUrl(HttpRequest
* req
, const char *url
);
52 ServerStateData::ServerStateData(FwdState
*theFwdState
): AsyncJob("ServerStateData"),requestSender(NULL
)
54 , adaptedHeadSource(NULL
)
55 , adaptationAccessCheckPending(false)
56 , startedAdaptation(false)
64 request
= HTTPMSGLOCK(fwd
->request
);
67 ServerStateData::~ServerStateData()
69 // paranoid: check that swanSong has been called
70 assert(!requestBodySource
);
72 assert(!virginBodyDestination
);
73 assert(!adaptedBodySource
);
78 HTTPMSGUNLOCK(request
);
79 HTTPMSGUNLOCK(theVirginReply
);
80 HTTPMSGUNLOCK(theFinalReply
);
82 fwd
= NULL
; // refcounted
84 if (responseBodyBuffer
!= NULL
) {
85 delete responseBodyBuffer
;
86 responseBodyBuffer
= NULL
;
91 ServerStateData::swanSong()
93 // get rid of our piping obligations
94 if (requestBodySource
!= NULL
)
95 requestBodySource
->clearConsumer();
101 BodyConsumer::swanSong();
103 Initiator::swanSong();
104 BodyProducer::swanSong();
110 ServerStateData::virginReply() {
111 assert(theVirginReply
);
112 return theVirginReply
;
116 ServerStateData::virginReply() const {
117 assert(theVirginReply
);
118 return theVirginReply
;
122 ServerStateData::setVirginReply(HttpReply
*rep
) {
123 debugs(11,5, HERE
<< this << " setting virgin reply to " << rep
);
124 assert(!theVirginReply
);
126 theVirginReply
= HTTPMSGLOCK(rep
);
127 return theVirginReply
;
131 ServerStateData::finalReply() {
132 assert(theFinalReply
);
133 return theFinalReply
;
137 ServerStateData::setFinalReply(HttpReply
*rep
) {
138 debugs(11,5, HERE
<< this << " setting final reply to " << rep
);
140 assert(!theFinalReply
);
142 theFinalReply
= HTTPMSGLOCK(rep
);
144 entry
->replaceHttpReply(theFinalReply
);
145 haveParsedReplyHeaders();
147 return theFinalReply
;
150 // called when no more server communication is expected; may quit
152 ServerStateData::serverComplete()
154 debugs(11,5,HERE
<< "serverComplete " << this);
156 if (!doneWithServer()) {
158 assert(doneWithServer());
163 if (requestBodySource
!= NULL
)
164 stopConsumingFrom(requestBodySource
);
166 if (responseBodyBuffer
!= NULL
)
173 ServerStateData::serverComplete2()
175 debugs(11,5,HERE
<< "serverComplete2 " << this);
178 if (virginBodyDestination
!= NULL
)
179 stopProducingFor(virginBodyDestination
, true);
181 if (!doneWithAdaptation())
185 completeForwarding();
189 // When we are done talking to the primary server, we may be still talking
190 // to the ICAP service. And vice versa. Here, we quit only if we are done
192 void ServerStateData::quitIfAllDone() {
194 if (!doneWithAdaptation()) {
195 debugs(11,5, HERE
<< "transaction not done: still talking to ICAP");
200 if (!doneWithServer()) {
201 debugs(11,5, HERE
<< "transaction not done: still talking to server");
205 debugs(11,3, HERE
<< "transaction done");
207 deleteThis("ServerStateData::quitIfAllDone");
210 // FTP side overloads this to work around multiple calls to fwd->complete
212 ServerStateData::completeForwarding() {
213 debugs(11,5, HERE
<< "completing forwarding for " << fwd
);
218 // Register to receive request body
219 bool ServerStateData::startRequestBodyFlow()
221 HttpRequest
*r
= originalRequest();
222 assert(r
->body_pipe
!= NULL
);
223 requestBodySource
= r
->body_pipe
;
224 if (requestBodySource
->setConsumerIfNotLate(this)) {
225 debugs(11,3, HERE
<< "expecting request body from " <<
226 requestBodySource
->status());
230 debugs(11,3, HERE
<< "aborting on partially consumed request body: " <<
231 requestBodySource
->status());
232 requestBodySource
= NULL
;
236 // Entry-dependent callbacks use this check to quit if the entry went bad
238 ServerStateData::abortOnBadEntry(const char *abortReason
)
240 if (entry
->isAccepting())
243 debugs(11,5, HERE
<< "entry is not Accepting!");
244 abortTransaction(abortReason
);
248 // more request or adapted response body is available
250 ServerStateData::noteMoreBodyDataAvailable(BodyPipe::Pointer bp
)
253 if (adaptedBodySource
== bp
) {
254 handleMoreAdaptedBodyAvailable();
258 handleMoreRequestBodyAvailable();
261 // the entire request or adapted response body was provided, successfully
263 ServerStateData::noteBodyProductionEnded(BodyPipe::Pointer bp
)
266 if (adaptedBodySource
== bp
) {
267 handleAdaptedBodyProductionEnded();
271 handleRequestBodyProductionEnded();
274 // premature end of the request or adapted response body production
276 ServerStateData::noteBodyProducerAborted(BodyPipe::Pointer bp
)
279 if (adaptedBodySource
== bp
) {
280 handleAdaptedBodyProducerAborted();
284 handleRequestBodyProducerAborted();
288 // more origin request body data is available
290 ServerStateData::handleMoreRequestBodyAvailable()
293 sendMoreRequestBody();
295 debugs(9,3, HERE
<< "waiting for request body write to complete");
298 // there will be no more handleMoreRequestBodyAvailable calls
300 ServerStateData::handleRequestBodyProductionEnded()
303 doneSendingRequestBody();
305 debugs(9,3, HERE
<< "waiting for request body write to complete");
308 // called when we are done sending request body; kids extend this
310 ServerStateData::doneSendingRequestBody() {
311 debugs(9,3, HERE
<< "done sending request body");
312 assert(requestBodySource
!= NULL
);
313 stopConsumingFrom(requestBodySource
);
318 // called when body producers aborts; kids extend this
320 ServerStateData::handleRequestBodyProducerAborted()
322 if (requestSender
!= NULL
)
323 debugs(9,3, HERE
<< "fyi: request body aborted while we were sending");
325 fwd
->dontRetry(true); // the problem is not with the server
326 stopConsumingFrom(requestBodySource
); // requestSender, if any, will notice
331 // called when we wrote request headers(!) or a part of the body
333 ServerStateData::sentRequestBody(const CommIoCbParams
&io
)
335 debugs(11, 5, "sentRequestBody: FD " << io
.fd
<< ": size " << io
.size
<< ": errflag " << io
.flag
<< ".");
336 debugs(32,3,HERE
<< "sentRequestBody called");
338 requestSender
= NULL
;
341 fd_bytes(io
.fd
, io
.size
, FD_WRITE
);
342 kb_incr(&statCounter
.server
.all
.kbytes_out
, io
.size
);
343 // kids should increment their counters
346 if (io
.flag
== COMM_ERR_CLOSING
)
349 if (!requestBodySource
) {
350 debugs(9,3, HERE
<< "detected while-we-were-sending abort");
351 return; // do nothing;
355 debugs(11, 1, "sentRequestBody error: FD " << io
.fd
<< ": " << xstrerr(errno
));
357 err
= errorCon(ERR_WRITE_ERROR
, HTTP_BAD_GATEWAY
, fwd
->request
);
360 abortTransaction("I/O error while sending request body");
364 if (EBIT_TEST(entry
->flags
, ENTRY_ABORTED
)) {
365 abortTransaction("store entry aborted while sending request body");
369 if (requestBodySource
->exhausted())
370 doneSendingRequestBody();
372 sendMoreRequestBody();
376 ServerStateData::sendMoreRequestBody()
378 assert(requestBodySource
!= NULL
);
379 assert(!requestSender
);
381 if (requestBodySource
->getMoreData(buf
)) {
382 debugs(9,3, HERE
<< "will write " << buf
.contentSize() << " request body bytes");
383 typedef CommCbMemFunT
<ServerStateData
, CommIoCbParams
> Dialer
;
384 requestSender
= asyncCall(93,3, "ServerStateData::sentRequestBody",
385 Dialer(this, &ServerStateData::sentRequestBody
));
386 comm_write_mbuf(dataDescriptor(), &buf
, requestSender
);
388 debugs(9,3, HERE
<< "will wait for more request body bytes or eof");
389 requestSender
= NULL
;
393 // Compares hosts in urls, returns false if different, no sheme, or no host.
395 sameUrlHosts(const char *url1
, const char *url2
)
397 // XXX: Want urlHostname() here, but it uses static storage and copying
398 const char *host1
= strchr(url1
, ':');
399 const char *host2
= strchr(url2
, ':');
401 if (host1
&& host2
) {
402 // skip scheme slashes
406 } while (*host1
== '/' && *host2
== '/');
409 return false; // no host
411 // increment while the same until we reach the end of the URL/host
412 while (*host1
&& *host1
!= '/' && *host1
== *host2
) {
416 return *host1
== *host2
;
419 return false; // no URL scheme
422 // purges entries that match the value of a given HTTP [response] header
424 purgeEntriesByHeader(HttpRequest
*req
, const char *reqUrl
, HttpMsg
*rep
, http_hdr_type hdr
)
426 const char *hdrUrl
, *absUrl
;
429 hdrUrl
= rep
->header
.getStr(hdr
);
430 if (hdrUrl
== NULL
) {
435 * If the URL is relative, make it absolute so we can find it.
436 * If it's absolute, make sure the host parts match to avoid DOS attacks
437 * as per RFC 2616 13.10.
439 if (urlIsRelative(hdrUrl
)) {
440 absUrl
= urlMakeAbsolute(req
, hdrUrl
);
441 if (absUrl
!= NULL
) {
444 } else if (!sameUrlHosts(reqUrl
, hdrUrl
)) {
448 purgeEntriesByUrl(req
, hdrUrl
);
450 if (absUrl
!= NULL
) {
455 // some HTTP methods should purge matching cache entries
457 ServerStateData::maybePurgeOthers()
459 // only some HTTP methods should purge matching cache entries
460 if (!request
->method
.purgesOthers())
463 // and probably only if the response was successful
464 if (theFinalReply
->sline
.status
>= 400)
467 // XXX: should we use originalRequest() here?
468 const char *reqUrl
= urlCanonical(request
);
469 debugs(88, 5, "maybe purging due to " << RequestMethodStr(request
->method
) << ' ' << reqUrl
);
470 purgeEntriesByUrl(request
, reqUrl
);
471 purgeEntriesByHeader(request
, reqUrl
, theFinalReply
, HDR_LOCATION
);
472 purgeEntriesByHeader(request
, reqUrl
, theFinalReply
, HDR_CONTENT_LOCATION
);
475 // called (usually by kids) when we have final (possibly adapted) reply headers
477 ServerStateData::haveParsedReplyHeaders()
484 ServerStateData::originalRequest()
491 * Initiate an ICAP transaction. Return true on success.
492 * Caller will handle error condition by generating a Squid error message
493 * or take other action.
496 ServerStateData::startAdaptation(Adaptation::ServicePointer service
, HttpRequest
*cause
)
498 debugs(11, 5, "ServerStateData::startAdaptation() called");
500 debugs(11, 3, "ServerStateData::startAdaptation fails: lack of service");
503 if (service
->broken()) {
504 debugs(11, 3, "ServerStateData::startAdaptation fails: broken service");
508 // check whether we should be sending a body as well
509 // start body pipe to feed ICAP transaction if needed
510 assert(!virginBodyDestination
);
511 HttpReply
*vrep
= virginReply();
512 assert(!vrep
->body_pipe
);
514 if (vrep
->expectingBody(cause
->method
, size
) && size
) {
515 virginBodyDestination
= new BodyPipe(this);
516 vrep
->body_pipe
= virginBodyDestination
;
517 debugs(93, 6, HERE
<< "will send virgin reply body to " <<
518 virginBodyDestination
<< "; size: " << size
);
520 virginBodyDestination
->setBodySize(size
);
523 adaptedHeadSource
= initiateAdaptation(service
->makeXactLauncher(
525 return adaptedHeadSource
!= NULL
;
528 // properly cleans up ICAP-related state
529 // may be called multiple times
530 void ServerStateData::cleanAdaptation() {
531 debugs(11,5, HERE
<< "cleaning ICAP; ACL: " << adaptationAccessCheckPending
);
533 if (virginBodyDestination
!= NULL
)
534 stopProducingFor(virginBodyDestination
, false);
536 announceInitiatorAbort(adaptedHeadSource
);
538 if (adaptedBodySource
!= NULL
)
539 stopConsumingFrom(adaptedBodySource
);
541 if (!adaptationAccessCheckPending
) // we cannot cancel a pending callback
542 assert(doneWithAdaptation()); // make sure the two methods are in sync
546 ServerStateData::doneWithAdaptation() const {
547 return !adaptationAccessCheckPending
&&
548 !virginBodyDestination
&& !adaptedHeadSource
&& !adaptedBodySource
;
551 // sends virgin reply body to ICAP, buffering excesses if needed
553 ServerStateData::adaptVirginReplyBody(const char *data
, ssize_t len
)
555 assert(startedAdaptation
);
557 if (!virginBodyDestination
) {
558 debugs(11,3, HERE
<< "ICAP does not want more virgin body");
562 // grow overflow area if already overflowed
563 if (responseBodyBuffer
) {
564 responseBodyBuffer
->append(data
, len
);
565 data
= responseBodyBuffer
->content();
566 len
= responseBodyBuffer
->contentSize();
569 const ssize_t putSize
= virginBodyDestination
->putMoreData(data
, len
);
573 // if we had overflow area, shrink it as necessary
574 if (responseBodyBuffer
) {
575 if (putSize
== responseBodyBuffer
->contentSize()) {
576 delete responseBodyBuffer
;
577 responseBodyBuffer
= NULL
;
579 responseBodyBuffer
->consume(putSize
);
584 // if we did not have an overflow area, create it as needed
586 assert(!responseBodyBuffer
);
587 responseBodyBuffer
= new MemBuf
;
588 responseBodyBuffer
->init(4096, SQUID_TCP_SO_RCVBUF
* 10);
589 responseBodyBuffer
->append(data
, len
);
593 // can supply more virgin response body data
595 ServerStateData::noteMoreBodySpaceAvailable(BodyPipe::Pointer
)
597 if (responseBodyBuffer
) {
598 addVirginReplyBody(NULL
, 0); // kick the buffered fragment alive again
599 if (completed
&& !responseBodyBuffer
) {
604 maybeReadVirginBody();
607 // the consumer of our virgin response body aborted
609 ServerStateData::noteBodyConsumerAborted(BodyPipe::Pointer
)
611 stopProducingFor(virginBodyDestination
, false);
613 // do not force closeServer here in case we need to bypass AdaptationQueryAbort
615 if (doneWithAdaptation()) // we may still be receiving adapted response
616 handleAdaptationCompleted();
619 // received adapted response headers (body may follow)
621 ServerStateData::noteAdaptationAnswer(HttpMsg
*msg
)
623 clearAdaptation(adaptedHeadSource
); // we do not expect more messages
625 if (abortOnBadEntry("entry went bad while waiting for adapted headers"))
628 HttpReply
*rep
= dynamic_cast<HttpReply
*>(msg
);
630 debugs(11,5, HERE
<< this << " setting adapted reply to " << rep
);
633 assert(!adaptedBodySource
);
634 if (rep
->body_pipe
!= NULL
) {
635 // subscribe to receive adapted body
636 adaptedBodySource
= rep
->body_pipe
;
637 // assume that ICAP does not auto-consume on failures
638 assert(adaptedBodySource
->setConsumerIfNotLate(this));
641 if (doneWithAdaptation()) // we may still be sending virgin response
642 handleAdaptationCompleted();
646 // will not receive adapted response headers (and, hence, body)
648 ServerStateData::noteAdaptationQueryAbort(bool final
)
650 clearAdaptation(adaptedHeadSource
);
651 handleAdaptationAborted(!final
);
654 // more adapted response body is available
656 ServerStateData::handleMoreAdaptedBodyAvailable()
658 const size_t contentSize
= adaptedBodySource
->buf().contentSize();
660 debugs(11,5, HERE
<< "consuming " << contentSize
<< " bytes of adapted " <<
661 "response body at offset " << adaptedBodySource
->consumedSize());
663 if (abortOnBadEntry("entry refuses adapted body"))
667 BodyPipeCheckout
bpc(*adaptedBodySource
);
668 const StoreIOBuffer
ioBuf(&bpc
.buf
, bpc
.offset
);
670 bpc
.buf
.consume(contentSize
);
674 // the entire adapted response body was produced, successfully
676 ServerStateData::handleAdaptedBodyProductionEnded()
678 stopConsumingFrom(adaptedBodySource
);
680 if (abortOnBadEntry("entry went bad while waiting for adapted body eof"))
683 handleAdaptationCompleted();
686 // premature end of the adapted response body
687 void ServerStateData::handleAdaptedBodyProducerAborted()
689 stopConsumingFrom(adaptedBodySource
);
690 handleAdaptationAborted();
693 // common part of noteAdaptationAnswer and handleAdaptedBodyProductionEnded
695 ServerStateData::handleAdaptationCompleted()
697 debugs(11,5, HERE
<< "handleAdaptationCompleted");
700 // We stop reading origin response because we have no place to put it and
701 // cannot use it. If some origin servers do not like that or if we want to
702 // reuse more pconns, we can add code to discard unneeded origin responses.
703 if (!doneWithServer()) {
704 debugs(11,3, HERE
<< "closing origin conn due to ICAP completion");
708 completeForwarding();
713 // common part of noteAdaptation*Aborted and noteBodyConsumerAborted methods
715 ServerStateData::handleAdaptationAborted(bool bypassable
)
717 debugs(11,5, HERE
<< "handleAdaptationAborted; bypassable: " << bypassable
<<
718 ", entry empty: " << entry
->isEmpty());
720 if (abortOnBadEntry("entry went bad while ICAP aborted"))
723 // TODO: bypass if possible
725 if (entry
->isEmpty()) {
726 debugs(11,9, HERE
<< "creating ICAP error entry after ICAP failure");
727 ErrorState
*err
= errorCon(ERR_ICAP_FAILURE
, HTTP_INTERNAL_SERVER_ERROR
, request
);
730 fwd
->dontRetry(true);
733 abortTransaction("ICAP failure");
737 ServerStateData::adaptationAclCheckDone(Adaptation::ServicePointer service
)
739 adaptationAccessCheckPending
= false;
741 if (abortOnBadEntry("entry went bad while waiting for ICAP ACL check"))
744 // TODO: Should nonICAP and postICAP path check this on the server-side?
745 // That check now only happens on client-side, in processReplyAccess().
746 if (virginReply()->expectedBodyTooLarge(*request
)) {
747 sendBodyIsTooLargeError();
750 // TODO: Should we check receivedBodyTooLarge on the server-side as well?
752 startedAdaptation
= startAdaptation(service
, originalRequest());
754 if (!startedAdaptation
&& (!service
|| service
->cfg().bypass
)) {
755 // handle ICAP start failure when no service was selected
756 // or where the selected service was optional
757 setFinalReply(virginReply());
762 if (!startedAdaptation
) {
763 // handle start failure for an essential ICAP service
764 ErrorState
*err
= errorCon(ERR_ICAP_FAILURE
,
765 HTTP_INTERNAL_SERVER_ERROR
, originalRequest());
767 errorAppendEntry(entry
, err
);
768 abortTransaction("ICAP start failure");
776 ServerStateData::adaptationAclCheckDoneWrapper(Adaptation::ServicePointer service
, void *data
)
778 ServerStateData
*state
= (ServerStateData
*)data
;
779 state
->adaptationAclCheckDone(service
);
784 ServerStateData::sendBodyIsTooLargeError()
786 ErrorState
*err
= errorCon(ERR_TOO_BIG
, HTTP_FORBIDDEN
, request
);
789 fwd
->dontRetry(true);
790 abortTransaction("Virgin body too large.");
793 // TODO: when HttpStateData sends all errors to ICAP,
794 // we should be able to move this at the end of setVirginReply().
796 ServerStateData::adaptOrFinalizeReply()
799 // TODO: merge with client side and return void to hide the on/off logic?
800 // The callback can be called with a NULL service if adaptation is off.
801 adaptationAccessCheckPending
= Adaptation::AccessCheck::Start(
802 Adaptation::methodRespmod
, Adaptation::pointPreCache
,
803 request
, virginReply(), adaptationAclCheckDoneWrapper
, this);
804 if (adaptationAccessCheckPending
)
808 setFinalReply(virginReply());
812 ServerStateData::addVirginReplyBody(const char *data
, ssize_t len
)
815 assert(!adaptationAccessCheckPending
); // or would need to buffer while waiting
816 if (startedAdaptation
) {
817 adaptVirginReplyBody(data
, len
);
821 storeReplyBody(data
, len
);
824 // writes virgin or adapted reply body to store
826 ServerStateData::storeReplyBody(const char *data
, ssize_t len
)
828 // write even if len is zero to push headers towards the client side
829 entry
->write (StoreIOBuffer(len
, currentOffset
, (char*)data
));
831 currentOffset
+= len
;
834 size_t ServerStateData::replyBodySpace(size_t space
)
837 if (responseBodyBuffer
) {
838 return 0; // Stop reading if already overflowed waiting for ICAP to catch up
841 if (virginBodyDestination
!= NULL
) {
843 * BodyPipe buffer has a finite size limit. We
844 * should not read more data from the network than will fit
845 * into the pipe buffer or we _lose_ what did not fit if
846 * the response ends sooner that BodyPipe frees up space:
847 * There is no code to keep pumping data into the pipe once
848 * response ends and serverComplete() is called.
850 * If the pipe is totally full, don't register the read handler.
851 * The BodyPipe will call our noteMoreBodySpaceAvailable() method
852 * when it has free space again.
854 size_t adaptation_space
=
855 virginBodyDestination
->buf().potentialSpaceSize();
857 debugs(11,9, "ServerStateData may read up to min(" <<
858 adaptation_space
<< ", " << space
<< ") bytes");
860 if (adaptation_space
< space
)
861 space
= adaptation_space
;