]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/icap/ModXact.h
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / adaptation / icap / ModXact.h
CommitLineData
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
29namespace Adaptation
30{
e1381638
AJ
31namespace Icap
32{
26cc52cb 33
774c051c 34// estimated future presence and size of something (e.g., HTTP body)
35
36class SizedEstimate
37{
38
39public:
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
49private:
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.
59class VirginBodyAct
774c051c 60{
61
62public:
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
76private:
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 85class Preview
774c051c 86{
87
88public:
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
102private:
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.
109class TrailerParser
110{
111public:
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 123class ModXact: public Xaction, public BodyProducer, public BodyConsumer
774c051c 124{
5c2f68b7 125 CBDATA_CLASS(ModXact);
774c051c 126
774c051c 127public:
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 151public:
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 165private:
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
257private:
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
357class ModXactLauncher: public Launcher
c824c43b 358{
5c2f68b7
AJ
359 CBDATA_CLASS(ModXactLauncher);
360
c824c43b 361public:
63df1d28 362 ModXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, Adaptation::ServicePointer s);
c824c43b 363
364protected:
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