]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
merge from trunk r14590
[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/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 virtual 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 /// If the port is not set then it is a connection-less object
137 /// created by an internal squid subsystem
138 bool connectionless() const { return port == NULL; }
139
140 bool transparent() const;
141
142 /// true if we stopped receiving the request
143 const char *stoppedReceiving() const { return stoppedReceiving_; }
144 /// true if we stopped sending the response
145 const char *stoppedSending() const { return stoppedSending_; }
146 /// note request receiving error and close as soon as we write the response
147 void stopReceiving(const char *error);
148 /// note response sending error and close as soon as we read the request
149 void stopSending(const char *error);
150
151 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
152
153 /* BodyPipe API */
154 BodyPipe::Pointer expectRequestBody(int64_t size);
155 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer) = 0;
156 virtual void noteBodyConsumerAborted(BodyPipe::Pointer) = 0;
157
158 bool handleRequestBodyData();
159
160 /// Forward future client requests using the given server connection.
161 /// Optionally, monitor pinned server connection for remote-end closures.
162 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth, bool monitor = true);
163 /// Undo pinConnection() and, optionally, close the pinned connection.
164 void unpinConnection(const bool andClose);
165 /// Returns validated pinnned server connection (and stops its monitoring).
166 Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer);
167 /**
168 * Checks if there is pinning info if it is valid. It can close the server side connection
169 * if pinned info is not valid.
170 \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
171 \param CachePeer if it is not NULL also check if the CachePeer is the pinning CachePeer
172 \return The details of the server side connection (may be closed if failures were present).
173 */
174 const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const CachePeer *peer);
175 /**
176 * returts the pinned CachePeer if exists, NULL otherwise
177 */
178 CachePeer *pinnedPeer() const {return pinning.peer;}
179 bool pinnedAuth() const {return pinning.auth;}
180
181 /// called just before a FwdState-dispatched job starts using connection
182 virtual void notePeerConnection(Comm::ConnectionPointer) {}
183
184 // pining related comm callbacks
185 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
186
187 // comm callbacks
188 void clientReadFtpData(const CommIoCbParams &io);
189 void connStateClosed(const CommCloseCbParams &io);
190 void requestTimeout(const CommTimeoutCbParams &params);
191
192 // AsyncJob API
193 virtual void start();
194 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
195 virtual void swanSong();
196
197 /// Changes state so that we close the connection and quit after serving
198 /// the client-side-detected error response instead of getting stuck.
199 void quitAfterError(HttpRequest *request); // meant to be private
200
201 /// The caller assumes responsibility for connection closure detection.
202 void stopPinnedConnectionMonitoring();
203
204 #if USE_OPENSSL
205 /// the second part of old httpsAccept, waiting for future HttpsServer home
206 void postHttpsAccept();
207
208 /// Initializes and starts a peek-and-splice negotiation with the SSL client
209 void startPeekAndSplice();
210 /// Called when the initialization of peek-and-splice negotiation finidhed
211 void startPeekAndSpliceDone();
212 /// Called when a peek-and-splice step finished. For example after
213 /// server SSL certificates received and fake server SSL certificates
214 /// generated
215 void doPeekAndSpliceStep();
216 /// called by FwdState when it is done bumping the server
217 void httpsPeeked(Comm::ConnectionPointer serverConnection);
218
219 /// Splice a bumped client connection on peek-and-splice mode
220 void splice();
221
222 /// Check on_unsupported_protocol access list and splice if required
223 /// \retval true on splice
224 /// \retval false otherwise
225 bool spliceOnError(const err_type err);
226
227 /// Start to create dynamic Security::ContextPtr for host or uses static port SSL context.
228 void getSslContextStart();
229 /**
230 * Done create dynamic ssl certificate.
231 *
232 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
233 */
234 void getSslContextDone(Security::ContextPtr sslContext, bool isNew = false);
235 /// Callback function. It is called when squid receive message from ssl_crtd.
236 static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
237 /// Proccess response from ssl_crtd.
238 void sslCrtdHandleReply(const Helper::Reply &reply);
239
240 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
241 bool switchedToHttps() const { return switchedToHttps_; }
242 Ssl::ServerBump *serverBump() {return sslServerBump;}
243 inline void setServerBump(Ssl::ServerBump *srvBump) {
244 if (!sslServerBump)
245 sslServerBump = srvBump;
246 else
247 assert(sslServerBump == srvBump);
248 }
249 const SBuf &sslCommonName() const {return sslCommonName_;}
250 void resetSslCommonName(const char *name) {sslCommonName_ = name;}
251 /// Fill the certAdaptParams with the required data for certificate adaptation
252 /// and create the key for storing/retrieve the certificate to/from the cache
253 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
254 /// Called when the client sends the first request on a bumped connection.
255 /// Returns false if no [delayed] error should be written to the client.
256 /// Otherwise, writes the error to the client and returns true. Also checks
257 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
258 bool serveDelayedError(Http::Stream *);
259
260 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
261
262 #else
263 bool switchedToHttps() const { return false; }
264 #endif
265
266 /* clt_conn_tag=tag annotation access */
267 const SBuf &connectionTag() const { return connectionTag_; }
268 void connectionTag(const char *aTag) { connectionTag_ = aTag; }
269
270 /// handle a control message received by context from a peer and call back
271 virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
272
273 /// ClientStream calls this to supply response header (once) and data
274 /// for the current Http::Stream.
275 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) = 0;
276
277 /// remove no longer needed leading bytes from the input buffer
278 void consumeInput(const size_t byteCount);
279
280 /* TODO: Make the methods below (at least) non-public when possible. */
281
282 /// stop parsing the request and create context for relaying error info
283 Http::Stream *abortRequestParsing(const char *const errUri);
284
285 /// generate a fake CONNECT request with the given payload
286 /// at the beginning of the client I/O buffer
287 void fakeAConnectRequest(const char *reason, const SBuf &payload);
288
289 /// client data which may need to forward as-is to server after an
290 /// on_unsupported_protocol tunnel decision.
291 SBuf preservedClientData;
292
293 /* Registered Runner API */
294 virtual void startShutdown();
295 virtual void endingShutdown();
296
297 protected:
298 void startDechunkingRequest();
299 void finishDechunkingRequest(bool withSuccess);
300 void abortChunkedRequestBody(const err_type error);
301 err_type handleChunkedRequestBody();
302
303 void startPinnedConnectionMonitoring();
304 void clientPinnedConnectionRead(const CommIoCbParams &io);
305 #if USE_OPENSSL
306 /// Handles a ready-for-reading TLS squid-to-server connection that
307 /// we thought was idle.
308 /// \return false if and only if the connection should be closed.
309 bool handleIdleClientPinnedTlsRead();
310 #endif
311
312 /// parse input buffer prefix into a single transfer protocol request
313 /// return NULL to request more header bytes (after checking any limits)
314 /// use abortRequestParsing() to handle parsing errors w/o creating request
315 virtual Http::Stream *parseOneRequest() = 0;
316
317 /// start processing a freshly parsed request
318 virtual void processParsedRequest(Http::Stream *) = 0;
319
320 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
321 virtual int pipelinePrefetchMax() const;
322
323 /// timeout to use when waiting for the next request
324 virtual time_t idleTimeout() const = 0;
325
326 BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
327
328 private:
329 /* ::Server API */
330 virtual bool connFinishedWithConn(int size);
331
332 void clientAfterReadingRequests();
333 bool concurrentRequestQueueFilled() const;
334
335 void pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth);
336
337 /* PROXY protocol functionality */
338 bool proxyProtocolValidateClient();
339 bool parseProxyProtocolHeader();
340 bool parseProxy1p0();
341 bool parseProxy2p0();
342 bool proxyProtocolError(const char *reason);
343
344 /// whether PROXY protocol header is still expected
345 bool needProxyProtocolHeader_;
346
347 #if USE_AUTH
348 /// some user details that can be used to perform authentication on this connection
349 Auth::UserRequest::Pointer auth_;
350 #endif
351
352 /// the parser state for current HTTP/1.x input buffer processing
353 Http1::RequestParserPointer parser_;
354
355 #if USE_OPENSSL
356 bool switchedToHttps_;
357 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
358 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
359 SBuf sslCommonName_; ///< CN name for SSL certificate generation
360 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
361
362 /// HTTPS server cert. fetching state for bump-ssl-server-first
363 Ssl::ServerBump *sslServerBump;
364 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
365 #endif
366
367 /// the reason why we no longer write the response or nil
368 const char *stoppedSending_;
369 /// the reason why we no longer read the request or nil
370 const char *stoppedReceiving_;
371
372 SBuf connectionTag_; ///< clt_conn_tag=Tag annotation for client connection
373 };
374
375 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
376
377 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
378
379 int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
380
381 /// accept requests to a given port and inform subCall about them
382 void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId noteId);
383
384 void clientOpenListenSockets(void);
385 void clientConnectionsClose(void);
386 void httpRequestFree(void *);
387
388 /// decide whether to expect multiple requests on the corresponding connection
389 void clientSetKeepaliveFlag(ClientHttpRequest *http);
390
391 /// append a "part" HTTP header (as in a multi-part/range reply) to the buffer
392 void clientPackRangeHdr(const HttpReply *, const HttpHdrRangeSpec *, String boundary, MemBuf *);
393
394 /// put terminating boundary for multiparts to the buffer
395 void clientPackTermBound(String boundary, MemBuf *);
396
397 /* misplaced declaratrions of Stream callbacks provided/used by client side */
398 SQUIDCEXTERN CSR clientGetMoreData;
399 SQUIDCEXTERN CSS clientReplyStatus;
400 SQUIDCEXTERN CSD clientReplyDetach;
401 CSCB clientSocketRecipient;
402 CSD clientSocketDetach;
403
404 /* TODO: Move to HttpServer. Warning: Move requires large code nonchanges! */
405 Http::Stream *parseHttpRequest(ConnStateData *, const Http1::RequestParserPointer &);
406 void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, Http::Stream *);
407 void clientPostHttpsAccept(ConnStateData *);
408
409 #endif /* SQUID_CLIENTSIDE_H */
410