]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
SourceLayout: rename ClientSocketContext to Http::Stream
[thirdparty/squid.git] / src / client_side.h
1 /*
2 * Copyright (C) 1996-2016 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 /* DEBUG: section 33 Client-side Routines */
10
11 #ifndef SQUID_CLIENTSIDE_H
12 #define SQUID_CLIENTSIDE_H
13
14 #include "base/RunnersRegistry.h"
15 #include "clientStreamForward.h"
16 #include "comm.h"
17 #include "helper/forward.h"
18 #include "http/forward.h"
19 #include "HttpControlMsg.h"
20 #include "ipc/FdNotes.h"
21 #include "SBuf.h"
22 #include "servers/Server.h"
23 #if USE_AUTH
24 #include "auth/UserRequest.h"
25 #endif
26 #if USE_OPENSSL
27 #include "ssl/support.h"
28 #endif
29
30 class ClientHttpRequest;
31 class HttpHdrRangeSpec;
32
33 #if USE_OPENSSL
34 namespace Ssl
35 {
36 class ServerBump;
37 }
38 #endif
39
40 /**
41 * Legacy Server code managing a connection to a client.
42 *
43 * NP: presents AsyncJob API but does not operate autonomously as a Job.
44 * So Must() is not safe to use.
45 *
46 * Multiple requests (up to pipeline_prefetch) can be pipelined.
47 * This object is responsible for managing which one is currently being
48 * fulfilled and what happens to the queue if the current one causes the client
49 * connection to be closed early.
50 *
51 * Act as a manager for the client connection and passes data in buffer to a
52 * Parser relevant to the state (message headers vs body) that is being
53 * processed.
54 *
55 * Performs HTTP message processing to kick off the actual HTTP request
56 * handling objects (Http::Stream, ClientHttpRequest, HttpRequest).
57 *
58 * Performs SSL-Bump processing for switching between HTTP and HTTPS protocols.
59 *
60 * To terminate a ConnStateData close() the client Comm::Connection it is
61 * managing, or for graceful half-close use the stopReceiving() or
62 * stopSending() methods.
63 */
64 class ConnStateData : public Server, public HttpControlMsgSink, public RegisteredRunner
65 {
66
67 public:
68 explicit ConnStateData(const MasterXaction::Pointer &xact);
69 virtual ~ConnStateData();
70
71 /* ::Server API */
72 virtual void receivedFirstByte();
73 virtual bool handleReadData();
74 virtual void afterClientRead();
75 virtual void afterClientWrite(size_t);
76
77 /* HttpControlMsgSink API */
78 virtual void sendControlMsg(HttpControlMsg);
79
80 /// Traffic parsing
81 bool clientParseRequests();
82 void readNextRequest();
83
84 /// try to make progress on a transaction or read more I/O
85 void kick();
86
87 bool isOpen() const;
88
89 Http1::TeChunkedParser *bodyParser; ///< parses HTTP/1.1 chunked request body
90
91 /** number of body bytes we need to comm_read for the "current" request
92 *
93 * \retval 0 We do not need to read any [more] body bytes
94 * \retval negative May need more but do not know how many; could be zero!
95 * \retval positive Need to read exactly that many more body bytes
96 */
97 int64_t mayNeedToReadMoreBody() const;
98
99 #if USE_AUTH
100 /**
101 * Fetch the user details for connection based authentication
102 * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
103 */
104 const Auth::UserRequest::Pointer &getAuth() const { return auth_; }
105
106 /**
107 * Set the user details for connection-based authentication to use from now until connection closure.
108 *
109 * Any change to existing credentials shows that something invalid has happened. Such as:
110 * - NTLM/Negotiate auth was violated by the per-request headers missing a revalidation token
111 * - NTLM/Negotiate auth was violated by the per-request headers being for another user
112 * - SSL-Bump CONNECT tunnel with persistent credentials has ended
113 */
114 void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause);
115 #endif
116
117 Ip::Address log_addr;
118
119 struct {
120 bool readMore; ///< needs comm_read (for this request or new requests)
121 bool swanSang; // XXX: temporary flag to check proper cleanup
122 } flags;
123 struct {
124 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
125 char *host; /* host name of pinned connection */
126 int port; /* port of pinned connection */
127 bool pinned; /* this connection was pinned */
128 bool auth; /* pinned for www authentication */
129 bool reading; ///< we are monitoring for peer connection closure
130 bool zeroReply; ///< server closed w/o response (ERR_ZERO_SIZE_OBJECT)
131 CachePeer *peer; /* CachePeer the connection goes via */
132 AsyncCall::Pointer readHandler; ///< detects serverConnection closure
133 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
134 } pinning;
135
136 bool transparent() const;
137
138 /// true if we stopped receiving the request
139 const char *stoppedReceiving() const { return stoppedReceiving_; }
140 /// true if we stopped sending the response
141 const char *stoppedSending() const { return stoppedSending_; }
142 /// note request receiving error and close as soon as we write the response
143 void stopReceiving(const char *error);
144 /// note response sending error and close as soon as we read the request
145 void stopSending(const char *error);
146
147 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
148
149 /* BodyPipe API */
150 BodyPipe::Pointer expectRequestBody(int64_t size);
151 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer) = 0;
152 virtual void noteBodyConsumerAborted(BodyPipe::Pointer) = 0;
153
154 bool handleRequestBodyData();
155
156 /// Forward future client requests using the given server connection.
157 /// Optionally, monitor pinned server connection for remote-end closures.
158 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth, bool monitor = true);
159 /// Undo pinConnection() and, optionally, close the pinned connection.
160 void unpinConnection(const bool andClose);
161 /// Returns validated pinnned server connection (and stops its monitoring).
162 Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer);
163 /**
164 * Checks if there is pinning info if it is valid. It can close the server side connection
165 * if pinned info is not valid.
166 \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
167 \param CachePeer if it is not NULL also check if the CachePeer is the pinning CachePeer
168 \return The details of the server side connection (may be closed if failures were present).
169 */
170 const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const CachePeer *peer);
171 /**
172 * returts the pinned CachePeer if exists, NULL otherwise
173 */
174 CachePeer *pinnedPeer() const {return pinning.peer;}
175 bool pinnedAuth() const {return pinning.auth;}
176
177 /// called just before a FwdState-dispatched job starts using connection
178 virtual void notePeerConnection(Comm::ConnectionPointer) {}
179
180 // pining related comm callbacks
181 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
182
183 // comm callbacks
184 void clientReadFtpData(const CommIoCbParams &io);
185 void connStateClosed(const CommCloseCbParams &io);
186 void requestTimeout(const CommTimeoutCbParams &params);
187
188 // AsyncJob API
189 virtual void start();
190 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
191 virtual void swanSong();
192
193 /// Changes state so that we close the connection and quit after serving
194 /// the client-side-detected error response instead of getting stuck.
195 void quitAfterError(HttpRequest *request); // meant to be private
196
197 /// The caller assumes responsibility for connection closure detection.
198 void stopPinnedConnectionMonitoring();
199
200 #if USE_OPENSSL
201 /// the second part of old httpsAccept, waiting for future HttpsServer home
202 void postHttpsAccept();
203
204 /// Initializes and starts a peek-and-splice negotiation with the SSL client
205 void startPeekAndSplice();
206 /// Called when the initialization of peek-and-splice negotiation finidhed
207 void startPeekAndSpliceDone();
208 /// Called when a peek-and-splice step finished. For example after
209 /// server SSL certificates received and fake server SSL certificates
210 /// generated
211 void doPeekAndSpliceStep();
212 /// called by FwdState when it is done bumping the server
213 void httpsPeeked(Comm::ConnectionPointer serverConnection);
214
215 /// Splice a bumped client connection on peek-and-splice mode
216 void splice();
217
218 /// Check on_unsupported_protocol access list and splice if required
219 /// \retval true on splice
220 /// \retval false otherwise
221 bool spliceOnError(const err_type err);
222
223 /// Start to create dynamic Security::ContextPtr for host or uses static port SSL context.
224 void getSslContextStart();
225 /**
226 * Done create dynamic ssl certificate.
227 *
228 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
229 */
230 void getSslContextDone(Security::ContextPtr sslContext, bool isNew = false);
231 /// Callback function. It is called when squid receive message from ssl_crtd.
232 static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
233 /// Proccess response from ssl_crtd.
234 void sslCrtdHandleReply(const Helper::Reply &reply);
235
236 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
237 bool switchedToHttps() const { return switchedToHttps_; }
238 Ssl::ServerBump *serverBump() {return sslServerBump;}
239 inline void setServerBump(Ssl::ServerBump *srvBump) {
240 if (!sslServerBump)
241 sslServerBump = srvBump;
242 else
243 assert(sslServerBump == srvBump);
244 }
245 const SBuf &sslCommonName() const {return sslCommonName_;}
246 void resetSslCommonName(const char *name) {sslCommonName_ = name;}
247 /// Fill the certAdaptParams with the required data for certificate adaptation
248 /// and create the key for storing/retrieve the certificate to/from the cache
249 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
250 /// Called when the client sends the first request on a bumped connection.
251 /// Returns false if no [delayed] error should be written to the client.
252 /// Otherwise, writes the error to the client and returns true. Also checks
253 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
254 bool serveDelayedError(Http::Stream *);
255
256 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
257
258 #else
259 bool switchedToHttps() const { return false; }
260 #endif
261
262 /* clt_conn_tag=tag annotation access */
263 const SBuf &connectionTag() const { return connectionTag_; }
264 void connectionTag(const char *aTag) { connectionTag_ = aTag; }
265
266 /// handle a control message received by context from a peer and call back
267 virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
268
269 /// ClientStream calls this to supply response header (once) and data
270 /// for the current Http::Stream.
271 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) = 0;
272
273 /// remove no longer needed leading bytes from the input buffer
274 void consumeInput(const size_t byteCount);
275
276 /* TODO: Make the methods below (at least) non-public when possible. */
277
278 /// stop parsing the request and create context for relaying error info
279 Http::Stream *abortRequestParsing(const char *const errUri);
280
281 /// generate a fake CONNECT request with the given payload
282 /// at the beginning of the client I/O buffer
283 void fakeAConnectRequest(const char *reason, const SBuf &payload);
284
285 /// client data which may need to forward as-is to server after an
286 /// on_unsupported_protocol tunnel decision.
287 SBuf preservedClientData;
288
289 /* Registered Runner API */
290 virtual void startShutdown();
291 virtual void endingShutdown();
292
293 protected:
294 void startDechunkingRequest();
295 void finishDechunkingRequest(bool withSuccess);
296 void abortChunkedRequestBody(const err_type error);
297 err_type handleChunkedRequestBody();
298
299 void startPinnedConnectionMonitoring();
300 void clientPinnedConnectionRead(const CommIoCbParams &io);
301 #if USE_OPENSSL
302 /// Handles a ready-for-reading TLS squid-to-server connection that
303 /// we thought was idle.
304 /// \return false if and only if the connection should be closed.
305 bool handleIdleClientPinnedTlsRead();
306 #endif
307
308 /// parse input buffer prefix into a single transfer protocol request
309 /// return NULL to request more header bytes (after checking any limits)
310 /// use abortRequestParsing() to handle parsing errors w/o creating request
311 virtual Http::Stream *parseOneRequest() = 0;
312
313 /// start processing a freshly parsed request
314 virtual void processParsedRequest(Http::Stream *) = 0;
315
316 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
317 virtual int pipelinePrefetchMax() const;
318
319 /// timeout to use when waiting for the next request
320 virtual time_t idleTimeout() const = 0;
321
322 BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
323
324 private:
325 /* ::Server API */
326 virtual bool connFinishedWithConn(int size);
327
328 void clientAfterReadingRequests();
329 bool concurrentRequestQueueFilled() const;
330
331 void pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth);
332
333 /* PROXY protocol functionality */
334 bool proxyProtocolValidateClient();
335 bool parseProxyProtocolHeader();
336 bool parseProxy1p0();
337 bool parseProxy2p0();
338 bool proxyProtocolError(const char *reason);
339
340 /// whether PROXY protocol header is still expected
341 bool needProxyProtocolHeader_;
342
343 #if USE_AUTH
344 /// some user details that can be used to perform authentication on this connection
345 Auth::UserRequest::Pointer auth_;
346 #endif
347
348 /// the parser state for current HTTP/1.x input buffer processing
349 Http1::RequestParserPointer parser_;
350
351 #if USE_OPENSSL
352 bool switchedToHttps_;
353 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
354 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
355 SBuf sslCommonName_; ///< CN name for SSL certificate generation
356 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
357
358 /// HTTPS server cert. fetching state for bump-ssl-server-first
359 Ssl::ServerBump *sslServerBump;
360 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
361 #endif
362
363 /// the reason why we no longer write the response or nil
364 const char *stoppedSending_;
365 /// the reason why we no longer read the request or nil
366 const char *stoppedReceiving_;
367
368 SBuf connectionTag_; ///< clt_conn_tag=Tag annotation for client connection
369 };
370
371 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
372
373 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
374
375 int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
376
377 /// accept requests to a given port and inform subCall about them
378 void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId noteId);
379
380 void clientOpenListenSockets(void);
381 void clientConnectionsClose(void);
382 void httpRequestFree(void *);
383
384 /// decide whether to expect multiple requests on the corresponding connection
385 void clientSetKeepaliveFlag(ClientHttpRequest *http);
386
387 /// append a "part" HTTP header (as in a multi-part/range reply) to the buffer
388 void clientPackRangeHdr(const HttpReply *, const HttpHdrRangeSpec *, String boundary, MemBuf *);
389
390 /// put terminating boundary for multiparts to the buffer
391 void clientPackTermBound(String boundary, MemBuf *);
392
393 /* misplaced declaratrions of Stream callbacks provided/used by client side */
394 SQUIDCEXTERN CSR clientGetMoreData;
395 SQUIDCEXTERN CSS clientReplyStatus;
396 SQUIDCEXTERN CSD clientReplyDetach;
397 CSCB clientSocketRecipient;
398 CSD clientSocketDetach;
399
400 /* TODO: Move to HttpServer. Warning: Move requires large code nonchanges! */
401 Http::Stream *parseHttpRequest(ConnStateData *, const Http1::RequestParserPointer &);
402 void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, Http::Stream *);
403 void clientPostHttpsAccept(ConnStateData *);
404
405 #endif /* SQUID_CLIENTSIDE_H */
406