]>
Commit | Line | Data |
---|---|---|
774c051c | 1 | /* |
5b74111a | 2 | * Copyright (C) 1996-2018 The Squid Software Foundation and contributors |
774c051c | 3 | * |
bbc27441 AJ |
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. | |
774c051c | 7 | */ |
8 | ||
9 | #ifndef SQUID_ICAPMODXACT_H | |
10 | #define SQUID_ICAPMODXACT_H | |
11 | ||
af0ded40 | 12 | #include "AccessLogEntry.h" |
26cc52cb AR |
13 | #include "adaptation/icap/InOut.h" |
14 | #include "adaptation/icap/Launcher.h" | |
602d9612 A |
15 | #include "adaptation/icap/Xaction.h" |
16 | #include "BodyPipe.h" | |
51c3e7f0 | 17 | #include "http/one/forward.h" |
5f8252d2 | 18 | |
19 | /* | |
20 | * ICAPModXact implements ICAP REQMOD and RESPMOD transaction using | |
21 | * ICAPXaction as the base. The ICAPModXact receives a virgin HTTP message | |
22 | * from an ICAP vecoring point, (a.k.a., initiator), communicates with the | |
23 | * ICAP server, and sends the adapted HTTP message headers back. | |
24 | * Virgin/adapted HTTP message body is reveived/sent using BodyPipe | |
25 | * interface. The initiator (or its associate) is expected to send and/or | |
26 | * receive the HTTP body. | |
27 | */ | |
774c051c | 28 | |
af6a12ee AJ |
29 | namespace Adaptation |
30 | { | |
e1381638 AJ |
31 | namespace Icap |
32 | { | |
26cc52cb | 33 | |
774c051c | 34 | // estimated future presence and size of something (e.g., HTTP body) |
35 | ||
36 | class SizedEstimate | |
37 | { | |
38 | ||
39 | public: | |
40 | SizedEstimate(); // not expected by default | |
47f6e231 | 41 | void expect(int64_t aSize); // expect with any, even unknown size |
774c051c | 42 | bool expected() const; |
43 | ||
44 | /* other members can be accessed iff expected() */ | |
45 | ||
46 | bool knownSize() const; | |
47f6e231 | 47 | uint64_t size() const; // can be accessed iff knownSize() |
774c051c | 48 | |
49 | private: | |
50 | enum { dtUnexpected = -2, dtUnknown = -1 }; | |
47f6e231 | 51 | int64_t theData; // combines expectation and size info to save RAM |
774c051c | 52 | }; |
53 | ||
9e008dda | 54 | // Virgin body may be used for two activities: (a) writing preview or prime |
5f8252d2 | 55 | // body to the ICAP server and (b) sending the body back in the echo mode. |
56 | // Both activities use the same BodyPipe and may be active at the same time. | |
57 | // This class is used to maintain the state of body writing or sending | |
58 | // activity and to coordinate consumption of the shared virgin body buffer. | |
59 | class VirginBodyAct | |
774c051c | 60 | { |
61 | ||
62 | public: | |
478cfe99 | 63 | VirginBodyAct(); |
774c051c | 64 | |
5f8252d2 | 65 | void plan(); // the activity may happen; do not consume at or above offset |
66 | void disable(); // the activity wont continue; no consumption restrictions | |
478cfe99 | 67 | |
68 | bool active() const { return theState == stActive; } | |
69 | bool disabled() const { return theState == stDisabled; } | |
774c051c | 70 | |
71 | // methods below require active() | |
72 | ||
47f6e231 | 73 | uint64_t offset() const; // the absolute beginning of not-yet-acted-on data |
5f8252d2 | 74 | void progress(size_t size); // note processed body bytes |
774c051c | 75 | |
76 | private: | |
47f6e231 | 77 | int64_t theStart; // unprocessed virgin body data offset |
478cfe99 | 78 | |
79 | typedef enum { stUndecided, stActive, stDisabled } State; | |
80 | State theState; | |
774c051c | 81 | }; |
82 | ||
83 | // maintains preview-related sizes | |
84 | ||
26cc52cb | 85 | class Preview |
774c051c | 86 | { |
87 | ||
88 | public: | |
26cc52cb | 89 | Preview(); // disabled |
774c051c | 90 | void enable(size_t anAd); // enabled with advertised size |
91 | bool enabled() const; | |
92 | ||
93 | /* other members can be accessed iff enabled() */ | |
94 | ||
95 | size_t ad() const; // advertised preview size | |
96 | size_t debt() const; // remains to write | |
97 | bool done() const; // wrote everything | |
98 | bool ieof() const; // premature EOF | |
99 | ||
c99de607 | 100 | void wrote(size_t size, bool wroteEof); |
774c051c | 101 | |
102 | private: | |
103 | size_t theWritten; | |
104 | size_t theAd; | |
105 | enum State { stDisabled, stWriting, stIeof, stDone } theState; | |
106 | }; | |
107 | ||
69c698a3 EB |
108 | /// Parses and stores ICAP trailer header block. |
109 | class TrailerParser | |
110 | { | |
111 | public: | |
112 | TrailerParser() : trailer(hoReply), hdr_sz(0) {} | |
113 | /// Parses trailers stored in a buffer. | |
114 | /// \returns true and sets hdr_sz on success | |
115 | /// \returns false and sets *error to zero when needs more data | |
116 | /// \returns false and sets *error to a positive Http::StatusCode on error | |
117 | bool parse(const char *buf, int len, int atEnd, Http::StatusCode *error); | |
118 | HttpHeader trailer; | |
119 | /// parsed trailer size if parse() was successful | |
120 | size_t hdr_sz; // pedantic XXX: wrong type dictated by HttpHeader::parse() API | |
121 | }; | |
122 | ||
26cc52cb | 123 | class ModXact: public Xaction, public BodyProducer, public BodyConsumer |
774c051c | 124 | { |
5c2f68b7 | 125 | CBDATA_CLASS(ModXact); |
774c051c | 126 | |
774c051c | 127 | public: |
63df1d28 | 128 | ModXact(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, ServiceRep::Pointer &s); |
c7d51c86 | 129 | virtual ~ModXact(); |
774c051c | 130 | |
5f8252d2 | 131 | // BodyProducer methods |
bd7f2ede | 132 | virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer); |
133 | virtual void noteBodyConsumerAborted(BodyPipe::Pointer); | |
774c051c | 134 | |
5f8252d2 | 135 | // BodyConsumer methods |
bd7f2ede | 136 | virtual void noteMoreBodyDataAvailable(BodyPipe::Pointer); |
137 | virtual void noteBodyProductionEnded(BodyPipe::Pointer); | |
138 | virtual void noteBodyProducerAborted(BodyPipe::Pointer); | |
774c051c | 139 | |
140 | // comm handlers | |
141 | virtual void handleCommConnected(); | |
142 | virtual void handleCommWrote(size_t size); | |
143 | virtual void handleCommRead(size_t size); | |
144 | void handleCommWroteHeaders(); | |
145 | void handleCommWroteBody(); | |
146 | ||
147 | // service waiting | |
148 | void noteServiceReady(); | |
2dba5b8e | 149 | void noteServiceAvailable(); |
774c051c | 150 | |
5f8252d2 | 151 | public: |
26cc52cb AR |
152 | InOut virgin; |
153 | InOut adapted; | |
5f8252d2 | 154 | |
478cfe99 | 155 | // bypasses exceptions if needed and possible |
0a8bbeeb | 156 | virtual void callException(const std::exception &e); |
478cfe99 | 157 | |
64b66b76 CT |
158 | /// record error detail in the virgin request if possible |
159 | virtual void detailError(int errDetail); | |
7a957a93 | 160 | // Icap::Xaction API |
129fe2a1 | 161 | virtual void clearError(); |
d4ddb3e6 CT |
162 | /// The master transaction log entry |
163 | virtual AccessLogEntry::Pointer masterLogEntry() { return alMaster; } | |
64b66b76 | 164 | |
774c051c | 165 | private: |
5f8252d2 | 166 | virtual void start(); |
167 | ||
3ff65596 AR |
168 | /// locates the request, either as a cause or as a virgin message itself |
169 | const HttpRequest &virginRequest() const; // Must always be available | |
170 | ||
774c051c | 171 | void estimateVirginBody(); |
5f8252d2 | 172 | void makeAdaptedBodyPipe(const char *what); |
774c051c | 173 | |
174 | void waitForService(); | |
175 | ||
176 | // will not send anything [else] on the adapted pipe | |
177 | bool doneSending() const; | |
178 | ||
179 | void startWriting(); | |
180 | void writeMore(); | |
5f8252d2 | 181 | void writePreviewBody(); |
774c051c | 182 | void writePrimeBody(); |
183 | void writeSomeBody(const char *label, size_t size); | |
23e05fb1 | 184 | void decideWritingAfterPreview(const char *previewKind); |
774c051c | 185 | |
186 | void startReading(); | |
187 | void readMore(); | |
188 | virtual bool doneReading() const { return commEof || state.doneParsing(); } | |
c99de607 | 189 | virtual bool doneWriting() const { return state.doneWriting(); } |
774c051c | 190 | |
5f8252d2 | 191 | size_t virginContentSize(const VirginBodyAct &act) const; |
192 | const char *virginContentData(const VirginBodyAct &act) const; | |
193 | bool virginBodyEndReached(const VirginBodyAct &act) const; | |
194 | ||
774c051c | 195 | void makeRequestHeaders(MemBuf &buf); |
83c51da9 | 196 | void makeAllowHeader(MemBuf &buf); |
5f8252d2 | 197 | void makeUsernameHeader(const HttpRequest *request, MemBuf &buf); |
774c051c | 198 | void addLastRequestChunk(MemBuf &buf); |
c99de607 | 199 | void openChunk(MemBuf &buf, size_t chunkSize, bool ieof); |
200 | void closeChunk(MemBuf &buf); | |
774c051c | 201 | void virginConsume(); |
5f8252d2 | 202 | void finishNullOrEmptyBodyPreview(MemBuf &buf); |
774c051c | 203 | |
c824c43b | 204 | void decideOnPreview(); |
205 | void decideOnRetries(); | |
774c051c | 206 | bool shouldAllow204(); |
83c51da9 CT |
207 | bool shouldAllow206any(); |
208 | bool shouldAllow206in(); | |
209 | bool shouldAllow206out(); | |
c824c43b | 210 | bool canBackupEverything() const; |
211 | ||
774c051c | 212 | void prepBackup(size_t expectedSize); |
213 | void backup(const MemBuf &buf); | |
214 | ||
215 | void parseMore(); | |
216 | ||
217 | void parseHeaders(); | |
218 | void parseIcapHead(); | |
219 | void parseHttpHead(); | |
63df1d28 | 220 | bool parseHead(Http::Message *head); |
774c051c | 221 | |
5f8252d2 | 222 | void decideOnParsingBody(); |
774c051c | 223 | void parseBody(); |
69c698a3 | 224 | void parseIcapTrailer(); |
774c051c | 225 | void maybeAllocateHttpMsg(); |
226 | ||
227 | void handle100Continue(); | |
b559db5d | 228 | bool validate200Ok(); |
774c051c | 229 | void handle200Ok(); |
230 | void handle204NoContent(); | |
83c51da9 | 231 | void handle206PartialContent(); |
774c051c | 232 | void handleUnknownScode(); |
233 | ||
478cfe99 | 234 | void bypassFailure(); |
235 | ||
236 | void startSending(); | |
a22e6cd3 | 237 | void disableBypass(const char *reason, bool includeGroupBypass); |
478cfe99 | 238 | |
239 | void prepEchoing(); | |
83c51da9 | 240 | void prepPartialBodyEchoing(uint64_t pos); |
774c051c | 241 | void echoMore(); |
63df1d28 | 242 | void updateSources(); ///< Update the Http::Message sources |
774c051c | 243 | |
244 | virtual bool doneAll() const; | |
5f8252d2 | 245 | virtual void swanSong(); |
774c051c | 246 | |
774c051c | 247 | void stopReceiving(); |
248 | void stopSending(bool nicely); | |
c99de607 | 249 | void stopWriting(bool nicely); |
69c698a3 | 250 | void stopParsing(const bool checkUnparsedData = true); |
774c051c | 251 | void stopBackup(); |
252 | ||
253 | virtual void fillPendingStatus(MemBuf &buf) const; | |
254 | virtual void fillDoneStatus(MemBuf &buf) const; | |
3cfc19b3 | 255 | virtual bool fillVirginHttpHeader(MemBuf&) const; |
774c051c | 256 | |
257 | private: | |
69c698a3 EB |
258 | /// parses a message header or trailer |
259 | /// \returns true on success | |
260 | /// \returns false if more data is needed | |
261 | /// \throw TextException on unrecoverable error | |
262 | template<class Part> | |
263 | bool parsePart(Part *part, const char *description); | |
264 | ||
63df1d28 AJ |
265 | void packHead(MemBuf &httpBuf, const Http::Message *head); |
266 | void encapsulateHead(MemBuf &icapBuf, const char *section, MemBuf &httpBuf, const Http::Message *head); | |
774c051c | 267 | bool gotEncapsulated(const char *section) const; |
69c698a3 EB |
268 | /// whether ICAP response header indicates HTTP header presence |
269 | bool expectHttpHeader() const; | |
270 | /// whether ICAP response header indicates HTTP body presence | |
271 | bool expectHttpBody() const; | |
272 | /// whether ICAP response header indicates ICAP trailers presence | |
273 | bool expectIcapTrailers() const; | |
5f8252d2 | 274 | void checkConsuming(); |
774c051c | 275 | |
3ff65596 | 276 | virtual void finalizeLogInfo(); |
774c051c | 277 | |
278 | SizedEstimate virginBody; | |
5f8252d2 | 279 | VirginBodyAct virginBodyWriting; // virgin body writing state |
280 | VirginBodyAct virginBodySending; // virgin body sending state | |
47f6e231 | 281 | uint64_t virginConsumed; // virgin data consumed so far |
26cc52cb | 282 | Preview preview; // use for creating (writing) the preview |
774c051c | 283 | |
db1720f8 | 284 | Http1::TeChunkedParser *bodyParser; // ICAP response body parser |
774c051c | 285 | |
478cfe99 | 286 | bool canStartBypass; // enables bypass of transaction failures |
a22e6cd3 | 287 | bool protectGroupBypass; // protects ServiceGroup-wide bypass of failures |
478cfe99 | 288 | |
bae917ac CT |
289 | /** |
290 | * size of HTTP header in ICAP reply or -1 if there is not any encapsulated | |
291 | * message data | |
292 | */ | |
293 | int64_t replyHttpHeaderSize; | |
294 | /** | |
dcaab393 | 295 | * size of dechunked HTTP body in ICAP reply or -1 if there is not any |
bae917ac CT |
296 | * encapsulated message data |
297 | */ | |
298 | int64_t replyHttpBodySize; | |
3ff65596 AR |
299 | |
300 | int adaptHistoryId; ///< adaptation history slot reservation | |
301 | ||
69c698a3 EB |
302 | TrailerParser *trailerParser; |
303 | ||
774c051c | 304 | class State |
305 | { | |
306 | ||
307 | public: | |
308 | State(); | |
309 | ||
310 | public: | |
311 | ||
5f8252d2 | 312 | bool serviceWaiting; // waiting for ICAP service options |
313 | bool allowedPostview204; // mmust handle 204 No Content outside preview | |
83c51da9 CT |
314 | bool allowedPostview206; // must handle 206 Partial Content outside preview |
315 | bool allowedPreview206; // must handle 206 Partial Content inside preview | |
316 | bool readyForUob; ///< got a 206 response and expect a use-origin-body | |
2dba5b8e | 317 | bool waitedForService; ///< true if was queued at least once |
774c051c | 318 | |
319 | // will not write anything [else] to the ICAP server connection | |
c99de607 | 320 | bool doneWriting() const { return writing == writingReallyDone; } |
774c051c | 321 | |
5f8252d2 | 322 | // will not use virgin.body_pipe |
9e008dda AJ |
323 | bool doneConsumingVirgin() const { |
324 | return writing >= writingAlmostDone | |
7ddcfbab A |
325 | && ((sending == sendingAdapted && !readyForUob) || |
326 | sending == sendingDone); | |
9e008dda | 327 | } |
5f8252d2 | 328 | |
774c051c | 329 | // parsed entire ICAP response from the ICAP server |
330 | bool doneParsing() const { return parsing == psDone; } | |
331 | ||
332 | // is parsing ICAP or HTTP headers read from the ICAP server | |
9e008dda | 333 | bool parsingHeaders() const { |
774c051c | 334 | return parsing == psIcapHeader || |
335 | parsing == psHttpHeader; | |
336 | } | |
337 | ||
69c698a3 | 338 | enum Parsing { psIcapHeader, psHttpHeader, psBody, psIcapTrailer, psDone } parsing; |
774c051c | 339 | |
340 | // measures ICAP request writing progress | |
341 | enum Writing { writingInit, writingConnect, writingHeaders, | |
9e008dda AJ |
342 | writingPreview, writingPaused, writingPrime, |
343 | writingAlmostDone, // waiting for the last write() call to finish | |
344 | writingReallyDone | |
345 | } writing; | |
774c051c | 346 | |
347 | enum Sending { sendingUndecided, sendingVirgin, sendingAdapted, | |
9e008dda AJ |
348 | sendingDone |
349 | } sending; | |
2fadd50d | 350 | } state; |
774c051c | 351 | |
af0ded40 | 352 | AccessLogEntry::Pointer alMaster; ///< Master transaction AccessLogEntry |
774c051c | 353 | }; |
354 | ||
26cc52cb AR |
355 | // An Launcher that stores ModXact construction info and |
356 | // creates ModXact when needed | |
357 | class ModXactLauncher: public Launcher | |
c824c43b | 358 | { |
5c2f68b7 AJ |
359 | CBDATA_CLASS(ModXactLauncher); |
360 | ||
c824c43b | 361 | public: |
63df1d28 | 362 | ModXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, Adaptation::ServicePointer s); |
c824c43b | 363 | |
364 | protected: | |
26cc52cb | 365 | virtual Xaction *createXaction(); |
c824c43b | 366 | |
3ff65596 AR |
367 | virtual void swanSong(); |
368 | ||
369 | /// starts or stops transaction accounting in ICAP history | |
370 | void updateHistory(bool start); | |
371 | ||
26cc52cb | 372 | InOut virgin; |
c824c43b | 373 | |
af0ded40 | 374 | AccessLogEntry::Pointer al; |
c824c43b | 375 | }; |
774c051c | 376 | |
26cc52cb AR |
377 | } // namespace Icap |
378 | } // namespace Adaptation | |
379 | ||
774c051c | 380 | #endif /* SQUID_ICAPMOD_XACT_H */ |
f53969cc | 381 |