]> git.ipfire.org Git - thirdparty/squid.git/blob - src/clients/Client.h
Preserve caller context across (and improve) deferred reads (#1025)
[thirdparty/squid.git] / src / clients / Client.h
1 /*
2 * Copyright (C) 1996-2022 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 #ifndef SQUID_SRC_CLIENTS_CLIENT_H
10 #define SQUID_SRC_CLIENTS_CLIENT_H
11
12 #include "base/AsyncJob.h"
13 #include "BodyPipe.h"
14 #include "CommCalls.h"
15 #include "FwdState.h"
16 #include "http/forward.h"
17 #include "StoreIOBuffer.h"
18 #if USE_ADAPTATION
19 #include "adaptation/forward.h"
20 #include "adaptation/Initiator.h"
21 #endif
22
23 /**
24 * Client is a common base for classes such as HttpStateData and FtpStateData.
25 * All such classes must be able to consume request bodies from a BodyPipe
26 * or ICAP producer, adapt virgin responses using ICAP, and provide a
27 * consumer with responses.
28 */
29 class Client:
30 #if USE_ADAPTATION
31 public Adaptation::Initiator,
32 public BodyProducer,
33 #endif
34 public BodyConsumer
35 {
36
37 public:
38 Client(FwdState *);
39 virtual ~Client();
40
41 /// \return primary or "request data connection"
42 virtual const Comm::ConnectionPointer & dataConnection() const = 0;
43
44 // BodyConsumer: consume request body or adapted response body.
45 // The implementation just calls the corresponding HTTP or ICAP handle*()
46 // method, depending on the pipe.
47 virtual void noteMoreBodyDataAvailable(BodyPipe::Pointer);
48 virtual void noteBodyProductionEnded(BodyPipe::Pointer);
49 virtual void noteBodyProducerAborted(BodyPipe::Pointer);
50
51 /// read response data from the network
52 virtual void maybeReadVirginBody() = 0;
53
54 /// abnormal transaction termination; reason is for debugging only
55 virtual void abortAll(const char *reason) = 0;
56
57 /// abnormal data transfer termination
58 /// \retval true the transaction will be terminated (abortAll called)
59 /// \retval false the transaction will survive
60 virtual bool abortOnData(const char *reason);
61
62 /// a hack to reach HttpStateData::orignal_request
63 virtual HttpRequestPointer originalRequest();
64
65 #if USE_ADAPTATION
66 // Adaptation::Initiator API: start an ICAP transaction and receive adapted headers.
67 virtual void noteAdaptationAnswer(const Adaptation::Answer &answer);
68 virtual void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group);
69
70 // BodyProducer: provide virgin response body to ICAP.
71 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer );
72 virtual void noteBodyConsumerAborted(BodyPipe::Pointer );
73 #endif
74 virtual bool getMoreRequestBody(MemBuf &buf);
75 virtual void processReplyBody() = 0;
76
77 //AsyncJob virtual methods
78 virtual void swanSong();
79 virtual bool doneAll() const;
80
81 public: // should be protected
82 void serverComplete(); /**< call when no server communication is expected */
83
84 /// remember that the received virgin reply was parsed in its entirety,
85 /// including its body (if any)
86 void markParsedVirginReplyAsWhole(const char *reasonWeAreSure);
87
88 private:
89 void serverComplete2(); /**< Continuation of serverComplete */
90 bool completed = false; /**< serverComplete() has been called */
91
92 protected:
93 // kids customize these
94 virtual void haveParsedReplyHeaders(); /**< called when got final headers */
95 virtual void completeForwarding(); /**< default calls fwd->complete() */
96
97 // BodyConsumer for HTTP: consume request body.
98 bool startRequestBodyFlow();
99 void handleMoreRequestBodyAvailable();
100 void handleRequestBodyProductionEnded();
101 virtual void handleRequestBodyProducerAborted() = 0;
102
103 // sending of the request body to the server
104 void sendMoreRequestBody();
105 // has body; kids overwrite to increment I/O stats counters
106 virtual void sentRequestBody(const CommIoCbParams &io) = 0;
107 virtual void doneSendingRequestBody() = 0;
108
109 /// Use this to end communication with the server. The call cancels our
110 /// closure handler and tells FwdState to forget about the connection.
111 virtual void closeServer() = 0;
112 virtual bool doneWithServer() const = 0; /**< did we end communication? */
113 /// whether we may receive more virgin response body bytes
114 virtual bool mayReadVirginReplyBody() const = 0;
115
116 /// Called when a previously delayed dataConnection() read may be possible.
117 /// \sa delayRead()
118 virtual void noteDelayAwareReadChance() = 0;
119
120 /// Entry-dependent callbacks use this check to quit if the entry went bad
121 bool abortOnBadEntry(const char *abortReason);
122
123 bool blockCaching();
124
125 #if USE_ADAPTATION
126 void startAdaptation(const Adaptation::ServiceGroupPointer &group, HttpRequest *cause);
127 void adaptVirginReplyBody(const char *buf, ssize_t len);
128 void cleanAdaptation();
129 virtual bool doneWithAdaptation() const; /**< did we end ICAP communication? */
130
131 // BodyConsumer for ICAP: consume adapted response body.
132 void handleMoreAdaptedBodyAvailable();
133 void handleAdaptedBodyProductionEnded();
134 void handleAdaptedBodyProducerAborted();
135
136 void handleAdaptedHeader(Http::Message *msg);
137 void handleAdaptationCompleted();
138 void handleAdaptationBlocked(const Adaptation::Answer &answer);
139 void handleAdaptationAborted(bool bypassable = false);
140 bool handledEarlyAdaptationAbort();
141
142 /// called by StoreEntry when it has more buffer space available
143 void resumeBodyStorage();
144 /// called when the entire adapted response body is consumed
145 void endAdaptedBodyConsumption();
146 #endif
147
148 protected:
149 const HttpReply *virginReply() const;
150 HttpReply *virginReply();
151 HttpReply *setVirginReply(HttpReply *r);
152
153 HttpReply *finalReply();
154 HttpReply *setFinalReply(HttpReply *r);
155
156 // Kids use these to stuff data into the response instead of messing with the entry directly
157 void adaptOrFinalizeReply();
158 void addVirginReplyBody(const char *buf, ssize_t len);
159 void storeReplyBody(const char *buf, ssize_t len);
160 /// \deprecated use SBuf I/O API and calcBufferSpaceToReserve() instead
161 size_t replyBodySpace(const MemBuf &readBuf, const size_t minSpace) const;
162 /// determine how much space the buffer needs to reserve
163 size_t calcBufferSpaceToReserve(const size_t space, const size_t wantSpace) const;
164
165 void adjustBodyBytesRead(const int64_t delta);
166
167 /// Defer reading until it is likely to become possible.
168 /// Eventually, noteDelayAwareReadChance() will be called.
169 void delayRead();
170
171 // These should be private
172 int64_t currentOffset = 0; /**< Our current offset in the StoreEntry */
173 MemBuf *responseBodyBuffer = nullptr; /**< Data temporarily buffered for ICAP */
174
175 public: // should not be
176 StoreEntry *entry = nullptr;
177 FwdState::Pointer fwd;
178 HttpRequestPointer request;
179
180 protected:
181 BodyPipe::Pointer requestBodySource; /**< to consume request body */
182 AsyncCall::Pointer requestSender; /**< set if we are expecting Comm::Write to call us back */
183
184 #if USE_ADAPTATION
185 BodyPipe::Pointer virginBodyDestination; /**< to provide virgin response body */
186 CbcPointer<Adaptation::Initiate> adaptedHeadSource; /**< to get adapted response headers */
187 BodyPipe::Pointer adaptedBodySource; /**< to consume adated response body */
188
189 bool adaptationAccessCheckPending = false;
190 bool startedAdaptation = false;
191
192 /// handleAdaptedBodyProductionEnded() was called
193 bool receivedWholeAdaptedReply = false;
194 #endif
195 bool receivedWholeRequestBody = false; ///< handleRequestBodyProductionEnded called
196
197 /// whether we should not be talking to FwdState; XXX: clear fwd instead
198 /// points to a string literal which is used only for debugging
199 const char *doneWithFwd = nullptr;
200
201 private:
202 void sendBodyIsTooLargeError();
203 void maybePurgeOthers();
204
205 HttpReply *theVirginReply = nullptr; /**< reply received from the origin server */
206 HttpReply *theFinalReply = nullptr; /**< adapted reply from ICAP or virgin reply */
207 };
208
209 #endif /* SQUID_SRC_CLIENTS_CLIENT_H */
210