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