2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 33 Client-side Routines */
11 #ifndef SQUID_CLIENTSIDE_H
12 #define SQUID_CLIENTSIDE_H
14 #include "base/RunnersRegistry.h"
15 #include "clientStreamForward.h"
17 #include "helper/forward.h"
18 #include "http/forward.h"
19 #include "HttpControlMsg.h"
20 #include "ipc/FdNotes.h"
22 #include "servers/Server.h"
24 #include "auth/UserRequest.h"
27 #include "ssl/support.h"
31 class ClientHttpRequest
;
32 class clientStreamNode
;
40 * This is in fact the processing context for a single HTTP transaction.
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.
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)
50 * Contexts self-register with the Pipeline being managed by the Server
51 * for the connection on which the request was received.
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.
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.
66 * Alternatively the initiateClose() method can be called to terminate the
67 * whole client connection and all other pending contexts.
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
75 * The individual processing actions are done by other Jobs which we
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.
84 class ClientSocketContext
: public RefCountable
86 MEMPROXY_CLASS(ClientSocketContext
);
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
);
95 Comm::ConnectionPointer clientConnection
; /// details about the client connection socket.
96 ClientHttpRequest
*http
; /* we pretend to own that job */
98 char reqbuf
[HTTP_REQBUF_SZ
];
102 unsigned deferred
:1; /* This is a pipelined request waiting for the current object to complete */
104 unsigned parsed_ok
:1; /* Was this parsed correctly? */
106 bool mayUseConnection() const {return mayUseConnection_
;}
108 void mayUseConnection(bool aBool
) {
109 mayUseConnection_
= aBool
;
110 debugs(33,3, HERE
<< "This " << this << " marked " << aBool
);
117 clientStreamNode
*node
;
119 StoreIOBuffer queuedBuffer
;
122 DeferredParams deferredparams
;
123 int64_t writtenToSocket
;
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)
144 void prepareReply(HttpReply
* rep
);
145 void packChunk(const StoreIOBuffer
&bodyData
, MemBuf
&mb
);
146 void packRange(StoreIOBuffer
const &, MemBuf
* mb
);
149 bool mayUseConnection_
; /* This request may use the connection. Don't read anymore requests for now */
150 bool connRegistered_
;
153 class ConnectionDetail
;
162 * Legacy Server code managing a connection to a client.
164 * NP: presents AsyncJob API but does not operate autonomously as a Job.
165 * So Must() is not safe to use.
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.
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
176 * Performs HTTP message processing to kick off the actual HTTP request
177 * handling objects (ClientSocketContext, ClientHttpRequest, HttpRequest).
179 * Performs SSL-Bump processing for switching between HTTP and HTTPS protocols.
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.
185 class ConnStateData
: public Server
, public HttpControlMsgSink
, public RegisteredRunner
189 explicit ConnStateData(const MasterXaction::Pointer
&xact
);
190 virtual ~ConnStateData();
193 virtual void receivedFirstByte();
194 virtual bool handleReadData();
195 virtual void afterClientRead();
196 virtual void afterClientWrite(size_t);
198 /* HttpControlMsgSink API */
199 virtual void sendControlMsg(HttpControlMsg
);
202 bool clientParseRequests();
203 void readNextRequest();
205 /// try to make progress on a transaction or read more I/O
210 Http1::TeChunkedParser
*bodyParser
; ///< parses HTTP/1.1 chunked request body
212 /** number of body bytes we need to comm_read for the "current" request
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
218 int64_t mayNeedToReadMoreBody() const;
222 * Fetch the user details for connection based authentication
223 * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
225 const Auth::UserRequest::Pointer
&getAuth() const { return auth_
; }
228 * Set the user details for connection-based authentication to use from now until connection closure.
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
235 void setAuth(const Auth::UserRequest::Pointer
&aur
, const char *cause
);
238 Ip::Address log_addr
;
241 bool readMore
; ///< needs comm_read (for this request or new requests)
242 bool swanSang
; // XXX: temporary flag to check proper cleanup
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*/
257 bool transparent() const;
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
);
268 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
271 BodyPipe::Pointer
expectRequestBody(int64_t size
);
272 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer
) = 0;
273 virtual void noteBodyConsumerAborted(BodyPipe::Pointer
) = 0;
275 bool handleRequestBodyData();
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
);
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).
291 const Comm::ConnectionPointer
validatePinnedConnection(HttpRequest
*request
, const CachePeer
*peer
);
293 * returts the pinned CachePeer if exists, NULL otherwise
295 CachePeer
*pinnedPeer() const {return pinning
.peer
;}
296 bool pinnedAuth() const {return pinning
.auth
;}
298 /// called just before a FwdState-dispatched job starts using connection
299 virtual void notePeerConnection(Comm::ConnectionPointer
) {}
301 // pining related comm callbacks
302 virtual void clientPinnedConnectionClosed(const CommCloseCbParams
&io
);
305 void clientReadFtpData(const CommIoCbParams
&io
);
306 void connStateClosed(const CommCloseCbParams
&io
);
307 void requestTimeout(const CommTimeoutCbParams
¶ms
);
310 virtual void start();
311 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
312 virtual void swanSong();
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
318 /// The caller assumes responsibility for connection closure detection.
319 void stopPinnedConnectionMonitoring();
322 /// the second part of old httpsAccept, waiting for future HttpsServer home
323 void postHttpsAccept();
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
332 void doPeekAndSpliceStep();
333 /// called by FwdState when it is done bumping the server
334 void httpsPeeked(Comm::ConnectionPointer serverConnection
);
336 /// Splice a bumped client connection on peek-and-splice mode
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
);
344 /// Start to create dynamic Security::ContextPtr for host or uses static port SSL context.
345 void getSslContextStart();
347 * Done create dynamic ssl certificate.
349 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
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
);
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
) {
362 sslServerBump
= srvBump
;
364 assert(sslServerBump
== srvBump
);
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
);
377 Ssl::BumpMode sslBumpMode
; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
380 bool switchedToHttps() const { return false; }
383 /* clt_conn_tag=tag annotation access */
384 const SBuf
&connectionTag() const { return connectionTag_
; }
385 void connectionTag(const char *aTag
) { connectionTag_
= aTag
; }
387 /// handle a control message received by context from a peer and call back
388 virtual void writeControlMsgAndCall(HttpReply
*rep
, AsyncCall::Pointer
&call
) = 0;
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;
394 /// remove no longer needed leading bytes from the input buffer
395 void consumeInput(const size_t byteCount
);
397 /* TODO: Make the methods below (at least) non-public when possible. */
399 /// stop parsing the request and create context for relaying error info
400 ClientSocketContext
*abortRequestParsing(const char *const errUri
);
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
);
406 /// client data which may need to forward as-is to server after an
407 /// on_unsupported_protocol tunnel decision.
408 SBuf preservedClientData
;
410 /* Registered Runner API */
411 virtual void startShutdown();
412 virtual void endingShutdown();
415 void startDechunkingRequest();
416 void finishDechunkingRequest(bool withSuccess
);
417 void abortChunkedRequestBody(const err_type error
);
418 err_type
handleChunkedRequestBody();
420 void startPinnedConnectionMonitoring();
421 void clientPinnedConnectionRead(const CommIoCbParams
&io
);
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();
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;
434 /// start processing a freshly parsed request
435 virtual void processParsedRequest(ClientSocketContext
*context
) = 0;
437 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
438 virtual int pipelinePrefetchMax() const;
440 /// timeout to use when waiting for the next request
441 virtual time_t idleTimeout() const = 0;
443 BodyPipe::Pointer bodyPipe
; ///< set when we are reading request body
447 virtual bool connFinishedWithConn(int size
);
449 void clientAfterReadingRequests();
450 bool concurrentRequestQueueFilled() const;
452 void pinNewConnection(const Comm::ConnectionPointer
&pinServer
, HttpRequest
*request
, CachePeer
*aPeer
, bool auth
);
454 /* PROXY protocol functionality */
455 bool proxyProtocolValidateClient();
456 bool parseProxyProtocolHeader();
457 bool parseProxy1p0();
458 bool parseProxy2p0();
459 bool proxyProtocolError(const char *reason
);
461 /// whether PROXY protocol header is still expected
462 bool needProxyProtocolHeader_
;
465 /// some user details that can be used to perform authentication on this connection
466 Auth::UserRequest::Pointer auth_
;
469 /// the parser state for current HTTP/1.x input buffer processing
470 Http1::RequestParserPointer parser_
;
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
479 /// HTTPS server cert. fetching state for bump-ssl-server-first
480 Ssl::ServerBump
*sslServerBump
;
481 Ssl::CertSignAlgorithm signAlgorithm
; ///< The signing algorithm to use
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_
;
489 SBuf connectionTag_
; ///< clt_conn_tag=Tag annotation for client connection
492 void setLogUri(ClientHttpRequest
* http
, char const *uri
, bool cleanUrl
= false);
494 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion
, const char *end
= NULL
);
496 int varyEvaluateMatch(StoreEntry
* entry
, HttpRequest
* req
);
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
);
501 void clientOpenListenSockets(void);
502 void clientConnectionsClose(void);
503 void httpRequestFree(void *);
505 /// decide whether to expect multiple requests on the corresponding connection
506 void clientSetKeepaliveFlag(ClientHttpRequest
*http
);
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
;
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
*);
520 #endif /* SQUID_CLIENTSIDE_H */