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