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