2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
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.
9 #ifndef SQUID_SRC_CLIENT_SIDE_REQUEST_H
10 #define SQUID_SRC_CLIENT_SIDE_REQUEST_H
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"
22 #include "adaptation/forward.h"
23 #include "adaptation/Initiator.h"
26 class ClientRequestContext
;
30 class ClientHttpRequest
32 : public Adaptation::Initiator
, // to start adaptation transactions
33 public BodyConsumer
// to receive reply bodies in request satisf. mode
37 CBDATA_CHILD(ClientHttpRequest
);
39 CBDATA_CLASS(ClientHttpRequest
);
43 ClientHttpRequest(ConnStateData
*);
44 ClientHttpRequest(ClientHttpRequest
&&) = delete;
46 ~ClientHttpRequest() override
;
51 String
rangeBoundaryStr() const;
53 void updateCounters();
55 MemObject
* memObject() const {
56 return (storeEntry() ? storeEntry()->mem_obj
: nullptr);
58 bool multipartRangeRequest() const;
59 void processRequest();
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
*);
68 ConnStateData
*getConn() const {
69 return (cbdataReferenceValid(conn_
) ? conn_
: nullptr);
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
*);
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
*);
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
);
87 /// Checks whether the current request is internal and adjusts it accordingly.
88 void checkForInternalAccess();
90 /// update the code in the transaction processing tags
91 void updateLoggingTags(const LogTags_ot code
) { al
->cache
.code
.update(code
); }
93 /// the processing tags associated with this request transaction.
94 const LogTags
&loggingTags() const { return al
->cache
.code
; }
96 int64_t mRangeCLen() const;
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.
103 /// sets log_uri when we know the current request
104 void setLogUriToRequestUri();
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
&);
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 *);
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();
119 /// Build an error reply. For use with the callouts.
120 void calloutsError(const err_type
, const ErrorDetail::Pointer
&);
122 /// if necessary, stores new error information (if any)
123 void updateError(const Error
&);
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;
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().
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;
143 String store_id
; /* StoreID for transactions where the request member is nil */
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.
152 /// Response header and body bytes written to the client connection.
154 /// Response header bytes written to the client connection.
155 size_t headers_sz
= 0;
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
161 const AccessLogEntry::Pointer al
; ///< access.log entry
165 bool done_copying
= false;
169 Http::StatusCode status
= Http::scNone
;
170 char *location
= nullptr;
174 dlink_list client_stream
;
176 ClientRequestContext
*calloutContext
= nullptr;
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
183 /// initializes the current unassigned request to the virgin request
184 /// sets the current request, asserting that it was unset
185 void assignRequest(HttpRequest
*);
187 int64_t maxReplyBodySize_
= 0;
188 StoreEntry
*entry_
= nullptr;
189 StoreEntry
*loggingEntry_
= nullptr;
190 ConnStateData
* conn_
= nullptr;
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
);
201 void sslBumpEstablish(Comm::Flag
);
204 /// whether (and how) the request needs to be bumped
205 Ssl::BumpMode sslBumpNeed_
= Ssl::bumpEnd
;
210 void startAdaptation(const Adaptation::ServiceGroupPointer
&);
211 bool requestSatisfactionMode() const { return request_satisfaction_mode
; }
214 bool doneAll() const override
{
215 return Initiator::doneAll() &&
216 BodyConsumer::doneAll() &&
217 false; // TODO: Refactor into a proper AsyncJob
219 void callException(const std::exception
&) override
;
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);
226 void handleAdaptedHeader(Http::Message
*);
227 void handleAdaptationBlock(const Adaptation::Answer
&);
229 /* Adaptation::Initiator API */
230 void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer
) override
;
231 void noteAdaptationAnswer(const Adaptation::Answer
&) override
;
233 /* BodyConsumer API */
234 void noteMoreBodyDataAvailable(BodyPipe::Pointer
) override
;
235 void noteBodyProductionEnded(BodyPipe::Pointer
) override
;
236 void noteBodyProducerAborted(BodyPipe::Pointer
) override
;
238 void endRequestSatisfaction();
239 /// called by StoreEntry when it has more buffer space available
240 void resumeBodyStorage();
243 CbcPointer
<Adaptation::Initiate
> virginHeadSource
;
244 BodyPipe::Pointer adaptedBodySource
;
246 /// noteBodyProductionEnded() was called
247 bool receivedWholeAdaptedReply
= false;
249 bool request_satisfaction_mode
= false;
250 int64_t request_satisfaction_offset
= 0;
254 /* client http based routines */
255 char *clientConstructTraceEcho(ClientHttpRequest
*);
257 ACLFilledChecklist::MakingPointer
clientAclChecklistCreate(const acl_access
*, ClientHttpRequest
*);
258 void clientAclChecklistFill(ACLFilledChecklist
&, ClientHttpRequest
*);
259 void clientAccessCheck(ClientHttpRequest
*);
261 /* ones that should be elsewhere */
262 void tunnelStart(ClientHttpRequest
*);
264 #endif /* SQUID_SRC_CLIENT_SIDE_REQUEST_H */