1 /*
2  * Copyright (C) 1996-2021 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_CLIENTSIDEREQUEST_H
10 #define SQUID_CLIENTSIDEREQUEST_H
11 
12 #include "AccessLogEntry.h"
13 #include "acl/forward.h"
14 #include "client_side.h"
15 #include "clientStream.h"
16 #include "http/forward.h"
17 #include "HttpHeaderRange.h"
18 #include "LogTags.h"
19 
20 #if USE_ADAPTATION
21 #include "adaptation/forward.h"
22 #include "adaptation/Initiator.h"
23 class HttpMsg;
24 #endif
25 
26 class ClientRequestContext;
27 class ConnStateData;
28 class MemObject;
29 
30 /* client_side_request.c - client side request related routines (pure logic) */
31 int clientBeginRequest(const HttpRequestMethod&, char const *, CSCB *, CSD *, ClientStreamData, HttpHeader const *, char *, size_t, const MasterXactionPointer &);
32 
33 class ClientHttpRequest
34 #if USE_ADAPTATION
35     : public Adaptation::Initiator, // to start adaptation transactions
36       public BodyConsumer     // to receive reply bodies in request satisf. mode
37 #endif
38 {
39     CBDATA_CLASS(ClientHttpRequest);
40 
41 public:
42     ClientHttpRequest(ConnStateData *csd);
43     ~ClientHttpRequest();
44     /* Not implemented - present to prevent synthetic operations */
45     ClientHttpRequest(ClientHttpRequest const &);
46     ClientHttpRequest& operator=(ClientHttpRequest const &);
47 
48     String rangeBoundaryStr() const;
49     void freeResources();
50     void updateCounters();
51     void logRequest();
52     _SQUID_INLINE_ MemObject * memObject() const;
53     bool multipartRangeRequest() const;
54     void processRequest();
55     void httpStart();
56     bool onlyIfCached()const;
57     bool gotEnough() const;
58     _SQUID_INLINE_ StoreEntry *storeEntry() const;
59     void storeEntry(StoreEntry *);
60     _SQUID_INLINE_ StoreEntry *loggingEntry() const;
61     void loggingEntry(StoreEntry *);
62 
63     _SQUID_INLINE_ ConnStateData * getConn() const;
64     _SQUID_INLINE_ void setConn(ConnStateData *);
65 
66     /// Initializes the current request with the virgin request.
67     /// Call this method when the virgin request becomes known.
68     /// To update the current request later, use resetRequest().
69     void initRequest(HttpRequest *);
70 
71     /// Resets the current request to the latest adapted or redirected
72     /// request. Call this every time adaptation or redirection changes
73     /// the request. To set the virgin request, use initRequest().
74     void resetRequest(HttpRequest *);
75 
76     /** Details of the client socket which produced us.
77      * Treat as read-only for the lifetime of this HTTP request.
78      */
79     Comm::ConnectionPointer clientConnection;
80 
81     /// Request currently being handled by ClientHttpRequest.
82     /// Starts as a virgin request; see initRequest().
83     /// Usually remains nil until the virgin request header is parsed or faked.
84     /// Adaptation and redirections replace it; see resetRequest().
85     HttpRequest * const request;
86     /// Usually starts as a URI received from the client, with scheme and host
87     /// added if needed. Is used to create the virgin request for initRequest().
88     /// URIs of adapted/redirected requests replace it via resetRequest().
89     char *uri;
90 
91     // TODO: remove this field and store the URI directly in al->url
92     /// Cleaned up URI of the current (virgin or adapted/redirected) request,
93     /// computed URI of an internally-generated requests, or
94     /// one of the hard-coded "error:..." URIs.
95     char * const log_uri;
96 
97     String store_id; /* StoreID for transactions where the request member is nil */
98 
99     struct Out {
OutOut100         Out() : offset(0), size(0), headers_sz(0) {}
101 
102         int64_t offset;
103         uint64_t size;
104         size_t headers_sz;
105     } out;
106 
107     HttpHdrRangeIter range_iter;    /* data for iterating thru range specs */
108     size_t req_sz;      /* raw request size on input, not current request size */
109 
110     /// the processing tags associated with this request transaction.
111     // NP: still an enum so each stage altering it must take care when replacing it.
112     LogTags logType;
113 
114     AccessLogEntry::Pointer al; ///< access.log entry
115 
116     struct Flags {
FlagsFlags117         Flags() : accel(false), internal(false), done_copying(false), purging(false) {}
118 
119         bool accel;
120         bool internal;
121         bool done_copying;
122         bool purging;
123     } flags;
124 
125     struct Redirect {
RedirectRedirect126         Redirect() : status(Http::scNone), location(NULL) {}
127 
128         Http::StatusCode status;
129         char *location;
130     } redirect;
131 
132     dlink_node active;
133     dlink_list client_stream;
134     int64_t mRangeCLen() const;
135 
136     ClientRequestContext *calloutContext;
137     void doCallouts();
138 
139     // The three methods below prepare log_uri and friends for future logging.
140     // Call the best-fit method whenever the current request or its URI changes.
141 
142     /// sets log_uri when we know the current request
143     void setLogUriToRequestUri();
144     /// sets log_uri to a parsed request URI when Squid fails to parse or
145     /// validate other request components, yielding no current request
146     void setLogUriToRawUri(const char *rawUri, const HttpRequestMethod &);
147     /// sets log_uri and uri to an internally-generated "error:..." URI when
148     /// neither the current request nor the parsed request URI are known
149     void setErrorUri(const char *errorUri);
150 
151     /// Prepares to satisfy a Range request with a generated HTTP 206 response.
152     /// Initializes range_iter state to allow raw range_iter access.
153     /// \returns Content-Length value for the future response; never negative
154     int64_t prepPartialResponseGeneration();
155 
156     /// Build an error reply. For use with the callouts.
157     void calloutsError(const err_type error, const int errDetail);
158 
159 #if USE_ADAPTATION
160     // AsyncJob virtual methods
doneAll()161     virtual bool doneAll() const {
162         return Initiator::doneAll() &&
163                BodyConsumer::doneAll() && false;
164     }
165     virtual void callException(const std::exception &ex);
166 #endif
167 
168 private:
169     /// assigns log_uri with aUri without copying the entire C-string
170     void absorbLogUri(char *aUri);
171     /// resets the current request and log_uri to nil
172     void clearRequest();
173     /// initializes the current unassigned request to the virgin request
174     /// sets the current request, asserting that it was unset
175     void assignRequest(HttpRequest *aRequest);
176 
177     int64_t maxReplyBodySize_;
178     StoreEntry *entry_;
179     StoreEntry *loggingEntry_;
180     ConnStateData * conn_;
181 
182 #if USE_OPENSSL
183     /// whether (and how) the request needs to be bumped
184     Ssl::BumpMode sslBumpNeed_;
185 
186 public:
187     /// returns raw sslBump mode value
sslBumpNeed()188     Ssl::BumpMode sslBumpNeed() const { return sslBumpNeed_; }
189     /// returns true if and only if the request needs to be bumped
sslBumpNeeded()190     bool sslBumpNeeded() const { return sslBumpNeed_ == Ssl::bumpServerFirst || sslBumpNeed_ == Ssl::bumpClientFirst || sslBumpNeed_ == Ssl::bumpBump || sslBumpNeed_ == Ssl::bumpPeek || sslBumpNeed_ == Ssl::bumpStare; }
191     /// set the sslBumpNeeded state
192     void sslBumpNeed(Ssl::BumpMode mode);
193     void sslBumpStart();
194     void sslBumpEstablish(Comm::Flag errflag);
195 #endif
196 
197 #if USE_ADAPTATION
198 
199 public:
200     void startAdaptation(const Adaptation::ServiceGroupPointer &g);
requestSatisfactionMode()201     bool requestSatisfactionMode() const { return request_satisfaction_mode; }
202 
203 private:
204     /// Handles an adaptation client request failure.
205     /// Bypasses the error if possible, or build an error reply.
206     void handleAdaptationFailure(int errDetail, bool bypassable = false);
207 
208     // Adaptation::Initiator API
209     virtual void noteAdaptationAnswer(const Adaptation::Answer &answer);
210     void handleAdaptedHeader(HttpMsg *msg);
211     void handleAdaptationBlock(const Adaptation::Answer &answer);
212     virtual void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group);
213 
214     // BodyConsumer API, called by BodyPipe
215     virtual void noteMoreBodyDataAvailable(BodyPipe::Pointer);
216     virtual void noteBodyProductionEnded(BodyPipe::Pointer);
217     virtual void noteBodyProducerAborted(BodyPipe::Pointer);
218 
219     void endRequestSatisfaction();
220     /// called by StoreEntry when it has more buffer space available
221     void resumeBodyStorage();
222 
223 private:
224     CbcPointer<Adaptation::Initiate> virginHeadSource;
225     BodyPipe::Pointer adaptedBodySource;
226 
227     bool request_satisfaction_mode;
228     int64_t request_satisfaction_offset;
229 #endif
230 };
231 
232 /* client http based routines */
233 char *clientConstructTraceEcho(ClientHttpRequest *);
234 
235 ACLFilledChecklist *clientAclChecklistCreate(const acl_access * acl,ClientHttpRequest * http);
236 int clientHttpRequestStatus(int fd, ClientHttpRequest const *http);
237 void clientAccessCheck(ClientHttpRequest *);
238 
239 /* ones that should be elsewhere */
240 void tunnelStart(ClientHttpRequest *);
241 
242 #if _USE_INLINE_
243 #include "client_side_request.cci"
244 #include "Store.h"
245 #endif
246 
247 #endif /* SQUID_CLIENTSIDEREQUEST_H */
248 
249