]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
Convert ClientSocketContext to MEMPROXY class
[thirdparty/squid.git] / src / client_side.h
1 /*
2 * Copyright (C) 1996-2015 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 ConnStateData;
31 class ClientHttpRequest;
32 class clientStreamNode;
33 namespace AnyP
34 {
35 class PortCfg;
36 } // namespace Anyp
37
38 /**
39 * Badly named.
40 * This is in fact the processing context for a single HTTP transaction.
41 *
42 * A context lifetime extends from directly after a request has been parsed
43 * off the client connection buffer, until the last byte of both request
44 * and reply payload (if any) have been written.
45 *
46 * (NOTE: it is not certain yet if an early reply to a POST/PUT is sent by
47 * the server whether the context will remain in the pipeline until its
48 * request payload has finished being read. It is supposed to, but may not)
49 *
50 * Contexts self-register with the Pipeline being managed by the Server
51 * for the connection on which the request was received.
52 *
53 * When HTTP/1 pipeline is operating there may be multiple transactions using
54 * the clientConnection. Only the back() context may read from the connection,
55 * and only the front() context may write to it. A context which needs to read
56 * or write to the connection but does not meet those criteria must be shifted
57 * to the deferred state.
58 *
59 * When a context is completed the finished() method needs to be called which
60 * will perform all cleanup and deregistration operations. If the reason for
61 * finishing is an error, then notifyIoError() needs to be called prior to
62 * the finished() method.
63 * The caller should follow finished() with a call to ConnStateData::kick()
64 * to resume processing of other transactions or I/O on the connection.
65 *
66 * Alternatively the initiateClose() method can be called to terminate the
67 * whole client connection and all other pending contexts.
68 *
69 * The socket level management is done by a Server which owns us.
70 * The scope of this objects control over a socket consists of the data
71 * buffer received from the Server with an initially unknown length.
72 * When that length is known it sets the end boundary of our access to the
73 * buffer.
74 *
75 * The individual processing actions are done by other Jobs which we
76 * kick off as needed.
77 *
78 * XXX: If an async call ends the ClientHttpRequest job, ClientSocketContext
79 * (and ConnStateData) may not know about it, leading to segfaults and
80 * assertions. This is difficult to fix
81 * because ClientHttpRequest lacks a good way to communicate its ongoing
82 * destruction back to the ClientSocketContext which pretends to "own" *http.
83 */
84 class ClientSocketContext : public RefCountable
85 {
86 MEMPROXY_CLASS(ClientSocketContext);
87
88 public:
89 typedef RefCount<ClientSocketContext> Pointer;
90 ClientSocketContext(const Comm::ConnectionPointer &aConn, ClientHttpRequest *aReq);
91 ~ClientSocketContext();
92 bool startOfOutput() const;
93 void writeComplete(size_t size);
94
95 Comm::ConnectionPointer clientConnection; /// details about the client connection socket.
96 ClientHttpRequest *http; /* we pretend to own that job */
97 HttpReply *reply;
98 char reqbuf[HTTP_REQBUF_SZ];
99
100 struct {
101
102 unsigned deferred:1; /* This is a pipelined request waiting for the current object to complete */
103
104 unsigned parsed_ok:1; /* Was this parsed correctly? */
105 } flags;
106 bool mayUseConnection() const {return mayUseConnection_;}
107
108 void mayUseConnection(bool aBool) {
109 mayUseConnection_ = aBool;
110 debugs(33,3, HERE << "This " << this << " marked " << aBool);
111 }
112
113 class DeferredParams
114 {
115
116 public:
117 clientStreamNode *node;
118 HttpReply *rep;
119 StoreIOBuffer queuedBuffer;
120 };
121
122 DeferredParams deferredparams;
123 int64_t writtenToSocket;
124 void pullData();
125 int64_t getNextRangeOffset() const;
126 bool canPackMoreRanges() const;
127 clientStream_status_t socketState();
128 void sendBody(HttpReply * rep, StoreIOBuffer bodyData);
129 void sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData);
130 size_t lengthToSend(Range<int64_t> const &available);
131 void noteSentBodyBytes(size_t);
132 void buildRangeHeader(HttpReply * rep);
133 clientStreamNode * getTail() const;
134 clientStreamNode * getClientReplyContext() const;
135 ConnStateData *getConn() const;
136 void finished(); ///< cleanup when the transaction has finished. may destroy 'this'
137 void deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer receivedData);
138 bool multipartRangeRequest() const;
139 void registerWithConn();
140 void noteIoError(const int xerrno); ///< update state to reflect I/O error
141 void initiateClose(const char *reason); ///< terminate due to a send/write error (may continue reading)
142
143 private:
144 void prepareReply(HttpReply * rep);
145 void packChunk(const StoreIOBuffer &bodyData, MemBuf &mb);
146 void packRange(StoreIOBuffer const &, MemBuf * mb);
147 void doClose();
148
149 bool mayUseConnection_; /* This request may use the connection. Don't read anymore requests for now */
150 bool connRegistered_;
151 };
152
153 class ConnectionDetail;
154 #if USE_OPENSSL
155 namespace Ssl
156 {
157 class ServerBump;
158 }
159 #endif
160
161 /**
162 * Legacy Server code managing a connection to a client.
163 *
164 * NP: presents AsyncJob API but does not operate autonomously as a Job.
165 * So Must() is not safe to use.
166 *
167 * Multiple requests (up to pipeline_prefetch) can be pipelined.
168 * This object is responsible for managing which one is currently being
169 * fulfilled and what happens to the queue if the current one causes the client
170 * connection to be closed early.
171 *
172 * Act as a manager for the client connection and passes data in buffer to a
173 * Parser relevant to the state (message headers vs body) that is being
174 * processed.
175 *
176 * Performs HTTP message processing to kick off the actual HTTP request
177 * handling objects (ClientSocketContext, ClientHttpRequest, HttpRequest).
178 *
179 * Performs SSL-Bump processing for switching between HTTP and HTTPS protocols.
180 *
181 * To terminate a ConnStateData close() the client Comm::Connection it is
182 * managing, or for graceful half-close use the stopReceiving() or
183 * stopSending() methods.
184 */
185 class ConnStateData : public Server, public HttpControlMsgSink, public RegisteredRunner
186 {
187
188 public:
189 explicit ConnStateData(const MasterXaction::Pointer &xact);
190 virtual ~ConnStateData();
191
192 /* ::Server API */
193 virtual void receivedFirstByte();
194 virtual bool handleReadData();
195 virtual void afterClientRead();
196 virtual void afterClientWrite(size_t);
197
198 /* HttpControlMsgSink API */
199 virtual void sendControlMsg(HttpControlMsg);
200
201 /// Traffic parsing
202 bool clientParseRequests();
203 void readNextRequest();
204
205 /// try to make progress on a transaction or read more I/O
206 void kick();
207
208 bool isOpen() const;
209
210 Http1::TeChunkedParser *bodyParser; ///< parses HTTP/1.1 chunked request body
211
212 /** number of body bytes we need to comm_read for the "current" request
213 *
214 * \retval 0 We do not need to read any [more] body bytes
215 * \retval negative May need more but do not know how many; could be zero!
216 * \retval positive Need to read exactly that many more body bytes
217 */
218 int64_t mayNeedToReadMoreBody() const;
219
220 #if USE_AUTH
221 /**
222 * Fetch the user details for connection based authentication
223 * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
224 */
225 const Auth::UserRequest::Pointer &getAuth() const { return auth_; }
226
227 /**
228 * Set the user details for connection-based authentication to use from now until connection closure.
229 *
230 * Any change to existing credentials shows that something invalid has happened. Such as:
231 * - NTLM/Negotiate auth was violated by the per-request headers missing a revalidation token
232 * - NTLM/Negotiate auth was violated by the per-request headers being for another user
233 * - SSL-Bump CONNECT tunnel with persistent credentials has ended
234 */
235 void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause);
236 #endif
237
238 Ip::Address log_addr;
239
240 struct {
241 bool readMore; ///< needs comm_read (for this request or new requests)
242 bool swanSang; // XXX: temporary flag to check proper cleanup
243 } flags;
244 struct {
245 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
246 char *host; /* host name of pinned connection */
247 int port; /* port of pinned connection */
248 bool pinned; /* this connection was pinned */
249 bool auth; /* pinned for www authentication */
250 bool reading; ///< we are monitoring for peer connection closure
251 bool zeroReply; ///< server closed w/o response (ERR_ZERO_SIZE_OBJECT)
252 CachePeer *peer; /* CachePeer the connection goes via */
253 AsyncCall::Pointer readHandler; ///< detects serverConnection closure
254 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
255 } pinning;
256
257 bool transparent() const;
258
259 /// true if we stopped receiving the request
260 const char *stoppedReceiving() const { return stoppedReceiving_; }
261 /// true if we stopped sending the response
262 const char *stoppedSending() const { return stoppedSending_; }
263 /// note request receiving error and close as soon as we write the response
264 void stopReceiving(const char *error);
265 /// note response sending error and close as soon as we read the request
266 void stopSending(const char *error);
267
268 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
269
270 /* BodyPipe API */
271 BodyPipe::Pointer expectRequestBody(int64_t size);
272 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer) = 0;
273 virtual void noteBodyConsumerAborted(BodyPipe::Pointer) = 0;
274
275 bool handleRequestBodyData();
276
277 /// Forward future client requests using the given server connection.
278 /// Optionally, monitor pinned server connection for remote-end closures.
279 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth, bool monitor = true);
280 /// Undo pinConnection() and, optionally, close the pinned connection.
281 void unpinConnection(const bool andClose);
282 /// Returns validated pinnned server connection (and stops its monitoring).
283 Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer);
284 /**
285 * Checks if there is pinning info if it is valid. It can close the server side connection
286 * if pinned info is not valid.
287 \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
288 \param CachePeer if it is not NULL also check if the CachePeer is the pinning CachePeer
289 \return The details of the server side connection (may be closed if failures were present).
290 */
291 const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const CachePeer *peer);
292 /**
293 * returts the pinned CachePeer if exists, NULL otherwise
294 */
295 CachePeer *pinnedPeer() const {return pinning.peer;}
296 bool pinnedAuth() const {return pinning.auth;}
297
298 /// called just before a FwdState-dispatched job starts using connection
299 virtual void notePeerConnection(Comm::ConnectionPointer) {}
300
301 // pining related comm callbacks
302 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
303
304 // comm callbacks
305 void clientReadFtpData(const CommIoCbParams &io);
306 void connStateClosed(const CommCloseCbParams &io);
307 void requestTimeout(const CommTimeoutCbParams &params);
308
309 // AsyncJob API
310 virtual void start();
311 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
312 virtual void swanSong();
313
314 /// Changes state so that we close the connection and quit after serving
315 /// the client-side-detected error response instead of getting stuck.
316 void quitAfterError(HttpRequest *request); // meant to be private
317
318 /// The caller assumes responsibility for connection closure detection.
319 void stopPinnedConnectionMonitoring();
320
321 #if USE_OPENSSL
322 /// the second part of old httpsAccept, waiting for future HttpsServer home
323 void postHttpsAccept();
324
325 /// Initializes and starts a peek-and-splice negotiation with the SSL client
326 void startPeekAndSplice();
327 /// Called when the initialization of peek-and-splice negotiation finidhed
328 void startPeekAndSpliceDone();
329 /// Called when a peek-and-splice step finished. For example after
330 /// server SSL certificates received and fake server SSL certificates
331 /// generated
332 void doPeekAndSpliceStep();
333 /// called by FwdState when it is done bumping the server
334 void httpsPeeked(Comm::ConnectionPointer serverConnection);
335
336 /// Splice a bumped client connection on peek-and-splice mode
337 void splice();
338
339 /// Check on_unsupported_protocol access list and splice if required
340 /// \retval true on splice
341 /// \retval false otherwise
342 bool spliceOnError(const err_type err);
343
344 /// Start to create dynamic Security::ContextPtr for host or uses static port SSL context.
345 void getSslContextStart();
346 /**
347 * Done create dynamic ssl certificate.
348 *
349 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
350 */
351 void getSslContextDone(Security::ContextPtr sslContext, bool isNew = false);
352 /// Callback function. It is called when squid receive message from ssl_crtd.
353 static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
354 /// Proccess response from ssl_crtd.
355 void sslCrtdHandleReply(const Helper::Reply &reply);
356
357 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
358 bool switchedToHttps() const { return switchedToHttps_; }
359 Ssl::ServerBump *serverBump() {return sslServerBump;}
360 inline void setServerBump(Ssl::ServerBump *srvBump) {
361 if (!sslServerBump)
362 sslServerBump = srvBump;
363 else
364 assert(sslServerBump == srvBump);
365 }
366 const SBuf &sslCommonName() const {return sslCommonName_;}
367 void resetSslCommonName(const char *name) {sslCommonName_ = name;}
368 /// Fill the certAdaptParams with the required data for certificate adaptation
369 /// and create the key for storing/retrieve the certificate to/from the cache
370 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
371 /// Called when the client sends the first request on a bumped connection.
372 /// Returns false if no [delayed] error should be written to the client.
373 /// Otherwise, writes the error to the client and returns true. Also checks
374 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
375 bool serveDelayedError(ClientSocketContext *context);
376
377 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
378
379 #else
380 bool switchedToHttps() const { return false; }
381 #endif
382
383 /* clt_conn_tag=tag annotation access */
384 const SBuf &connectionTag() const { return connectionTag_; }
385 void connectionTag(const char *aTag) { connectionTag_ = aTag; }
386
387 /// handle a control message received by context from a peer and call back
388 virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
389
390 /// ClientStream calls this to supply response header (once) and data
391 /// for the current ClientSocketContext.
392 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) = 0;
393
394 /// remove no longer needed leading bytes from the input buffer
395 void consumeInput(const size_t byteCount);
396
397 /* TODO: Make the methods below (at least) non-public when possible. */
398
399 /// stop parsing the request and create context for relaying error info
400 ClientSocketContext *abortRequestParsing(const char *const errUri);
401
402 /// generate a fake CONNECT request with the given payload
403 /// at the beginning of the client I/O buffer
404 void fakeAConnectRequest(const char *reason, const SBuf &payload);
405
406 /// client data which may need to forward as-is to server after an
407 /// on_unsupported_protocol tunnel decision.
408 SBuf preservedClientData;
409
410 /* Registered Runner API */
411 virtual void startShutdown();
412 virtual void endingShutdown();
413
414 protected:
415 void startDechunkingRequest();
416 void finishDechunkingRequest(bool withSuccess);
417 void abortChunkedRequestBody(const err_type error);
418 err_type handleChunkedRequestBody();
419
420 void startPinnedConnectionMonitoring();
421 void clientPinnedConnectionRead(const CommIoCbParams &io);
422 #if USE_OPENSSL
423 /// Handles a ready-for-reading TLS squid-to-server connection that
424 /// we thought was idle.
425 /// \return false if and only if the connection should be closed.
426 bool handleIdleClientPinnedTlsRead();
427 #endif
428
429 /// parse input buffer prefix into a single transfer protocol request
430 /// return NULL to request more header bytes (after checking any limits)
431 /// use abortRequestParsing() to handle parsing errors w/o creating request
432 virtual ClientSocketContext *parseOneRequest() = 0;
433
434 /// start processing a freshly parsed request
435 virtual void processParsedRequest(ClientSocketContext *context) = 0;
436
437 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
438 virtual int pipelinePrefetchMax() const;
439
440 /// timeout to use when waiting for the next request
441 virtual time_t idleTimeout() const = 0;
442
443 BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
444
445 private:
446 /* ::Server API */
447 virtual bool connFinishedWithConn(int size);
448
449 void clientAfterReadingRequests();
450 bool concurrentRequestQueueFilled() const;
451
452 void pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth);
453
454 /* PROXY protocol functionality */
455 bool proxyProtocolValidateClient();
456 bool parseProxyProtocolHeader();
457 bool parseProxy1p0();
458 bool parseProxy2p0();
459 bool proxyProtocolError(const char *reason);
460
461 /// whether PROXY protocol header is still expected
462 bool needProxyProtocolHeader_;
463
464 #if USE_AUTH
465 /// some user details that can be used to perform authentication on this connection
466 Auth::UserRequest::Pointer auth_;
467 #endif
468
469 /// the parser state for current HTTP/1.x input buffer processing
470 Http1::RequestParserPointer parser_;
471
472 #if USE_OPENSSL
473 bool switchedToHttps_;
474 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
475 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
476 SBuf sslCommonName_; ///< CN name for SSL certificate generation
477 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
478
479 /// HTTPS server cert. fetching state for bump-ssl-server-first
480 Ssl::ServerBump *sslServerBump;
481 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
482 #endif
483
484 /// the reason why we no longer write the response or nil
485 const char *stoppedSending_;
486 /// the reason why we no longer read the request or nil
487 const char *stoppedReceiving_;
488
489 SBuf connectionTag_; ///< clt_conn_tag=Tag annotation for client connection
490 };
491
492 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
493
494 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
495
496 int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
497
498 /// accept requests to a given port and inform subCall about them
499 void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId noteId);
500
501 void clientOpenListenSockets(void);
502 void clientConnectionsClose(void);
503 void httpRequestFree(void *);
504
505 /// decide whether to expect multiple requests on the corresponding connection
506 void clientSetKeepaliveFlag(ClientHttpRequest *http);
507
508 /* misplaced declaratrions of Stream callbacks provided/used by client side */
509 SQUIDCEXTERN CSR clientGetMoreData;
510 SQUIDCEXTERN CSS clientReplyStatus;
511 SQUIDCEXTERN CSD clientReplyDetach;
512 CSCB clientSocketRecipient;
513 CSD clientSocketDetach;
514
515 /* TODO: Move to HttpServer. Warning: Move requires large code nonchanges! */
516 ClientSocketContext *parseHttpRequest(ConnStateData *, const Http1::RequestParserPointer &);
517 void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, ClientSocketContext *);
518 void clientPostHttpsAccept(ConnStateData *);
519
520 #endif /* SQUID_CLIENTSIDE_H */
521