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