]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
Cleanup: rename Security::ContextPointer to ContextPtr
[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 CBDATA_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(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, Comm::Flag errflag);
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
142 /// starts writing 1xx control message to the client
143 void writeControlMsg(HttpControlMsg &msg);
144
145 protected:
146 static IOCB WroteControlMsg;
147 void wroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, Comm::Flag errflag, int xerrno);
148
149 private:
150 void prepareReply(HttpReply * rep);
151 void packChunk(const StoreIOBuffer &bodyData, MemBuf &mb);
152 void packRange(StoreIOBuffer const &, MemBuf * mb);
153 void doClose();
154 void initiateClose(const char *reason);
155
156 AsyncCall::Pointer cbControlMsgSent; ///< notifies HttpControlMsg Source
157
158 bool mayUseConnection_; /* This request may use the connection. Don't read anymore requests for now */
159 bool connRegistered_;
160 };
161
162 class ConnectionDetail;
163 #if USE_OPENSSL
164 namespace Ssl
165 {
166 class ServerBump;
167 }
168 #endif
169
170 /**
171 * Legacy Server code managing a connection to a client.
172 *
173 * NP: presents AsyncJob API but does not operate autonomously as a Job.
174 * So Must() is not safe to use.
175 *
176 * Multiple requests (up to pipeline_prefetch) can be pipelined.
177 * This object is responsible for managing which one is currently being
178 * fulfilled and what happens to the queue if the current one causes the client
179 * connection to be closed early.
180 *
181 * Act as a manager for the client connection and passes data in buffer to a
182 * Parser relevant to the state (message headers vs body) that is being
183 * processed.
184 *
185 * Performs HTTP message processing to kick off the actual HTTP request
186 * handling objects (ClientSocketContext, ClientHttpRequest, HttpRequest).
187 *
188 * Performs SSL-Bump processing for switching between HTTP and HTTPS protocols.
189 *
190 * To terminate a ConnStateData close() the client Comm::Connection it is
191 * managing, or for graceful half-close use the stopReceiving() or
192 * stopSending() methods.
193 */
194 class ConnStateData : public Server, public HttpControlMsgSink, public RegisteredRunner
195 {
196
197 public:
198 explicit ConnStateData(const MasterXaction::Pointer &xact);
199 virtual ~ConnStateData();
200
201 /* ::Server API */
202 virtual void receivedFirstByte();
203 virtual bool handleReadData();
204 virtual void afterClientRead();
205
206 /// Traffic parsing
207 bool clientParseRequests();
208 void readNextRequest();
209
210 /// try to make progress on a transaction or read more I/O
211 void kick();
212
213 bool isOpen() const;
214
215 // HttpControlMsgSink API
216 virtual void sendControlMsg(HttpControlMsg msg);
217
218 Http1::TeChunkedParser *bodyParser; ///< parses HTTP/1.1 chunked request body
219
220 /** number of body bytes we need to comm_read for the "current" request
221 *
222 * \retval 0 We do not need to read any [more] body bytes
223 * \retval negative May need more but do not know how many; could be zero!
224 * \retval positive Need to read exactly that many more body bytes
225 */
226 int64_t mayNeedToReadMoreBody() const;
227
228 #if USE_AUTH
229 /**
230 * Fetch the user details for connection based authentication
231 * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
232 */
233 const Auth::UserRequest::Pointer &getAuth() const { return auth_; }
234
235 /**
236 * Set the user details for connection-based authentication to use from now until connection closure.
237 *
238 * Any change to existing credentials shows that something invalid has happened. Such as:
239 * - NTLM/Negotiate auth was violated by the per-request headers missing a revalidation token
240 * - NTLM/Negotiate auth was violated by the per-request headers being for another user
241 * - SSL-Bump CONNECT tunnel with persistent credentials has ended
242 */
243 void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause);
244 #endif
245
246 Ip::Address log_addr;
247
248 struct {
249 bool readMore; ///< needs comm_read (for this request or new requests)
250 bool swanSang; // XXX: temporary flag to check proper cleanup
251 } flags;
252 struct {
253 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
254 char *host; /* host name of pinned connection */
255 int port; /* port of pinned connection */
256 bool pinned; /* this connection was pinned */
257 bool auth; /* pinned for www authentication */
258 bool reading; ///< we are monitoring for peer connection closure
259 bool zeroReply; ///< server closed w/o response (ERR_ZERO_SIZE_OBJECT)
260 CachePeer *peer; /* CachePeer the connection goes via */
261 AsyncCall::Pointer readHandler; ///< detects serverConnection closure
262 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
263 } pinning;
264
265 bool transparent() const;
266
267 /// true if we stopped receiving the request
268 const char *stoppedReceiving() const { return stoppedReceiving_; }
269 /// true if we stopped sending the response
270 const char *stoppedSending() const { return stoppedSending_; }
271 /// note request receiving error and close as soon as we write the response
272 void stopReceiving(const char *error);
273 /// note response sending error and close as soon as we read the request
274 void stopSending(const char *error);
275
276 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
277
278 /* BodyPipe API */
279 BodyPipe::Pointer expectRequestBody(int64_t size);
280 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer) = 0;
281 virtual void noteBodyConsumerAborted(BodyPipe::Pointer) = 0;
282
283 bool handleRequestBodyData();
284
285 /// Forward future client requests using the given server connection.
286 /// Optionally, monitor pinned server connection for remote-end closures.
287 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth, bool monitor = true);
288 /// Undo pinConnection() and, optionally, close the pinned connection.
289 void unpinConnection(const bool andClose);
290 /// Returns validated pinnned server connection (and stops its monitoring).
291 Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer);
292 /**
293 * Checks if there is pinning info if it is valid. It can close the server side connection
294 * if pinned info is not valid.
295 \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
296 \param CachePeer if it is not NULL also check if the CachePeer is the pinning CachePeer
297 \return The details of the server side connection (may be closed if failures were present).
298 */
299 const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const CachePeer *peer);
300 /**
301 * returts the pinned CachePeer if exists, NULL otherwise
302 */
303 CachePeer *pinnedPeer() const {return pinning.peer;}
304 bool pinnedAuth() const {return pinning.auth;}
305
306 /// called just before a FwdState-dispatched job starts using connection
307 virtual void notePeerConnection(Comm::ConnectionPointer) {}
308
309 // pining related comm callbacks
310 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
311
312 // comm callbacks
313 void clientReadFtpData(const CommIoCbParams &io);
314 void connStateClosed(const CommCloseCbParams &io);
315 void requestTimeout(const CommTimeoutCbParams &params);
316
317 // AsyncJob API
318 virtual void start();
319 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
320 virtual void swanSong();
321
322 /// Changes state so that we close the connection and quit after serving
323 /// the client-side-detected error response instead of getting stuck.
324 void quitAfterError(HttpRequest *request); // meant to be private
325
326 /// The caller assumes responsibility for connection closure detection.
327 void stopPinnedConnectionMonitoring();
328
329 #if USE_OPENSSL
330 /// the second part of old httpsAccept, waiting for future HttpsServer home
331 void postHttpsAccept();
332
333 /// Initializes and starts a peek-and-splice negotiation with the SSL client
334 void startPeekAndSplice();
335 /// Called when the initialization of peek-and-splice negotiation finidhed
336 void startPeekAndSpliceDone();
337 /// Called when a peek-and-splice step finished. For example after
338 /// server SSL certificates received and fake server SSL certificates
339 /// generated
340 void doPeekAndSpliceStep();
341 /// called by FwdState when it is done bumping the server
342 void httpsPeeked(Comm::ConnectionPointer serverConnection);
343
344 /// Splice a bumped client connection on peek-and-splice mode
345 void splice();
346
347 /// Check on_unsupported_protocol access list and splice if required
348 /// \retval true on splice
349 /// \retval false otherwise
350 bool spliceOnError(const err_type err);
351
352 /// Start to create dynamic Security::ContextPtr for host or uses static port SSL context.
353 void getSslContextStart();
354 /**
355 * Done create dynamic ssl certificate.
356 *
357 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
358 */
359 void getSslContextDone(Security::ContextPtr sslContext, bool isNew = false);
360 /// Callback function. It is called when squid receive message from ssl_crtd.
361 static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
362 /// Proccess response from ssl_crtd.
363 void sslCrtdHandleReply(const Helper::Reply &reply);
364
365 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
366 bool switchedToHttps() const { return switchedToHttps_; }
367 Ssl::ServerBump *serverBump() {return sslServerBump;}
368 inline void setServerBump(Ssl::ServerBump *srvBump) {
369 if (!sslServerBump)
370 sslServerBump = srvBump;
371 else
372 assert(sslServerBump == srvBump);
373 }
374 const SBuf &sslCommonName() const {return sslCommonName_;}
375 void resetSslCommonName(const char *name) {sslCommonName_ = name;}
376 /// Fill the certAdaptParams with the required data for certificate adaptation
377 /// and create the key for storing/retrieve the certificate to/from the cache
378 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
379 /// Called when the client sends the first request on a bumped connection.
380 /// Returns false if no [delayed] error should be written to the client.
381 /// Otherwise, writes the error to the client and returns true. Also checks
382 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
383 bool serveDelayedError(ClientSocketContext *context);
384
385 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
386
387 #else
388 bool switchedToHttps() const { return false; }
389 #endif
390
391 /* clt_conn_tag=tag annotation access */
392 const SBuf &connectionTag() const { return connectionTag_; }
393 void connectionTag(const char *aTag) { connectionTag_ = aTag; }
394
395 /// handle a control message received by context from a peer and call back
396 virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call) = 0;
397
398 /// ClientStream calls this to supply response header (once) and data
399 /// for the current ClientSocketContext.
400 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) = 0;
401
402 /// remove no longer needed leading bytes from the input buffer
403 void consumeInput(const size_t byteCount);
404
405 /* TODO: Make the methods below (at least) non-public when possible. */
406
407 /// stop parsing the request and create context for relaying error info
408 ClientSocketContext *abortRequestParsing(const char *const errUri);
409
410 /// generate a fake CONNECT request with the given payload
411 /// at the beginning of the client I/O buffer
412 void fakeAConnectRequest(const char *reason, const SBuf &payload);
413
414 /// client data which may need to forward as-is to server after an
415 /// on_unsupported_protocol tunnel decision.
416 SBuf preservedClientData;
417
418 /* Registered Runner API */
419 virtual void startShutdown();
420 virtual void endingShutdown();
421
422 protected:
423 void startDechunkingRequest();
424 void finishDechunkingRequest(bool withSuccess);
425 void abortChunkedRequestBody(const err_type error);
426 err_type handleChunkedRequestBody();
427
428 void startPinnedConnectionMonitoring();
429 void clientPinnedConnectionRead(const CommIoCbParams &io);
430 #if USE_OPENSSL
431 /// Handles a ready-for-reading TLS squid-to-server connection that
432 /// we thought was idle.
433 /// \return false if and only if the connection should be closed.
434 bool handleIdleClientPinnedTlsRead();
435 #endif
436
437 /// parse input buffer prefix into a single transfer protocol request
438 /// return NULL to request more header bytes (after checking any limits)
439 /// use abortRequestParsing() to handle parsing errors w/o creating request
440 virtual ClientSocketContext *parseOneRequest() = 0;
441
442 /// start processing a freshly parsed request
443 virtual void processParsedRequest(ClientSocketContext *context) = 0;
444
445 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
446 virtual int pipelinePrefetchMax() const;
447
448 /// timeout to use when waiting for the next request
449 virtual time_t idleTimeout() const = 0;
450
451 BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
452
453 private:
454 /* ::Server API */
455 virtual bool connFinishedWithConn(int size);
456
457 void clientAfterReadingRequests();
458 bool concurrentRequestQueueFilled() const;
459
460 void pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth);
461
462 /* PROXY protocol functionality */
463 bool proxyProtocolValidateClient();
464 bool parseProxyProtocolHeader();
465 bool parseProxy1p0();
466 bool parseProxy2p0();
467 bool proxyProtocolError(const char *reason);
468
469 /// whether PROXY protocol header is still expected
470 bool needProxyProtocolHeader_;
471
472 #if USE_AUTH
473 /// some user details that can be used to perform authentication on this connection
474 Auth::UserRequest::Pointer auth_;
475 #endif
476
477 /// the parser state for current HTTP/1.x input buffer processing
478 Http1::RequestParserPointer parser_;
479
480 #if USE_OPENSSL
481 bool switchedToHttps_;
482 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
483 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
484 SBuf sslCommonName_; ///< CN name for SSL certificate generation
485 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
486
487 /// HTTPS server cert. fetching state for bump-ssl-server-first
488 Ssl::ServerBump *sslServerBump;
489 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
490 #endif
491
492 /// the reason why we no longer write the response or nil
493 const char *stoppedSending_;
494 /// the reason why we no longer read the request or nil
495 const char *stoppedReceiving_;
496
497 SBuf connectionTag_; ///< clt_conn_tag=Tag annotation for client connection
498 };
499
500 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
501
502 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
503
504 int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
505
506 /// accept requests to a given port and inform subCall about them
507 void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId noteId);
508
509 void clientOpenListenSockets(void);
510 void clientConnectionsClose(void);
511 void httpRequestFree(void *);
512
513 /// decide whether to expect multiple requests on the corresponding connection
514 void clientSetKeepaliveFlag(ClientHttpRequest *http);
515
516 /* misplaced declaratrions of Stream callbacks provided/used by client side */
517 SQUIDCEXTERN CSR clientGetMoreData;
518 SQUIDCEXTERN CSS clientReplyStatus;
519 SQUIDCEXTERN CSD clientReplyDetach;
520 CSCB clientSocketRecipient;
521 CSD clientSocketDetach;
522
523 /* TODO: Move to HttpServer. Warning: Move requires large code nonchanges! */
524 ClientSocketContext *parseHttpRequest(ConnStateData *, const Http1::RequestParserPointer &);
525 void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, ClientSocketContext *);
526 void clientPostHttpsAccept(ConnStateData *);
527
528 #endif /* SQUID_CLIENTSIDE_H */
529