Squid Web Cache master
Loading...
Searching...
No Matches
Client.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "acl/FilledChecklist.h"
11#include "acl/Gadgets.h"
12#include "base/TextException.h"
13#include "clients/Client.h"
14#include "comm/Connection.h"
15#include "comm/forward.h"
16#include "comm/Write.h"
17#include "error/Detail.h"
18#include "errorpage.h"
19#include "fd.h"
20#include "HttpHdrContRange.h"
21#include "HttpReply.h"
22#include "HttpRequest.h"
23#include "SquidConfig.h"
24#include "StatCounters.h"
25#include "Store.h"
26#include "tools.h"
27
28#if USE_ADAPTATION
30#include "adaptation/Answer.h"
31#include "adaptation/Iterator.h"
32#include "base/AsyncCall.h"
33#endif
34
35// implemented in client_side_reply.cc until sides have a common parent
36void purgeEntriesByUrl(HttpRequest * req, const char *url);
37
38Client::Client(FwdState *theFwdState) :
39 AsyncJob("Client"),
40 fwd(theFwdState),
41 request(fwd->request)
42{
43 entry = fwd->entry;
44 entry->lock("Client");
45}
46
48{
49 // paranoid: check that swanSong has been called
51#if USE_ADAPTATION
54#endif
55
56 entry->unlock("Client");
57
60
61 if (responseBodyBuffer != nullptr) {
62 delete responseBodyBuffer;
63 responseBodyBuffer = nullptr;
64 }
65}
66
67void
69{
70 // get rid of our piping obligations
71 if (requestBodySource != nullptr)
73
74#if USE_ADAPTATION
76#endif
77
78 if (!doneWithServer())
80
81 if (!doneWithFwd) {
82 doneWithFwd = "swanSong()";
84 }
85
87#if USE_ADAPTATION
88 Initiator::swanSong();
90#endif
91
92 // paranoid: check that swanSong has been called
93 // extra paranoid: yeah, I really mean it. they MUST pass here.
95#if USE_ADAPTATION
98#endif
99}
100
101HttpReply *
107
108const HttpReply *
110{
112 return theVirginReply;
113}
114
115HttpReply *
117{
118 debugs(11,5, this << " setting virgin reply to " << rep);
120 assert(rep);
121 theVirginReply = rep;
123 if (fwd->al)
125 return theVirginReply;
126}
127
128HttpReply *
134
135HttpReply *
137{
138 debugs(11,5, this << " setting final reply to " << rep);
139
141 assert(rep);
142 theFinalReply = rep;
144 if (fwd->al)
146
147 // give entry the reply because haveParsedReplyHeaders() expects it there
148 entry->replaceHttpReply(theFinalReply, false); // but do not write yet
149 haveParsedReplyHeaders(); // update the entry/reply (e.g., set timestamps)
151 entry->release();
152 entry->startWriting(); // write the updated entry to store
153
154 return theFinalReply;
155}
156
157void
158Client::markParsedVirginReplyAsWhole(const char *reasonWeAreSure)
159{
160 assert(reasonWeAreSure);
161 debugs(11, 3, reasonWeAreSure);
162 markedParsedVirginReplyAsWhole = reasonWeAreSure;
163}
164
165// called when no more server communication is expected; may quit
166void
168{
169 debugs(11,5, "serverComplete " << this);
170
171 if (!doneWithServer()) {
172 closeServer();
174 }
175
176 completed = true;
177
178 if (requestBodySource != nullptr)
180
181 if (responseBodyBuffer != nullptr)
182 return;
183
185}
186
187void
189{
190 debugs(11,5, "serverComplete2 " << this);
191
192#if USE_ADAPTATION
193 if (virginBodyDestination != nullptr)
195
196 if (!doneWithAdaptation())
197 return;
198#endif
199
201}
202
203bool Client::doneAll() const
204{
205 return doneWithServer() &&
206#if USE_ADAPTATION
210#endif
212}
213
214// FTP side overloads this to work around multiple calls to fwd->complete
215void
217{
218 debugs(11,5, "completing forwarding for " << fwd);
219 assert(fwd != nullptr);
220
221 auto storedWholeReply = markedParsedVirginReplyAsWhole;
222#if USE_ADAPTATION
223 // This precondition is necessary for its two implications:
224 // * We cannot be waiting to decide whether to adapt this response. Thus,
225 // the startedAdaptation check below correctly detects all adaptation
226 // cases (i.e. it does not miss adaptationAccessCheckPending ones).
227 // * We cannot be waiting to consume/store received adapted response bytes.
228 // Thus, receivedWholeAdaptedReply implies that we stored everything.
230
232 storedWholeReply = receivedWholeAdaptedReply ? "receivedWholeAdaptedReply" : nullptr;
233#endif
234
235 if (storedWholeReply)
236 fwd->markStoredReplyAsWhole(storedWholeReply);
237
238 doneWithFwd = "completeForwarding()";
239 fwd->complete();
240}
241
242// Register to receive request body
244{
246 assert(r->body_pipe != nullptr);
249 debugs(11,3, "expecting request body from " <<
251 return true;
252 }
253
254 debugs(11,3, "aborting on partially consumed request body: " <<
256 requestBodySource = nullptr;
257 return false;
258}
259
260// Entry-dependent callbacks use this check to quit if the entry went bad
261bool
262Client::abortOnBadEntry(const char *abortReason)
263{
264 if (entry->isAccepting())
265 return false;
266
267 debugs(11,5, "entry is not Accepting!");
268 abortOnData(abortReason);
269 return true;
270}
271
272// more request or adapted response body is available
273void
275{
276#if USE_ADAPTATION
277 if (adaptedBodySource == bp) {
279 return;
280 }
281#endif
282 if (requestBodySource == bp)
284}
285
286// the entire request or adapted response body was provided, successfully
287void
289{
290#if USE_ADAPTATION
291 if (adaptedBodySource == bp) {
293 return;
294 }
295#endif
296 if (requestBodySource == bp)
298}
299
300// premature end of the request or adapted response body production
301void
303{
304#if USE_ADAPTATION
305 if (adaptedBodySource == bp) {
307 return;
308 }
309#endif
310 if (requestBodySource == bp)
312}
313
314bool
315Client::abortOnData(const char *reason)
316{
317 abortAll(reason);
318 return true;
319}
320
321// more origin request body data is available
322void
324{
325 if (!requestSender)
327 else
328 debugs(9,3, "waiting for request body write to complete");
329}
330
331// there will be no more handleMoreRequestBodyAvailable calls
332void
334{
336 if (!requestSender)
338 else
339 debugs(9,3, "waiting for request body write to complete");
340}
341
342// called when we are done sending request body; kids extend this
343void
345{
346 debugs(9,3, "done sending request body");
347 assert(requestBodySource != nullptr);
349
350 // kids extend this
351}
352
353// called when body producers aborts; kids extend this
354void
356{
357 if (requestSender != nullptr)
358 debugs(9,3, "fyi: request body aborted while we were sending");
359
360 fwd->dontRetry(true); // the problem is not with the server
361 stopConsumingFrom(requestBodySource); // requestSender, if any, will notice
362
363 // kids extend this
364}
365
366// called when we wrote request headers(!) or a part of the body
367void
369{
370 debugs(11, 5, "sentRequestBody: FD " << io.fd << ": size " << io.size << ": errflag " << io.flag << ".");
371 debugs(32,3, "sentRequestBody called");
372
373 requestSender = nullptr;
374
375 if (io.size > 0) {
378 // kids should increment their counters
379 }
380
381 if (io.flag == Comm::ERR_CLOSING)
382 return;
383
384 if (!requestBodySource) {
385 debugs(9,3, "detected while-we-were-sending abort");
386 return; // do nothing;
387 }
388
389 // both successful and failed writes affect response times
391
392 if (io.flag) {
393 debugs(11, DBG_IMPORTANT, "ERROR: sentRequestBody failure: FD " << io.fd << ": " << xstrerr(io.xerrno));
394 ErrorState *err;
396 err->xerrno = io.xerrno;
397 fwd->fail(err);
398 abortOnData("I/O error while sending request body");
399 return;
400 }
401
403 abortOnData("store entry aborted while sending request body");
404 return;
405 }
406
411 else
412 debugs(9,3, "waiting for body production end or abort");
413}
414
415void
417{
418 assert(requestBodySource != nullptr);
420
422
423 if (!Comm::IsConnOpen(conn)) {
424 debugs(9,3, "cannot send request body to closing " << conn);
425 return; // wait for the kid's close handler; TODO: assert(closer);
426 }
427
428 MemBuf buf;
429 if (getMoreRequestBody(buf) && buf.contentSize() > 0) {
430 debugs(9,3, "will write " << buf.contentSize() << " request body bytes");
433 Comm::Write(conn, &buf, requestSender);
434 } else {
435 debugs(9,3, "will wait for more request body bytes or eof");
436 requestSender = nullptr;
437 }
438}
439
441bool
443{
444 // default implementation does not encode request body content
445 Must(requestBodySource != nullptr);
446 return requestBodySource->getMoreData(buf);
447}
448
449// Compares hosts in urls, returns false if different, no scheme, or no host.
450static bool
451sameUrlHosts(const char *url1, const char *url2)
452{
453 // XXX: Want AnyP::Uri::parse() here, but it uses static storage and copying
454 const char *host1 = strchr(url1, ':');
455 const char *host2 = strchr(url2, ':');
456
457 if (host1 && host2) {
458 // skip scheme slashes
459 do {
460 ++host1;
461 ++host2;
462 } while (*host1 == '/' && *host2 == '/');
463
464 if (!*host1)
465 return false; // no host
466
467 // increment while the same until we reach the end of the URL/host
468 while (*host1 && *host1 != '/' && *host1 == *host2) {
469 ++host1;
470 ++host2;
471 }
472 return *host1 == *host2;
473 }
474
475 return false; // no URL scheme
476}
477
478// purges entries that match the value of a given HTTP [response] header
479static void
481{
482 const auto hdrUrl = rep->header.getStr(hdr);
483 if (!hdrUrl)
484 return;
485
486 /*
487 * If the URL is relative, make it absolute so we can find it.
488 * If it's absolute, make sure the host parts match to avoid DOS attacks
489 * as per RFC 2616 13.10.
490 */
491 SBuf absUrlMaker;
492 const char *absUrl = nullptr;
493 if (urlIsRelative(hdrUrl)) {
494 if (req->method.id() == Http::METHOD_CONNECT)
495 absUrl = hdrUrl; // TODO: merge authority-uri and hdrUrl
496 else if (req->url.getScheme() == AnyP::PROTO_URN)
497 absUrl = req->url.absolute().c_str();
498 else {
499 AnyP::Uri tmpUrl = req->url;
500 if (*hdrUrl == '/') {
501 // RFC 3986 section 4.2: absolute-path reference
502 // for this logic replace the entire request-target URI path
503 tmpUrl.path(hdrUrl);
504 } else {
505 tmpUrl.addRelativePath(hdrUrl);
506 }
507 absUrlMaker = tmpUrl.absolute();
508 absUrl = absUrlMaker.c_str();
509 }
510 } else if (!sameUrlHosts(reqUrl, hdrUrl)) {
511 return;
512 } else
513 absUrl = hdrUrl;
514
515 purgeEntriesByUrl(req, absUrl);
516}
517
518// some HTTP methods should purge matching cache entries
519void
521{
522 // only some HTTP methods should purge matching cache entries
524 return;
525
526 // and probably only if the response was successful
527 if (theFinalReply->sline.status() >= 400)
528 return;
529
530 // XXX: should we use originalRequest() here?
532 const char *reqUrl = tmp.c_str();
533 debugs(88, 5, "maybe purging due to " << request->method << ' ' << tmp);
537}
538
540void
542{
545
546 // adaptation may overwrite old offset computed using the virgin response
547 currentOffset = 0;
548 if (const auto cr = theFinalReply->contentRange()) {
549 if (cr->spec.offset != HttpHdrRangeSpec::UnknownPosition)
550 currentOffset = cr->spec.offset;
551 }
552}
553
555bool
557{
558 if (const auto acl = Config.accessList.storeMiss) {
559 // This relatively expensive check is not in StoreEntry::checkCachable:
560 // That method lacks HttpRequest and may be called too many times.
561 ACLFilledChecklist ch(acl, originalRequest().getRaw());
562 ch.updateAle(fwd->al);
564 if (!ch.fastCheck().allowed()) { // when in doubt, block
565 debugs(20, 3, "store_miss prohibits caching");
566 return true;
567 }
568 }
569 return false;
570}
571
574{
575 return request;
576}
577
578#if USE_ADAPTATION
580void
582{
583 debugs(11, 5, "Client::startAdaptation() called");
584 // check whether we should be sending a body as well
585 // start body pipe to feed ICAP transaction if needed
587 HttpReply *vrep = virginReply();
588 assert(!vrep->body_pipe);
589 int64_t size = 0;
590 if (vrep->expectingBody(cause->method, size) && size) {
593 debugs(93, 6, "will send virgin reply body to " <<
594 virginBodyDestination << "; size: " << size);
595 if (size > 0)
597 }
598
600 new Adaptation::Iterator(vrep, cause, fwd->al, group));
603}
604
605// properly cleans up ICAP-related state
606// may be called multiple times
608{
609 debugs(11,5, "cleaning ICAP; ACL: " << adaptationAccessCheckPending);
610
611 if (virginBodyDestination != nullptr)
613
615
616 if (adaptedBodySource != nullptr)
618
619 if (!adaptationAccessCheckPending) // we cannot cancel a pending callback
620 assert(doneWithAdaptation()); // make sure the two methods are in sync
621}
622
623bool
629
630// sends virgin reply body to ICAP, buffering excesses if needed
631void
632Client::adaptVirginReplyBody(const char *data, ssize_t len)
633{
635
637 debugs(11,3, "ICAP does not want more virgin body");
638 return;
639 }
640
641 // grow overflow area if already overflowed
642 if (responseBodyBuffer) {
643 responseBodyBuffer->append(data, len);
644 data = responseBodyBuffer->content();
646 }
647
648 const ssize_t putSize = virginBodyDestination->putMoreData(data, len);
649 data += putSize;
650 len -= putSize;
651
652 // if we had overflow area, shrink it as necessary
653 if (responseBodyBuffer) {
654 if (putSize == responseBodyBuffer->contentSize()) {
655 delete responseBodyBuffer;
656 responseBodyBuffer = nullptr;
657 } else {
658 responseBodyBuffer->consume(putSize);
659 }
660 return;
661 }
662
663 // if we did not have an overflow area, create it as needed
664 if (len > 0) {
668 responseBodyBuffer->append(data, len);
669 }
670}
671
672// can supply more virgin response body data
673void
675{
676 if (responseBodyBuffer) {
677 addVirginReplyBody(nullptr, 0); // kick the buffered fragment alive again
680 return;
681 }
682 }
684}
685
686// the consumer of our virgin response body aborted
687void
689{
691
692 // do not force closeServer here in case we need to bypass AdaptationQueryAbort
693
694 if (doneWithAdaptation()) // we may still be receiving adapted response
696}
697
698// received adapted response headers (body may follow)
699void
701{
702 clearAdaptation(adaptedHeadSource); // we do not expect more messages
703
704 switch (answer.kind) {
706 handleAdaptedHeader(const_cast<Http::Message*>(answer.message.getRaw()));
707 break;
708
711 break;
712
715 break;
716 }
717}
718
719void
721{
722 if (abortOnBadEntry("entry went bad while waiting for adapted headers")) {
723 // If the adapted response has a body, the ICAP side needs to know
724 // that nobody will consume that body. We will be destroyed upon
725 // return. Tell the ICAP side that it is on its own.
726 HttpReply *rep = dynamic_cast<HttpReply*>(msg);
727 assert(rep);
728 if (rep->body_pipe != nullptr)
730
731 return;
732 }
733
734 HttpReply *rep = dynamic_cast<HttpReply*>(msg);
735 assert(rep);
736 debugs(11,5, this << " setting adapted reply to " << rep);
737 setFinalReply(rep);
738
740 if (rep->body_pipe != nullptr) {
741 // subscribe to receive adapted body
743 // assume that ICAP does not auto-consume on failures
744 const bool result = adaptedBodySource->setConsumerIfNotLate(this);
745 assert(result);
747 } else {
748 // no body
751 if (doneWithAdaptation()) // we may still be sending virgin response
753 }
754}
755
756void
758{
759 if (abortOnBadEntry("store entry aborted while kick producer callback"))
760 return;
761
763 return;
764
766
768}
769
770// more adapted response body is available
771void
773{
774 if (abortOnBadEntry("entry refuses adapted body"))
775 return;
776
777 assert(entry);
778
779 size_t contentSize = adaptedBodySource->buf().contentSize();
780
781 if (!contentSize)
782 return; // XXX: bytesWanted asserts on zero-size ranges
783
784 const size_t spaceAvailable = entry->bytesWanted(Range<size_t>(0, contentSize), true);
785
786 if (spaceAvailable < contentSize ) {
787 // No or partial body data consuming
788 typedef NullaryMemFunT<Client> Dialer;
789 AsyncCall::Pointer call = asyncCall(93, 5, "Client::resumeBodyStorage",
790 Dialer(this, &Client::resumeBodyStorage));
791 entry->deferProducer(call);
792 }
793
794 if (!spaceAvailable) {
795 debugs(11, 5, "NOT storing " << contentSize << " bytes of adapted " <<
796 "response body at offset " << adaptedBodySource->consumedSize());
797 return;
798 }
799
800 if (spaceAvailable < contentSize ) {
801 debugs(11, 5, "postponing storage of " <<
802 (contentSize - spaceAvailable) << " body bytes");
803 contentSize = spaceAvailable;
804 }
805
806 debugs(11,5, "storing " << contentSize << " bytes of adapted " <<
807 "response body at offset " << adaptedBodySource->consumedSize());
808
810 const StoreIOBuffer ioBuf(&bpc.buf, currentOffset, contentSize);
811 currentOffset += ioBuf.length;
812 entry->write(ioBuf);
813 bpc.buf.consume(contentSize);
814 bpc.checkIn();
815}
816
817// the entire adapted response body was produced, successfully
818void
820{
821 if (abortOnBadEntry("entry went bad while waiting for adapted body eof"))
822 return;
823
826
828}
829
830void
832{
833 if (!adaptedBodySource) {
834 debugs(11, 7, "not consuming; " << startedAdaptation);
835 return;
836 }
837
839 // wait for noteBodyProductionEnded() or noteBodyProducerAborted()
840 // because completeForwarding() needs to know whether we receivedWholeAdaptedReply
841 debugs(11, 7, "waiting for adapted body production ending");
842 return;
843 }
844
846 debugs(11, 5, "waiting to consume the remainder of the adapted body from " << adaptedBodySource->status());
847 return; // resumeBodyStorage() should eventually consume the rest
848 }
849
851
852 if (doneWithAdaptation()) // we may still be sending virgin response
854}
855
856// premature end of the adapted response body
858{
859 if (abortOnBadEntry("entry went bad while waiting for the now-aborted adapted body"))
860 return;
861
863 adaptedReplyAborted = true;
864 Must(adaptedBodySource != nullptr);
866 debugs(11,5, "waiting to consume the remainder of the aborted adapted body");
867 return; // resumeBodyStorage() should eventually consume the rest
868 }
869
871 return;
872
873 checkAdaptationWithBodyCompletion(); // the user should get a truncated response
874}
875
876// common part of noteAdaptationAnswer and handleAdaptedBodyProductionEnded
877void
879{
880 debugs(11,5, "handleAdaptationCompleted");
882
883 // We stop reading origin response because we have no place to put it(*) and
884 // cannot use it. If some origin servers do not like that or if we want to
885 // reuse more pconns, we can add code to discard unneeded origin responses.
886 // (*) TODO: Is it possible that the adaptation xaction is still running?
888 debugs(11,3, "closing origin conn due to ICAP completion");
889 closeServer();
890 }
891
893}
894
895// common part of noteAdaptation*Aborted and noteBodyConsumerAborted methods
896void
898{
899 debugs(11,5, "handleAdaptationAborted; bypassable: " << bypassable <<
900 ", entry empty: " << entry->isEmpty());
901
902 if (abortOnBadEntry("entry went bad while ICAP aborted"))
903 return;
904
905 // TODO: bypass if possible
907 abortAll("adaptation failure with a filled entry");
908}
909
912bool
914{
915 if (entry->isEmpty()) {
916 debugs(11,8, "adaptation failure with an empty entry: " << *entry);
918 static const auto d = MakeNamedErrorDetail("ICAP_RESPMOD_EARLY");
919 err->detailError(d);
920 fwd->fail(err);
921 fwd->dontRetry(true);
922 abortAll("adaptation failure with an empty entry");
923 return true; // handled
924 }
925
926 if (request) { // update logged info directly
927 static const auto d = MakeNamedErrorDetail("ICAP_RESPMOD_LATE");
929 }
930
931 return false; // the caller must handle
932}
933
934// adaptation service wants us to deny HTTP client access to this response
935void
937{
938 const auto blockedAnswer = answer.blockedToChecklistAnswer();
939
940 debugs(11,5, blockedAnswer.lastCheckDescription());
941
942 if (abortOnBadEntry("entry went bad while ICAP aborted"))
943 return;
944
945 if (!entry->isEmpty()) { // too late to block (should not really happen)
946 if (request) {
947 static const auto d = MakeNamedErrorDetail("RESPMOD_BLOCK_LATE");
949 }
950 abortAll("late adaptation block");
951 return;
952 }
953
954 debugs(11,7, "creating adaptation block response");
955
956 auto page_id = FindDenyInfoPage(blockedAnswer, true);
957 if (page_id == ERR_NONE)
958 page_id = ERR_ACCESS_DENIED;
959
960 const auto err = new ErrorState(page_id, Http::scForbidden, request.getRaw(), fwd->al);
961 static const auto d = MakeNamedErrorDetail("RESPMOD_BLOCK_EARLY");
962 err->detailError(d);
963 fwd->fail(err);
964 fwd->dontRetry(true);
965
966 abortOnData("timely adaptation block");
967}
968
969void
971{
973
974 if (abortOnBadEntry("entry went bad while waiting for ICAP ACL check"))
975 return;
976
977 // TODO: Should non-ICAP and ICAP REPMOD pre-cache paths check this?
978 // That check now only happens on REQMOD pre-cache and REPMOD post-cache, in processReplyAccess().
979 if (virginReply()->expectedBodyTooLarge(*request)) {
981 return;
982 }
983 // TODO: Should we check receivedBodyTooLarge as well?
984
985 if (!group) {
986 debugs(11, 3, "no adaptation needed");
989 return;
990 }
991
992 startAdaptation(group, originalRequest().getRaw());
994}
995#endif
996
997void
999{
1000 const auto err = new ErrorState(ERR_TOO_BIG, Http::scForbidden, request.getRaw(), fwd->al);
1001 fwd->fail(err);
1002 fwd->dontRetry(true);
1003 abortOnData("Virgin body too large.");
1004}
1005
1006// TODO: when HttpStateData sends all errors to ICAP,
1007// we should be able to move this at the end of setVirginReply().
1008void
1010{
1011#if USE_ADAPTATION
1012 // TODO: merge with client side and return void to hide the on/off logic?
1013 // The callback can be called with a NULL service if adaptation is off.
1016 originalRequest().getRaw(), virginReply(), fwd->al, this);
1017 debugs(11,5, "adaptationAccessCheckPending=" << adaptationAccessCheckPending);
1019 return;
1020#endif
1021
1023}
1024
1026void
1028{
1029 int64_t &bodyBytesRead = originalRequest()->hier.bodyBytesRead;
1030
1031 // if we got here, do not log a dash even if we got nothing from the server
1032 if (bodyBytesRead < 0)
1033 bodyBytesRead = 0;
1034
1035 bodyBytesRead += delta; // supports negative and zero deltas
1036
1037 // check for overflows ("infinite" response?) and underflows (a bug)
1038 Must(bodyBytesRead >= 0);
1039}
1040
1041void
1043{
1046
1047 using DeferredReadDialer = NullaryMemFunT<Client>;
1048 AsyncCall::Pointer call = asyncCall(11, 5, "Client::noteDelayAwareReadChance",
1049 DeferredReadDialer(this, &Client::noteDelayAwareReadChance));
1050 entry->mem().delayRead(call);
1051}
1052
1053void
1054Client::addVirginReplyBody(const char *data, ssize_t len)
1055{
1057
1058#if USE_ADAPTATION
1059 assert(!adaptationAccessCheckPending); // or would need to buffer while waiting
1060 if (startedAdaptation) {
1061 adaptVirginReplyBody(data, len);
1062 return;
1063 }
1064#endif
1065 storeReplyBody(data, len);
1066}
1067
1068// writes virgin or adapted reply body to store
1069void
1070Client::storeReplyBody(const char *data, ssize_t len)
1071{
1072 // write even if len is zero to push headers towards the client side
1073 entry->write (StoreIOBuffer(len, currentOffset, (char*)data));
1074
1075 currentOffset += len;
1076}
1077
1078size_t
1079Client::calcBufferSpaceToReserve(size_t space, const size_t wantSpace) const
1080{
1081 if (space < wantSpace) {
1082 const size_t maxSpace = SBuf::maxSize; // absolute best
1083 space = min(wantSpace, maxSpace); // do not promise more than asked
1084 }
1085
1086#if USE_ADAPTATION
1087 if (responseBodyBuffer) {
1088 return 0; // Stop reading if already overflowed waiting for ICAP to catch up
1089 }
1090
1091 if (virginBodyDestination != nullptr) {
1092 /*
1093 * BodyPipe buffer has a finite size limit. We
1094 * should not read more data from the network than will fit
1095 * into the pipe buffer or we _lose_ what did not fit if
1096 * the response ends sooner that BodyPipe frees up space:
1097 * There is no code to keep pumping data into the pipe once
1098 * response ends and serverComplete() is called.
1099 */
1100 const size_t adaptor_space = virginBodyDestination->buf().potentialSpaceSize();
1101
1102 debugs(11,9, "Client may read up to min(" <<
1103 adaptor_space << ", " << space << ") bytes");
1104
1105 if (adaptor_space < space)
1106 space = adaptor_space;
1107 }
1108#endif
1109
1110 return space;
1111}
1112
#define Assure(condition)
Definition Assure.h:35
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition AsyncCall.h:156
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition Detail.cc:54
int size
Definition ModDevPoll.cc:70
class SquidConfig Config
StatCounters statCounter
#define Must(condition)
bool urlIsRelative(const char *url)
Definition Uri.cc:846
err_type FindDenyInfoPage(const Acl::Answer &answer, const bool redirect_allowed)
Definition Gadgets.cc:34
#define assert(EX)
Definition assert.h:17
#define SQUID_TCP_SO_RCVBUF
Definition autoconf.h:1458
Acl::Answer const & fastCheck()
Definition Checklist.cc:298
void updateAle(const AccessLogEntry::Pointer &)
void updateReply(const HttpReply::Pointer &)
HttpReplyPointer reply
bool allowed() const
Definition Acl.h:82
static bool Start(Method method, VectPoint vp, HttpRequest *req, HttpReply *, const AccessLogEntryPointer &, Adaptation::Initiator *)
summarizes adaptation service answer for the noteAdaptationAnswer() API
Definition Answer.h:25
Acl::Answer blockedToChecklistAnswer() const
creates an Acl::Answer from akBlock answer
Definition Answer.cc:44
Kind kind
the type of the answer
Definition Answer.h:47
Http::MessagePointer message
HTTP request or response to forward.
Definition Answer.h:44
bool final
whether the error, if any, cannot be bypassed
Definition Answer.h:46
@ akForward
forward the supplied adapted HTTP message
Definition Answer.h:29
@ akBlock
block or deny the master xaction; see authority
Definition Answer.h:30
@ akError
no adapted message will come; see bypassable
Definition Answer.h:31
CbcPointer< Initiate > initiateAdaptation(Initiate *x)
< starts freshly created initiate and returns a safe pointer to it
Definition Initiator.cc:23
void clearAdaptation(CbcPointer< Initiate > &x)
clears the pointer (does not call announceInitiatorAbort)
Definition Initiator.cc:32
void announceInitiatorAbort(CbcPointer< Initiate > &x)
inform the transaction about abnormal termination and clear the pointer
Definition Initiator.cc:38
bool initiated(const CbcPointer< AsyncJob > &job) const
Must(initiated(initiate)) instead of Must(initiate.set()), for clarity.
Definition Initiator.h:52
iterates services in ServiceGroup, starting adaptation launchers
Definition Iterator.h:32
AnyP::UriScheme const & getScheme() const
Definition Uri.h:58
void path(const char *p)
Definition Uri.h:96
void addRelativePath(const char *relUrl)
Definition Uri.cc:879
SBuf & absolute() const
Definition Uri.cc:743
virtual bool doneAll() const
whether positive goal has been reached
Definition AsyncJob.cc:112
virtual void swanSong()
Definition AsyncJob.h:61
void stopConsumingFrom(RefCount< BodyPipe > &)
Definition BodyPipe.cc:118
MemBuf & buf
Definition BodyPipe.h:74
void expectNoConsumption()
there will be no more setConsumer() calls
Definition BodyPipe.cc:267
size_t putMoreData(const char *buf, size_t size)
Definition BodyPipe.cc:213
size_t getMoreData(MemBuf &buf)
Definition BodyPipe.cc:294
const MemBuf & buf() const
Definition BodyPipe.h:137
bool exhausted() const
Definition BodyPipe.cc:174
void setBodySize(uint64_t aSize)
Definition BodyPipe.cc:147
uint64_t consumedSize() const
Definition BodyPipe.h:111
bool setConsumerIfNotLate(const Consumer::Pointer &aConsumer)
Definition BodyPipe.cc:228
const char * status() const
Definition BodyPipe.cc:446
void stopProducingFor(RefCount< BodyPipe > &, bool atEof)
Definition BodyPipe.cc:107
void noteAdaptationAnswer(const Adaptation::Answer &answer) override
Definition Client.cc:700
const char * doneWithFwd
Definition Client.h:211
bool adaptationAccessCheckPending
Definition Client.h:190
void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group) override
Definition Client.cc:970
void checkAdaptationWithBodyCompletion()
Definition Client.cc:831
void adaptVirginReplyBody(const char *buf, ssize_t len)
Definition Client.cc:632
void noteMoreBodySpaceAvailable(BodyPipe::Pointer) override
Definition Client.cc:674
virtual void maybeReadVirginBody()=0
read response data from the network
Client(FwdState *)
Definition Client.cc:38
void noteMoreBodyDataAvailable(BodyPipe::Pointer) override
Definition Client.cc:274
void sendMoreRequestBody()
Definition Client.cc:416
void maybePurgeOthers()
Definition Client.cc:520
bool receivedWholeRequestBody
handleRequestBodyProductionEnded called
Definition Client.h:200
void handleAdaptationCompleted()
Definition Client.cc:878
HttpReply * theFinalReply
Definition Client.h:218
void serverComplete2()
Definition Client.cc:188
void sendBodyIsTooLargeError()
Definition Client.cc:998
BodyPipe::Pointer adaptedBodySource
Definition Client.h:188
BodyPipe::Pointer requestBodySource
Definition Client.h:182
AsyncCall::Pointer requestSender
Definition Client.h:183
bool completed
Definition Client.h:90
void resumeBodyStorage()
called by StoreEntry when it has more buffer space available
Definition Client.cc:757
virtual void completeForwarding()
Definition Client.cc:216
void serverComplete()
Definition Client.cc:167
void delayRead()
Definition Client.cc:1042
virtual HttpRequestPointer originalRequest()
a hack to reach HttpStateData::orignal_request
Definition Client.cc:573
virtual bool abortOnData(const char *reason)
Definition Client.cc:315
void handleMoreAdaptedBodyAvailable()
Definition Client.cc:772
const HttpReply * virginReply() const
Definition Client.cc:109
int64_t currentOffset
Definition Client.h:173
bool handledEarlyAdaptationAbort()
Definition Client.cc:913
virtual bool getMoreRequestBody(MemBuf &buf)
either fill buf with available [encoded] request body bytes or return false
Definition Client.cc:442
bool doneAll() const override
whether positive goal has been reached
Definition Client.cc:203
void startAdaptation(const Adaptation::ServiceGroupPointer &group, HttpRequest *cause)
Initiate an asynchronous adaptation transaction which will call us back.
Definition Client.cc:581
virtual void abortAll(const char *reason)=0
abnormal transaction termination; reason is for debugging only
bool abortOnBadEntry(const char *abortReason)
Entry-dependent callbacks use this check to quit if the entry went bad.
Definition Client.cc:262
void storeReplyBody(const char *buf, ssize_t len)
Definition Client.cc:1070
virtual void handleRequestBodyProducerAborted()=0
Definition Client.cc:355
bool waitingForDelayAwareReadChance
whether we are waiting for MemObject::delayRead() to call us back
Definition Client.h:203
bool receivedWholeAdaptedReply
Definition Client.h:196
const char * markedParsedVirginReplyAsWhole
Definition Client.h:207
bool startRequestBodyFlow()
Definition Client.cc:243
void handleAdaptedBodyProducerAborted()
Definition Client.cc:857
void handleRequestBodyProductionEnded()
Definition Client.cc:333
bool blockCaching()
whether to prevent caching of an otherwise cachable response
Definition Client.cc:556
bool adaptedReplyAborted
handleAdaptedBodyProducerAborted() has been called
Definition Client.h:198
void handleAdaptedBodyProductionEnded()
Definition Client.cc:819
HttpReply * setVirginReply(HttpReply *r)
Definition Client.cc:116
void handleAdaptationBlocked(const Adaptation::Answer &answer)
Definition Client.cc:936
BodyPipe::Pointer virginBodyDestination
Definition Client.h:186
void noteBodyProductionEnded(BodyPipe::Pointer) override
Definition Client.cc:288
HttpReply * finalReply()
Definition Client.cc:129
void adaptOrFinalizeReply()
Definition Client.cc:1009
size_t calcBufferSpaceToReserve(const size_t space, const size_t wantSpace) const
determine how much space the buffer needs to reserve
Definition Client.cc:1079
void addVirginReplyBody(const char *buf, ssize_t len)
Definition Client.cc:1054
void cleanAdaptation()
Definition Client.cc:607
void noteBodyProducerAborted(BodyPipe::Pointer) override
Definition Client.cc:302
CbcPointer< Adaptation::Initiate > adaptedHeadSource
Definition Client.h:187
HttpRequestPointer request
Definition Client.h:179
void handleAdaptedHeader(Http::Message *msg)
Definition Client.cc:720
virtual bool doneWithServer() const =0
void adjustBodyBytesRead(const int64_t delta)
initializes bodyBytesRead stats if needed and applies delta
Definition Client.cc:1027
void handleAdaptationAborted(bool bypassable=false)
Definition Client.cc:897
void markParsedVirginReplyAsWhole(const char *reasonWeAreSure)
Definition Client.cc:158
bool startedAdaptation
Definition Client.h:191
void noteBodyConsumerAborted(BodyPipe::Pointer) override
Definition Client.cc:688
virtual void noteDelayAwareReadChance()=0
StoreEntry * entry
Definition Client.h:177
virtual bool mayReadVirginReplyBody() const =0
whether we may receive more virgin response body bytes
virtual void closeServer()=0
HttpReply * setFinalReply(HttpReply *r)
Definition Client.cc:136
void handleMoreRequestBodyAvailable()
Definition Client.cc:323
HttpReply * theVirginReply
Definition Client.h:217
virtual void processReplyBody()=0
MemBuf * responseBodyBuffer
Definition Client.h:174
virtual bool doneWithAdaptation() const
Definition Client.cc:624
void swanSong() override
Definition Client.cc:68
virtual void sentRequestBody(const CommIoCbParams &io)=0
Definition Client.cc:368
virtual const Comm::ConnectionPointer & dataConnection() const =0
virtual void doneSendingRequestBody()=0
Definition Client.cc:344
FwdState::Pointer fwd
Definition Client.h:178
~Client() override
Definition Client.cc:47
virtual void haveParsedReplyHeaders()
called when we have final (possibly adapted) reply headers; kids extend
Definition Client.cc:541
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition CommCalls.h:83
int fd
FD which the call was about. Set by the async call creator.
Definition CommCalls.h:85
Comm::Flag flag
comm layer result status.
Definition CommCalls.h:82
void handleUnregisteredServerEnd()
Definition FwdState.cc:804
HttpRequest * request
Definition FwdState.h:203
void complete()
Definition FwdState.cc:526
void fail(ErrorState *err)
Definition FwdState.cc:458
bool dontRetry()
Definition FwdState.h:130
StoreEntry * entry
Definition FwdState.h:202
void markStoredReplyAsWhole(const char *whyWeAreSure)
Definition FwdState.cc:575
AccessLogEntryPointer al
info for the future access.log entry
Definition FwdState.h:204
int64_t bodyBytesRead
number of body bytes received from the next hop or -1
static int64_t const UnknownPosition
const char * getStr(Http::HdrType id) const
Http::StatusLine sline
Definition HttpReply.h:56
const HttpHdrContRange * contentRange() const
Definition HttpReply.cc:345
bool expectingBody(const HttpRequestMethod &, int64_t &) const override
Definition HttpReply.cc:528
bool purgesOthers() const
Http::MethodType id() const
HttpRequestMethod method
HierarchyLogEntry hier
void detailError(const err_type c, const ErrorDetail::Pointer &d)
sets error detail if no earlier detail was available
AnyP::Uri url
the request URI
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
common parts of HttpRequest and HttpReply
Definition Message.h:26
HttpHeader header
Definition Message.h:74
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition Message.h:97
Http::StatusCode status() const
retrieve the status code for this status line
Definition StatusLine.h:45
void append(const char *c, int sz) override
Definition MemBuf.cc:209
void init(mb_size_t szInit, mb_size_t szMax)
Definition MemBuf.cc:93
char * content()
start of the added data
Definition MemBuf.h:41
mb_size_t contentSize() const
available data size
Definition MemBuf.h:47
mb_size_t potentialSpaceSize() const
Definition MemBuf.cc:161
void consume(mb_size_t sz)
removes sz bytes and "packs" by moving content left
Definition MemBuf.cc:168
const HttpReply & freshestReply() const
Definition MemObject.h:68
void delayRead(const AsyncCallPointer &)
Definition MemObject.cc:445
Definition Range.h:19
C * getRaw() const
Definition RefCount.h:89
Definition SBuf.h:94
const char * c_str()
Definition SBuf.cc:516
static const size_type maxSize
Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb.
Definition SBuf.h:103
acl_access * storeMiss
struct SquidConfig::@91 accessList
ByteCounter kbytes_out
struct StatCounters::@105 server
struct StatCounters::@105::@115 all
size_t bytesWanted(Range< size_t > const aRange, bool ignoreDelayPool=false) const
Definition store.cc:213
bool isAccepting() const
Definition store.cc:1988
uint16_t flags
Definition Store.h:231
MemObject & mem()
Definition Store.h:47
int unlock(const char *context)
Definition store.cc:469
void startWriting()
Definition store.cc:1721
void release(const bool shareable=false)
Definition store.cc:1146
void write(StoreIOBuffer)
Definition store.cc:780
void lock(const char *context)
Definition store.cc:445
void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting=true)
Definition store.cc:1705
bool isEmpty() const
Definition Store.h:65
void deferProducer(const AsyncCall::Pointer &producer)
call back producer when more buffer space is available
Definition store.cc:366
void purgeEntriesByUrl(HttpRequest *req, const char *url)
static bool sameUrlHosts(const char *url1, const char *url2)
Definition Client.cc:451
static void purgeEntriesByHeader(HttpRequest *req, const char *reqUrl, Http::Message *rep, Http::HdrType hdr)
Definition Client.cc:480
void purgeEntriesByUrl(HttpRequest *req, const char *url)
A const & min(A const &lhs, A const &rhs)
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define EBIT_TEST(flag, bit)
Definition defines.h:67
@ RELEASE_REQUEST
prohibits making the key public
Definition enums.h:93
@ ENTRY_ABORTED
Definition enums.h:110
@ ERR_ACCESS_DENIED
Definition forward.h:18
@ ERR_NONE
Definition forward.h:15
@ ERR_ICAP_FAILURE
Definition forward.h:64
@ ERR_WRITE_ERROR
Definition forward.h:29
@ ERR_TOO_BIG
Definition forward.h:40
void fd_bytes(const int fd, const int len, const IoDirection direction)
Definition fd.cc:221
void HTTPMSGUNLOCK(M *&a)
Definition Message.h:150
void HTTPMSGLOCK(Http::Message *a)
Definition Message.h:161
@ methodRespmod
Definition Elements.h:17
@ pointPreCache
Definition Elements.h:18
@ PROTO_URN
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition Connection.cc:27
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition Write.cc:33
@ ERR_CLOSING
Definition Flag.h:24
@ scForbidden
Definition StatusCode.h:48
@ scInternalServerError
Definition StatusCode.h:73
@ scBadGateway
Definition StatusCode.h:75
@ METHOD_CONNECT
Definition MethodType.h:29
const char * xstrerr(int error)
Definition xstrerror.cc:83