]> git.ipfire.org Git - thirdparty/squid.git/blame - src/Server.cc
Fix compile error introduced earlier 'unknown assert()'.
[thirdparty/squid.git] / src / Server.cc
CommitLineData
cd304fc2 1/*
2d1a172f 2 * $Id: Server.cc,v 1.19 2007/08/01 04:18:08 rousskov Exp $
cd304fc2 3 *
4 * DEBUG:
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
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.
18 *
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.
23 *
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.
28 *
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.
32 *
33 */
34
35#include "squid.h"
36#include "Server.h"
37#include "Store.h"
38#include "HttpRequest.h"
39#include "HttpReply.h"
5f8252d2 40#include "errorpage.h"
41
0f283edf 42#if ICAP_CLIENT
43#include "ICAP/ICAPModXact.h"
7dc79973 44#include "ICAP/ICAPConfig.h"
45extern ICAPConfig TheICAPConfig;
0f283edf 46#endif
cd304fc2 47
77089558 48ServerStateData::ServerStateData(FwdState *theFwdState): requestSender(NULL)
49#if ICAP_CLIENT
50 , icapAccessCheckPending(false)
51#endif
cd304fc2 52{
53 fwd = theFwdState;
54 entry = fwd->entry;
34266cde 55
5f8252d2 56 entry->lock();
34266cde 57
6dd9f4bd 58 request = HTTPMSGLOCK(fwd->request);
cd304fc2 59}
60
61ServerStateData::~ServerStateData()
62{
97b5e68f 63 entry->unlock();
cd304fc2 64
6dd9f4bd 65 HTTPMSGUNLOCK(request);
66 HTTPMSGUNLOCK(reply);
cd304fc2 67
68 fwd = NULL; // refcounted
69
5f8252d2 70 if (requestBodySource != NULL)
71 requestBodySource->clearConsumer();
72
73#if ICAP_CLIENT
74 cleanIcap();
75#endif
7dc79973 76
77 if (responseBodyBuffer != NULL) {
78 delete responseBodyBuffer;
79 responseBodyBuffer = NULL;
80 }
5f8252d2 81}
82
83// called when no more server communication is expected; may quit
84void
85ServerStateData::serverComplete()
86{
87 debugs(11,5,HERE << "serverComplete " << this);
88
89 if (!doneWithServer()) {
90 closeServer();
91 assert(doneWithServer());
92 }
93
7dc79973 94 completed = true;
95
5f8252d2 96 if (requestBodySource != NULL)
97 stopConsumingFrom(requestBodySource);
98
7dc79973 99 if (responseBodyBuffer != NULL)
100 return;
101
102 serverComplete2();
103}
104
105void
106ServerStateData::serverComplete2()
107{
108 debugs(11,5,HERE << "serverComplete2 " << this);
109
5f8252d2 110#if ICAP_CLIENT
111 if (virginBodyDestination != NULL)
112 stopProducingFor(virginBodyDestination, true);
113
114 if (!doneWithIcap())
115 return;
116#endif
117
118 completeForwarding();
119 quitIfAllDone();
120}
121
122// When we are done talking to the primary server, we may be still talking
123// to the ICAP service. And vice versa. Here, we quit only if we are done
124// talking to both.
125void ServerStateData::quitIfAllDone() {
126#if ICAP_CLIENT
127 if (!doneWithIcap()) {
128 debugs(11,5, HERE << "transaction not done: still talking to ICAP");
129 return;
130 }
131#endif
132
133 if (!doneWithServer()) {
134 debugs(11,5, HERE << "transaction not done: still talking to server");
135 return;
136 }
137
138 debugs(11,3, HERE << "transaction done");
139 delete this;
140}
141
142// FTP side overloads this to work around multiple calls to fwd->complete
143void
144ServerStateData::completeForwarding() {
145 debugs(11,5, HERE << "completing forwarding for " << fwd);
146 assert(fwd != NULL);
147 fwd->complete();
148}
149
150// Entry-dependent callbacks use this check to quit if the entry went bad
151bool
152ServerStateData::abortOnBadEntry(const char *abortReason)
153{
154 if (entry->isAccepting())
155 return false;
156
157 debugs(11,5, HERE << "entry is not Accepting!");
158 abortTransaction(abortReason);
159 return true;
160}
161
162// more request or adapted response body is available
163void
164ServerStateData::noteMoreBodyDataAvailable(BodyPipe &bp)
165{
166#if ICAP_CLIENT
167 if (adaptedBodySource == &bp) {
168 handleMoreAdaptedBodyAvailable();
169 return;
170 }
171#endif
172 handleMoreRequestBodyAvailable();
173}
174
175// the entire request or adapted response body was provided, successfully
176void
177ServerStateData::noteBodyProductionEnded(BodyPipe &bp)
178{
cd304fc2 179#if ICAP_CLIENT
5f8252d2 180 if (adaptedBodySource == &bp) {
181 handleAdaptedBodyProductionEnded();
182 return;
c99de607 183 }
cd304fc2 184#endif
5f8252d2 185 handleRequestBodyProductionEnded();
186}
187
188// premature end of the request or adapted response body production
189void
190ServerStateData::noteBodyProducerAborted(BodyPipe &bp)
191{
192#if ICAP_CLIENT
193 if (adaptedBodySource == &bp) {
194 handleAdaptedBodyProducerAborted();
195 return;
196 }
197#endif
198 handleRequestBodyProducerAborted();
199}
200
201
202// more origin request body data is available
203void
204ServerStateData::handleMoreRequestBodyAvailable()
205{
206 if (!requestSender)
207 sendMoreRequestBody();
208 else
209 debugs(9,3, HERE << "waiting for request body write to complete");
210}
211
212// there will be no more handleMoreRequestBodyAvailable calls
213void
214ServerStateData::handleRequestBodyProductionEnded()
215{
216 if (!requestSender)
217 doneSendingRequestBody();
218 else
219 debugs(9,3, HERE << "waiting for request body write to complete");
220}
221
222// called when we are done sending request body; kids extend this
223void
224ServerStateData::doneSendingRequestBody() {
225 debugs(9,3, HERE << "done sending request body");
226 assert(requestBodySource != NULL);
227 stopConsumingFrom(requestBodySource);
228
229 // kids extend this
230}
231
232// called when body producers aborts; kids extend this
233void
234ServerStateData::handleRequestBodyProducerAborted()
235{
236 if (requestSender != NULL)
237 debugs(9,3, HERE << "fyi: request body aborted while we were sending");
238
0919c51e 239 fwd->dontRetry(true); // the problem is not with the server
5f8252d2 240 stopConsumingFrom(requestBodySource); // requestSender, if any, will notice
241
242 // kids extend this
243}
244
245void
246ServerStateData::sentRequestBodyWrapper(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
247{
248 ServerStateData *server = static_cast<ServerStateData *>(data);
249 server->sentRequestBody(fd, size, errflag);
250}
251
252// called when we wrote request headers(!) or a part of the body
253void
254ServerStateData::sentRequestBody(int fd, size_t size, comm_err_t errflag)
255{
4a7a3d56 256 debugs(11, 5, "sentRequestBody: FD " << fd << ": size " << size << ": errflag " << errflag << ".");
5f8252d2 257 debugs(32,3,HERE << "sentRequestBody called");
258
259 requestSender = NULL;
260
261 if (size > 0) {
262 fd_bytes(fd, size, FD_WRITE);
263 kb_incr(&statCounter.server.all.kbytes_out, size);
264 // kids should increment their counters
265 }
266
267 if (errflag == COMM_ERR_CLOSING)
268 return;
269
270 if (!requestBodySource) {
271 debugs(9,3, HERE << "detected while-we-were-sending abort");
272 return; // do nothing;
273 }
274
275 if (errflag) {
bf8fe701 276 debugs(11, 1, "sentRequestBody error: FD " << fd << ": " << xstrerr(errno));
5f8252d2 277 ErrorState *err;
278 err = errorCon(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY, fwd->request);
279 err->xerrno = errno;
280 fwd->fail(err);
281 abortTransaction("I/O error while sending request body");
282 return;
283 }
284
285 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
286 abortTransaction("store entry aborted while sending request body");
287 return;
288 }
289
290 if (requestBodySource->exhausted())
291 doneSendingRequestBody();
292 else
293 sendMoreRequestBody();
cd304fc2 294}
295
5f8252d2 296void
297ServerStateData::sendMoreRequestBody()
298{
299 assert(requestBodySource != NULL);
300 assert(!requestSender);
301 MemBuf buf;
302 if (requestBodySource->getMoreData(buf)) {
303 debugs(9,3, HERE << "will write " << buf.contentSize() << " request body bytes");
304 requestSender = &ServerStateData::sentRequestBodyWrapper;
305 comm_write_mbuf(dataDescriptor(), &buf, requestSender, this);
306 } else {
307 debugs(9,3, HERE << "will wait for more request body bytes or eof");
308 requestSender = NULL;
309 }
310}
311
0f283edf 312// called by noteIcapAnswer(), HTTP server overwrites this
5f8252d2 313void
314ServerStateData::haveParsedReplyHeaders()
315{
316 // default does nothing
317}
318
7dc79973 319HttpRequest *
320ServerStateData::originalRequest()
321{
322 return request;
323}
5f8252d2 324
0c25e715 325#if ICAP_CLIENT
cd304fc2 326/*
c99de607 327 * Initiate an ICAP transaction. Return true on success.
cd304fc2 328 * Caller will handle error condition by generating a Squid error message
329 * or take other action.
330 */
c99de607 331bool
5f8252d2 332ServerStateData::startIcap(ICAPServiceRep::Pointer service, HttpRequest *cause)
cd304fc2 333{
bf8fe701 334 debugs(11, 5, "ServerStateData::startIcap() called");
c99de607 335 if (!service) {
bf8fe701 336 debugs(11, 3, "ServerStateData::startIcap fails: lack of service");
c99de607 337 return false;
338 }
339 if (service->broken()) {
bf8fe701 340 debugs(11, 3, "ServerStateData::startIcap fails: broken service");
c99de607 341 return false;
342 }
5f8252d2 343
344 // check whether we should be sending a body as well
345 assert(!virginBodyDestination);
346 assert(!reply->body_pipe);
347 // start body pipe to feed ICAP transaction if needed
348 ssize_t size = 0;
349 if (reply->expectingBody(cause->method, size) && size) {
350 virginBodyDestination = new BodyPipe(this);
351 reply->body_pipe = virginBodyDestination;
352 debugs(93, 6, HERE << "will send virgin reply body to " <<
353 virginBodyDestination << "; size: " << size);
354 }
355
0f283edf 356 adaptedHeadSource = initiateIcap(
357 new ICAPModXactLauncher(this, reply, cause, service));
c99de607 358 return true;
cd304fc2 359}
0c25e715 360
5f8252d2 361// properly cleans up ICAP-related state
362// may be called multiple times
363void ServerStateData::cleanIcap() {
ba82c452 364 debugs(11,5, HERE << "cleaning ICAP; ACL: " << icapAccessCheckPending);
5f8252d2 365
366 if (virginBodyDestination != NULL)
367 stopProducingFor(virginBodyDestination, false);
368
0f283edf 369 announceInitiatorAbort(adaptedHeadSource);
5f8252d2 370
371 if (adaptedBodySource != NULL)
372 stopConsumingFrom(adaptedBodySource);
373
ba82c452 374 if (!icapAccessCheckPending) // we cannot cancel a pending callback
375 assert(doneWithIcap()); // make sure the two methods are in sync
5f8252d2 376}
377
378bool
379ServerStateData::doneWithIcap() const {
ba82c452 380 return !icapAccessCheckPending &&
381 !virginBodyDestination && !adaptedHeadSource && !adaptedBodySource;
5f8252d2 382}
383
bc81cb2b 384// sends virgin reply body to ICAP, buffering excesses if needed
385void
386ServerStateData::adaptVirginReplyBody(const char *data, ssize_t len)
387{
388 assert(startedIcap);
389
390 if (!virginBodyDestination) {
391 debugs(11,3, HERE << "ICAP does not want more virgin body");
392 return;
393 }
394
395 // grow overflow area if already overflowed
396 if (responseBodyBuffer) {
397 responseBodyBuffer->append(data, len);
398 data = responseBodyBuffer->content();
399 len = responseBodyBuffer->contentSize();
400 }
401
402 const ssize_t putSize = virginBodyDestination->putMoreData(data, len);
403 data += putSize;
404 len -= putSize;
405
406 // if we had overflow area, shrink it as necessary
407 if (responseBodyBuffer) {
408 if (putSize == responseBodyBuffer->contentSize()) {
409 delete responseBodyBuffer;
410 responseBodyBuffer = NULL;
411 } else {
412 responseBodyBuffer->consume(putSize);
413 }
414 return;
415 }
416
417 // if we did not have an overflow area, create it as needed
418 if (len > 0) {
419 assert(!responseBodyBuffer);
420 responseBodyBuffer = new MemBuf;
421 responseBodyBuffer->init(4096, SQUID_TCP_SO_RCVBUF * 10);
422 responseBodyBuffer->append(data, len);
423 }
424}
425
5f8252d2 426// can supply more virgin response body data
427void
428ServerStateData::noteMoreBodySpaceAvailable(BodyPipe &)
429{
7dc79973 430 if (responseBodyBuffer) {
bc81cb2b 431 addVirginReplyBody(NULL, 0); // kick the buffered fragment alive again
432 if (completed && !responseBodyBuffer) {
433 serverComplete2();
434 return;
435 }
7dc79973 436 }
5f8252d2 437 maybeReadVirginBody();
438}
439
bc81cb2b 440// the consumer of our virgin response body aborted
5f8252d2 441void
442ServerStateData::noteBodyConsumerAborted(BodyPipe &bp)
443{
444 stopProducingFor(virginBodyDestination, false);
bc81cb2b 445
446 // do not force closeServer here in case we need to bypass IcapQueryAbort
447
448 if (doneWithIcap()) // we may still be receiving adapted response
449 handleIcapCompleted();
5f8252d2 450}
451
452// received adapted response headers (body may follow)
453void
0f283edf 454ServerStateData::noteIcapAnswer(HttpMsg *msg)
5f8252d2 455{
0f283edf 456 HttpReply *rep = dynamic_cast<HttpReply*>(msg);
5f8252d2 457 HTTPMSGLOCK(rep);
0f283edf 458 clearIcap(adaptedHeadSource); // we do not expect more messages
5f8252d2 459
460 if (abortOnBadEntry("entry went bad while waiting for adapted headers")) {
461 HTTPMSGUNLOCK(rep); // hopefully still safe, even if "this" is deleted
462 return;
463 }
464
465 assert(rep);
466 entry->replaceHttpReply(rep);
467 HTTPMSGUNLOCK(reply);
468
469 reply = rep; // already HTTPMSGLOCKed above
470
471 haveParsedReplyHeaders();
472
473 assert(!adaptedBodySource);
474 if (reply->body_pipe != NULL) {
475 // subscribe to receive adapted body
476 adaptedBodySource = reply->body_pipe;
477 // assume that ICAP does not auto-consume on failures
478 assert(adaptedBodySource->setConsumerIfNotLate(this));
479 } else {
480 // no body
bc81cb2b 481 if (doneWithIcap()) // we may still be sending virgin response
482 handleIcapCompleted();
5f8252d2 483 }
484
485}
486
487// will not receive adapted response headers (and, hence, body)
488void
0f283edf 489ServerStateData::noteIcapQueryAbort(bool final)
5f8252d2 490{
0f283edf 491 clearIcap(adaptedHeadSource);
492 handleIcapAborted(!final);
5f8252d2 493}
494
495// more adapted response body is available
496void
497ServerStateData::handleMoreAdaptedBodyAvailable()
498{
499 const size_t contentSize = adaptedBodySource->buf().contentSize();
500
501 debugs(11,5, HERE << "consuming " << contentSize << " bytes of adapted " <<
502 "response body at offset " << adaptedBodySource->consumedSize());
503
504 if (abortOnBadEntry("entry refuses adapted body"))
505 return;
506
507 assert(entry);
508 BodyPipeCheckout bpc(*adaptedBodySource);
509 const StoreIOBuffer ioBuf(&bpc.buf, bpc.offset);
510 entry->write(ioBuf);
511 bpc.buf.consume(contentSize);
512 bpc.checkIn();
513}
514
515// the entire adapted response body was produced, successfully
516void
517ServerStateData::handleAdaptedBodyProductionEnded()
518{
519 stopConsumingFrom(adaptedBodySource);
520
521 if (abortOnBadEntry("entry went bad while waiting for adapted body eof"))
522 return;
523
524 handleIcapCompleted();
525}
526
527// premature end of the adapted response body
528void ServerStateData::handleAdaptedBodyProducerAborted()
529{
530 stopConsumingFrom(adaptedBodySource);
531 handleIcapAborted();
532}
533
0f283edf 534// common part of noteIcapAnswer and handleAdaptedBodyProductionEnded
5f8252d2 535void
536ServerStateData::handleIcapCompleted()
537{
538 debugs(11,5, HERE << "handleIcapCompleted");
539 cleanIcap();
bc81cb2b 540
541 // We stop reading origin response because we have no place to put it and
542 // cannot use it. If some origin servers do not like that or if we want to
543 // reuse more pconns, we can add code to discard unneeded origin responses.
544 if (!doneWithServer()) {
545 debugs(11,3, HERE << "closing origin conn due to ICAP completion");
546 closeServer();
547 }
548
5f8252d2 549 completeForwarding();
bc81cb2b 550
5f8252d2 551 quitIfAllDone();
552}
553
bc81cb2b 554
5f8252d2 555// common part of noteIcap*Aborted and noteBodyConsumerAborted methods
556void
0f283edf 557ServerStateData::handleIcapAborted(bool bypassable)
5f8252d2 558{
0f283edf 559 debugs(11,5, HERE << "handleIcapAborted; bypassable: " << bypassable <<
560 ", entry empty: " << entry->isEmpty());
5f8252d2 561
562 if (abortOnBadEntry("entry went bad while ICAP aborted"))
563 return;
564
0f283edf 565 // TODO: bypass if possible
566
5f8252d2 567 if (entry->isEmpty()) {
568 debugs(11,9, HERE << "creating ICAP error entry after ICAP failure");
569 ErrorState *err =
570 errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
571 err->xerrno = errno;
572 fwd->fail(err);
573 fwd->dontRetry(true);
574 }
575
0f283edf 576 abortTransaction("ICAP failure");
5f8252d2 577}
578
7c4e4e7f 579void
580ServerStateData::icapAclCheckDone(ICAPServiceRep::Pointer service)
581{
582 icapAccessCheckPending = false;
583
584 if (abortOnBadEntry("entry went bad while waiting for ICAP ACL check"))
585 return;
586
bc81cb2b 587 startedIcap = startIcap(service, originalRequest());
7c4e4e7f 588
589 if (!startedIcap && (!service || service->bypass)) {
590 // handle ICAP start failure when no service was selected
591 // or where the selected service was optional
592 entry->replaceHttpReply(reply);
593
594 haveParsedReplyHeaders();
595 processReplyBody();
596
597 return;
598 }
599
600 if (!startedIcap) {
601 // handle start failure for an essential ICAP service
602 ErrorState *err = errorCon(ERR_ICAP_FAILURE,
603 HTTP_INTERNAL_SERVER_ERROR, originalRequest());
604 err->xerrno = errno;
605 errorAppendEntry(entry, err);
606 abortTransaction("ICAP start failure");
607 return;
608 }
609
610 processReplyBody();
611}
612
7dc79973 613void
614ServerStateData::icapAclCheckDoneWrapper(ICAPServiceRep::Pointer service, void *data)
615{
616 ServerStateData *state = (ServerStateData *)data;
617 state->icapAclCheckDone(service);
618}
0c25e715 619#endif
7dc79973 620
621void
e0f92cbf 622ServerStateData::setReply()
7dc79973 623{
7dc79973 624#if ICAP_CLIENT
625
626 if (TheICAPConfig.onoff) {
627 ICAPAccessCheck *icap_access_check =
628 new ICAPAccessCheck(ICAP::methodRespmod, ICAP::pointPreCache, request, reply, icapAclCheckDoneWrapper, this);
629
630 icapAccessCheckPending = true;
631 icap_access_check->check(); // will eventually delete self
632 return;
633 }
634
635#endif
636
637 entry->replaceHttpReply(reply);
638
639 haveParsedReplyHeaders();
640}
641
642void
bc81cb2b 643ServerStateData::addVirginReplyBody(const char *data, ssize_t len)
7dc79973 644{
7dc79973 645#if ICAP_CLIENT
bc81cb2b 646 assert(!icapAccessCheckPending); // or would need to buffer while waiting
647 if (startedIcap) {
648 adaptVirginReplyBody(data, len);
7dc79973 649 return;
650 }
7dc79973 651#endif
bc81cb2b 652 storeReplyBody(data, len);
653}
7dc79973 654
bc81cb2b 655// writes virgin or adapted reply body to store
656void
657ServerStateData::storeReplyBody(const char *data, ssize_t len)
658{
2d1a172f 659 // write even if len is zero to push headers towards the client side
7dc79973 660 entry->write (StoreIOBuffer(len, currentOffset, (char*)data));
661
662 currentOffset += len;
663}
664
665size_t ServerStateData::replyBodySpace(size_t space)
666{
667#if ICAP_CLIENT
668 if (responseBodyBuffer) {
669 return 0; // Stop reading if already overflowed waiting for ICAP to catch up
670 }
671
672 if (virginBodyDestination != NULL) {
673 /*
674 * BodyPipe buffer has a finite size limit. We
675 * should not read more data from the network than will fit
676 * into the pipe buffer or we _lose_ what did not fit if
677 * the response ends sooner that BodyPipe frees up space:
678 * There is no code to keep pumping data into the pipe once
679 * response ends and serverComplete() is called.
680 *
681 * If the pipe is totally full, don't register the read handler.
682 * The BodyPipe will call our noteMoreBodySpaceAvailable() method
683 * when it has free space again.
684 */
685 size_t icap_space = virginBodyDestination->buf().potentialSpaceSize();
686
687 debugs(11,9, "ServerStateData may read up to min(" << icap_space <<
688 ", " << space << ") bytes");
689
690 if (icap_space < space)
691 space = icap_space;
692 }
693#endif
694
695 return space;
696}