]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side_request.h
c2d5a35aa0b5ba5474b8492019948939bbdcac66
[thirdparty/squid.git] / src / client_side_request.h
1 /*
2 * Copyright (C) 1996-2025 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_CLIENT_SIDE_REQUEST_H
10 #define SQUID_SRC_CLIENT_SIDE_REQUEST_H
11
12 #include "AccessLogEntry.h"
13 #include "acl/FilledChecklist.h"
14 #include "client_side.h"
15 #include "http/forward.h"
16 #include "HttpHeaderRange.h"
17 #include "log/forward.h"
18 #include "LogTags.h"
19 #include "Store.h"
20
21 #if USE_ADAPTATION
22 #include "adaptation/forward.h"
23 #include "adaptation/Initiator.h"
24 #endif
25
26 class ClientRequestContext;
27 class ConnStateData;
28 class MemObject;
29
30 class ClientHttpRequest
31 #if USE_ADAPTATION
32 : public Adaptation::Initiator, // to start adaptation transactions
33 public BodyConsumer // to receive reply bodies in request satisf. mode
34 #endif
35 {
36 #if USE_ADAPTATION
37 CBDATA_CHILD(ClientHttpRequest);
38 #else
39 CBDATA_CLASS(ClientHttpRequest);
40 #endif
41
42 public:
43 ClientHttpRequest(ConnStateData *);
44 ClientHttpRequest(ClientHttpRequest &&) = delete;
45 #if USE_ADAPTATION
46 ~ClientHttpRequest() override;
47 #else
48 ~ClientHttpRequest();
49 #endif
50
51 String rangeBoundaryStr() const;
52 void freeResources();
53 void updateCounters();
54 void logRequest();
55 MemObject * memObject() const {
56 return (storeEntry() ? storeEntry()->mem_obj : nullptr);
57 }
58 bool multipartRangeRequest() const;
59 void processRequest();
60 void httpStart();
61 bool onlyIfCached()const;
62 bool gotEnough() const;
63 StoreEntry *storeEntry() const { return entry_; }
64 void storeEntry(StoreEntry *);
65 StoreEntry *loggingEntry() const { return loggingEntry_; }
66 void loggingEntry(StoreEntry *);
67
68 ConnStateData *getConn() const {
69 return (cbdataReferenceValid(conn_) ? conn_ : nullptr);
70 }
71
72 /// Initializes the current request with the virgin request.
73 /// Call this method when the virgin request becomes known.
74 /// To update the current request later, use resetRequest().
75 void initRequest(HttpRequest *);
76
77 /// Resets the current request to the latest adapted or redirected
78 /// request. Call this every time adaptation or redirection changes
79 /// the request. To set the virgin request, use initRequest().
80 void resetRequest(HttpRequest *);
81
82 // XXX: unify the uriChanged condition calculation with resetRequest() callers, removing this method
83 /// resetRequest() variation for callers with custom URI change detection logic
84 /// \param uriChanged whether the new request URI differs from the current request URI
85 void resetRequestXXX(HttpRequest *, bool uriChanged);
86
87 /// Checks whether the current request is internal and adjusts it accordingly.
88 void checkForInternalAccess();
89
90 /// update the code in the transaction processing tags
91 void updateLoggingTags(const LogTags_ot code) { al->cache.code.update(code); }
92
93 /// the processing tags associated with this request transaction.
94 const LogTags &loggingTags() const { return al->cache.code; }
95
96 int64_t mRangeCLen() const;
97
98 void doCallouts();
99
100 // The three methods below prepare log_uri and friends for future logging.
101 // Call the best-fit method whenever the current request or its URI changes.
102
103 /// sets log_uri when we know the current request
104 void setLogUriToRequestUri();
105
106 /// sets log_uri to a parsed request URI when Squid fails to parse or
107 /// validate other request components, yielding no current request
108 void setLogUriToRawUri(const char *, const HttpRequestMethod &);
109
110 /// sets log_uri and uri to an internally-generated "error:..." URI when
111 /// neither the current request nor the parsed request URI are known
112 void setErrorUri(const char *);
113
114 /// Prepares to satisfy a Range request with a generated HTTP 206 response.
115 /// Initializes range_iter state to allow raw range_iter access.
116 /// \returns Content-Length value for the future response; never negative
117 int64_t prepPartialResponseGeneration();
118
119 /// Build an error reply. For use with the callouts.
120 void calloutsError(const err_type, const ErrorDetail::Pointer &);
121
122 /// if necessary, stores new error information (if any)
123 void updateError(const Error &);
124
125 public:
126 /// Request currently being handled by ClientHttpRequest.
127 /// Usually remains nil until the virgin request header is parsed or faked.
128 /// Starts as a virgin request; see initRequest().
129 /// Adaptation and redirections replace it; see resetRequest().
130 HttpRequest * const request = nullptr;
131
132 /// Usually starts as a URI received from the client, with scheme and host
133 /// added if needed. Is used to create the virgin request for initRequest().
134 /// URIs of adapted/redirected requests replace it via resetRequest().
135 char *uri = nullptr;
136
137 // TODO: remove this field and store the URI directly in al->url
138 /// Cleaned up URI of the current (virgin or adapted/redirected) request,
139 /// computed URI of an internally-generated requests, or
140 /// one of the hard-coded "error:..." URIs.
141 char * const log_uri = nullptr;
142
143 String store_id; /* StoreID for transactions where the request member is nil */
144
145 struct Out {
146 /// Roughly speaking, this offset points to the next body byte we want
147 /// to receive from Store. Without Ranges (and I/O errors), we should
148 /// have received (and written to the client) all the previous bytes.
149 /// XXX: The offset is updated by various receive-write steps, making
150 /// its exact meaning illusive. Its Out class placement is confusing.
151 int64_t offset = 0;
152 /// Response header and body bytes written to the client connection.
153 uint64_t size = 0;
154 /// Response header bytes written to the client connection.
155 size_t headers_sz = 0;
156 } out;
157
158 HttpHdrRangeIter range_iter; /* data for iterating thru range specs */
159 size_t req_sz = 0; ///< raw request size on input, not current request size
160
161 const AccessLogEntry::Pointer al; ///< access.log entry
162
163 struct Flags {
164 bool accel = false;
165 bool done_copying = false;
166 } flags;
167
168 struct Redirect {
169 Http::StatusCode status = Http::scNone;
170 char *location = nullptr;
171 } redirect;
172
173 dlink_node active;
174 dlink_list client_stream;
175
176 ClientRequestContext *calloutContext = nullptr;
177
178 private:
179 /// assigns log_uri with aUri without copying the entire C-string
180 void absorbLogUri(char *);
181 /// resets the current request and log_uri to nil
182 void clearRequest();
183 /// initializes the current unassigned request to the virgin request
184 /// sets the current request, asserting that it was unset
185 void assignRequest(HttpRequest *);
186
187 int64_t maxReplyBodySize_ = 0;
188 StoreEntry *entry_ = nullptr;
189 StoreEntry *loggingEntry_ = nullptr;
190 ConnStateData * conn_ = nullptr;
191
192 #if USE_OPENSSL
193 public:
194 /// returns raw sslBump mode value
195 Ssl::BumpMode sslBumpNeed() const { return sslBumpNeed_; }
196 /// returns true if and only if the request needs to be bumped
197 bool sslBumpNeeded() const { return sslBumpNeed_ == Ssl::bumpServerFirst || sslBumpNeed_ == Ssl::bumpClientFirst || sslBumpNeed_ == Ssl::bumpBump || sslBumpNeed_ == Ssl::bumpPeek || sslBumpNeed_ == Ssl::bumpStare; }
198 /// set the sslBumpNeeded state
199 void sslBumpNeed(Ssl::BumpMode);
200 void sslBumpStart();
201 void sslBumpEstablish(Comm::Flag);
202
203 private:
204 /// whether (and how) the request needs to be bumped
205 Ssl::BumpMode sslBumpNeed_ = Ssl::bumpEnd;
206 #endif
207
208 #if USE_ADAPTATION
209 public:
210 void startAdaptation(const Adaptation::ServiceGroupPointer &);
211 bool requestSatisfactionMode() const { return request_satisfaction_mode; }
212
213 /* AsyncJob API */
214 bool doneAll() const override {
215 return Initiator::doneAll() &&
216 BodyConsumer::doneAll() &&
217 false; // TODO: Refactor into a proper AsyncJob
218 }
219 void callException(const std::exception &) override;
220
221 private:
222 /// Handles an adaptation client request failure.
223 /// Bypasses the error if possible, or build an error reply.
224 void handleAdaptationFailure(const ErrorDetail::Pointer &, bool bypassable = false);
225
226 void handleAdaptedHeader(Http::Message *);
227 void handleAdaptationBlock(const Adaptation::Answer &);
228
229 /* Adaptation::Initiator API */
230 void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer) override;
231 void noteAdaptationAnswer(const Adaptation::Answer &) override;
232
233 /* BodyConsumer API */
234 void noteMoreBodyDataAvailable(BodyPipe::Pointer) override;
235 void noteBodyProductionEnded(BodyPipe::Pointer) override;
236 void noteBodyProducerAborted(BodyPipe::Pointer) override;
237
238 void endRequestSatisfaction();
239 /// called by StoreEntry when it has more buffer space available
240 void resumeBodyStorage();
241
242 private:
243 CbcPointer<Adaptation::Initiate> virginHeadSource;
244 BodyPipe::Pointer adaptedBodySource;
245
246 /// noteBodyProductionEnded() was called
247 bool receivedWholeAdaptedReply = false;
248
249 bool request_satisfaction_mode = false;
250 int64_t request_satisfaction_offset = 0;
251 #endif
252 };
253
254 /* client http based routines */
255 char *clientConstructTraceEcho(ClientHttpRequest *);
256
257 ACLFilledChecklist::MakingPointer clientAclChecklistCreate(const acl_access *, ClientHttpRequest *);
258 void clientAclChecklistFill(ACLFilledChecklist &, ClientHttpRequest *);
259 void clientAccessCheck(ClientHttpRequest *);
260
261 /* ones that should be elsewhere */
262 void tunnelStart(ClientHttpRequest *);
263
264 #endif /* SQUID_SRC_CLIENT_SIDE_REQUEST_H */