]> git.ipfire.org Git - thirdparty/squid.git/blame - src/client_side.h
Fix "BUG: Lost previously bumped from-Squid connection" (#460)
[thirdparty/squid.git] / src / client_side.h
CommitLineData
6039b729 1/*
f6e9a3ee 2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
6039b729 3 *
bbc27441
AJ
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.
6039b729 7 */
8
bbc27441
AJ
9/* DEBUG: section 33 Client-side Routines */
10
6039b729 11#ifndef SQUID_CLIENTSIDE_H
12#define SQUID_CLIENTSIDE_H
13
d442618d 14#include "base/RunnersRegistry.h"
92ae4c86 15#include "clientStreamForward.h"
a98c2da5 16#include "comm.h"
24438ec5 17#include "helper/forward.h"
a24dfc69 18#include "http/forward.h"
e74be5fd 19#include "HttpControlMsg.h"
92ae4c86 20#include "ipc/FdNotes.h"
daf80700 21#include "log/forward.h"
36c774f7 22#include "proxyp/forward.h"
65e41a45 23#include "sbuf/SBuf.h"
fcc444e3 24#include "servers/Server.h"
582c2af2
FC
25#if USE_AUTH
26#include "auth/UserRequest.h"
27#endif
cb4f4424 28#if USE_OPENSSL
3cae14a6 29#include "security/Handshake.h"
061bbdec
CT
30#include "ssl/support.h"
31#endif
b27668ec
EB
32#if USE_DELAY_POOLS
33#include "MessageBucket.h"
34#endif
0655fa4d 35
801cfc26
CT
36#include <iosfwd>
37
0655fa4d 38class ClientHttpRequest;
d6fdeb41 39class HttpHdrRangeSpec;
0655fa4d 40
e16571ed
AJ
41class MasterXaction;
42typedef RefCount<MasterXaction> MasterXactionPointer;
43
cb4f4424 44#if USE_OPENSSL
87f237a9
A
45namespace Ssl
46{
47class ServerBump;
061bbdec
CT
48}
49#endif
434fe014 50
27774cee 51/**
434fe014
AJ
52 * Legacy Server code managing a connection to a client.
53 *
54 * NP: presents AsyncJob API but does not operate autonomously as a Job.
55 * So Must() is not safe to use.
56 *
57 * Multiple requests (up to pipeline_prefetch) can be pipelined.
58 * This object is responsible for managing which one is currently being
59 * fulfilled and what happens to the queue if the current one causes the client
60 * connection to be closed early.
61 *
62 * Act as a manager for the client connection and passes data in buffer to a
63 * Parser relevant to the state (message headers vs body) that is being
64 * processed.
27774cee 65 *
434fe014 66 * Performs HTTP message processing to kick off the actual HTTP request
d3dddfb5 67 * handling objects (Http::Stream, ClientHttpRequest, HttpRequest).
27774cee 68 *
434fe014 69 * Performs SSL-Bump processing for switching between HTTP and HTTPS protocols.
27774cee 70 *
434fe014
AJ
71 * To terminate a ConnStateData close() the client Comm::Connection it is
72 * managing, or for graceful half-close use the stopReceiving() or
73 * stopSending() methods.
27774cee 74 */
a27fcaed 75class ConnStateData : public Server, public HttpControlMsgSink, private IndependentRunner
6039b729 76{
77
78public:
5ceaee75 79 explicit ConnStateData(const MasterXactionPointer &xact);
92ae4c86 80 virtual ~ConnStateData();
6039b729 81
fcc444e3 82 /* ::Server API */
fcc444e3
AJ
83 virtual void receivedFirstByte();
84 virtual bool handleReadData();
85 virtual void afterClientRead();
21cd3227 86 virtual void afterClientWrite(size_t);
fcc444e3 87
84540b47
AJ
88 /* HttpControlMsgSink API */
89 virtual void sendControlMsg(HttpControlMsg);
2f97ab10 90 virtual void doneWithControlMsg();
84540b47 91
4959e21e 92 /// Traffic parsing
f35961af 93 bool clientParseRequests();
6039b729 94 void readNextRequest();
f4a53cf7 95
7d84a116 96 /// try to make progress on a transaction or read more I/O
f4a53cf7
AJ
97 void kick();
98
a2ac85d9 99 bool isOpen() const;
6039b729 100
fcc444e3 101 Http1::TeChunkedParser *bodyParser; ///< parses HTTP/1.1 chunked request body
6039b729 102
39cb8c41
AR
103 /** number of body bytes we need to comm_read for the "current" request
104 *
105 * \retval 0 We do not need to read any [more] body bytes
106 * \retval negative May need more but do not know how many; could be zero!
107 * \retval positive Need to read exactly that many more body bytes
108 */
109 int64_t mayNeedToReadMoreBody() const;
3b299123 110
2f1431ea 111#if USE_AUTH
63be0a78 112 /**
cc1e110a
AJ
113 * Fetch the user details for connection based authentication
114 * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
3b299123 115 */
cc1e110a
AJ
116 const Auth::UserRequest::Pointer &getAuth() const { return auth_; }
117
118 /**
119 * Set the user details for connection-based authentication to use from now until connection closure.
120 *
121 * Any change to existing credentials shows that something invalid has happened. Such as:
122 * - NTLM/Negotiate auth was violated by the per-request headers missing a revalidation token
123 * - NTLM/Negotiate auth was violated by the per-request headers being for another user
124 * - SSL-Bump CONNECT tunnel with persistent credentials has ended
125 */
126 void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause);
2f1431ea 127#endif
63be0a78 128
b7ac5457 129 Ip::Address log_addr;
6039b729 130
9e008dda 131 struct {
f35961af 132 bool readMore; ///< needs comm_read (for this request or new requests)
6e1d409c 133 bool swanSang; // XXX: temporary flag to check proper cleanup
2fadd50d 134 } flags;
d67acb4e 135 struct {
73c36fd9 136 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
d67acb4e
AJ
137 char *host; /* host name of pinned connection */
138 int port; /* port of pinned connection */
139 bool pinned; /* this connection was pinned */
140 bool auth; /* pinned for www authentication */
e7ce227f 141 bool reading; ///< we are monitoring for peer connection closure
693cb033 142 bool zeroReply; ///< server closed w/o response (ERR_ZERO_SIZE_OBJECT)
daf80700 143 bool peerAccessDenied; ///< cache_peer_access denied pinned connection reuse
a3c6762c 144 CachePeer *peer; /* CachePeer the connection goes via */
7ac40923 145 AsyncCall::Pointer readHandler; ///< detects serverConnection closure
9e008dda
AJ
146 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
147 } pinning;
d67acb4e 148
6039b729 149 bool transparent() const;
5f8252d2 150
cf6eb29e
CT
151 /// true if we stopped receiving the request
152 const char *stoppedReceiving() const { return stoppedReceiving_; }
153 /// true if we stopped sending the response
154 const char *stoppedSending() const { return stoppedSending_; }
155 /// note request receiving error and close as soon as we write the response
156 void stopReceiving(const char *error);
157 /// note response sending error and close as soon as we read the request
158 void stopSending(const char *error);
159
eb44b2d7 160 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
6039b729 161
92ae4c86 162 /* BodyPipe API */
3e62bd58 163 BodyPipe::Pointer expectRequestBody(int64_t size);
92ae4c86
AR
164 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer) = 0;
165 virtual void noteBodyConsumerAborted(BodyPipe::Pointer) = 0;
5f8252d2 166
39cb8c41 167 bool handleRequestBodyData();
0b86805b 168
801cfc26
CT
169 /// parameters for the async notePinnedConnectionBecameIdle() call
170 class PinnedIdleContext
171 {
172 public:
173 PinnedIdleContext(const Comm::ConnectionPointer &conn, const HttpRequest::Pointer &req): connection(conn), request(req) {}
174
175 Comm::ConnectionPointer connection; ///< to-server connection to be pinned
176 HttpRequest::Pointer request; ///< to-server request that initiated serverConnection
177 };
178
179 /// Called when a pinned connection becomes available for forwarding the next request.
180 void notePinnedConnectionBecameIdle(PinnedIdleContext pic);
181 /// Forward future client requests using the given to-server connection.
182 /// The connection is still being used by the current client request.
183 void pinBusyConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest::Pointer &request);
e7ce227f 184 /// Undo pinConnection() and, optionally, close the pinned connection.
89b1d7a2 185 void unpinConnection(const bool andClose);
daf80700
CT
186
187 /// \returns validated pinned to-server connection, stopping its monitoring
188 /// \throws a newly allocated ErrorState if validation fails
189 static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &);
d67acb4e 190 /**
a3c6762c 191 * returts the pinned CachePeer if exists, NULL otherwise
d67acb4e 192 */
a3c6762c 193 CachePeer *pinnedPeer() const {return pinning.peer;}
d67acb4e
AJ
194 bool pinnedAuth() const {return pinning.auth;}
195
92ae4c86
AR
196 /// called just before a FwdState-dispatched job starts using connection
197 virtual void notePeerConnection(Comm::ConnectionPointer) {}
198
d67acb4e 199 // pining related comm callbacks
92ae4c86 200 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
d67acb4e 201
1cf238db 202 // comm callbacks
a5d444a5 203 void clientReadFtpData(const CommIoCbParams &io);
1cf238db 204 void connStateClosed(const CommCloseCbParams &io);
205 void requestTimeout(const CommTimeoutCbParams &params);
206
207 // AsyncJob API
92ae4c86 208 virtual void start();
1cf238db 209 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
6e1d409c 210 virtual void swanSong();
1cf238db 211
84c77748
AR
212 /// Changes state so that we close the connection and quit after serving
213 /// the client-side-detected error response instead of getting stuck.
214 void quitAfterError(HttpRequest *request); // meant to be private
215
7ac40923
AR
216 /// The caller assumes responsibility for connection closure detection.
217 void stopPinnedConnectionMonitoring();
218
92ae4c86
AR
219 /// the second part of old httpsAccept, waiting for future HttpsServer home
220 void postHttpsAccept();
221
51e09c08 222#if USE_OPENSSL
d620ae0e 223 /// Initializes and starts a peek-and-splice negotiation with the SSL client
6b2b6cfe
CT
224 void startPeekAndSplice();
225
d620ae0e 226 /// Called when a peek-and-splice step finished. For example after
d5430dc8 227 /// server SSL certificates received and fake server SSL certificates
d620ae0e
CT
228 /// generated
229 void doPeekAndSpliceStep();
fd4624d7 230 /// called by FwdState when it is done bumping the server
801cfc26 231 void httpsPeeked(PinnedIdleContext pic);
d7ce0bcd 232
3248e962 233 /// Splice a bumped client connection on peek-and-splice mode
efda53c5 234 bool splice();
3248e962 235
0476ec45 236 /// Start to create dynamic Security::ContextPointer for host or uses static port SSL context.
1ce2822d 237 void getSslContextStart();
5107d2c4
CT
238
239 /// finish configuring the newly created SSL context"
240 void getSslContextDone(Security::ContextPointer &);
241
95d2589c 242 /// Callback function. It is called when squid receive message from ssl_crtd.
24438ec5 243 static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
95d2589c 244 /// Proccess response from ssl_crtd.
24438ec5 245 void sslCrtdHandleReply(const Helper::Reply &reply);
95d2589c 246
f5e17947 247 void switchToHttps(ClientHttpRequest *, Ssl::BumpMode bumpServerMode);
d20cf186 248 void parseTlsHandshake();
ae7ff0b8 249 bool switchedToHttps() const { return switchedToHttps_; }
fd4624d7 250 Ssl::ServerBump *serverBump() {return sslServerBump;}
38450a50
CT
251 inline void setServerBump(Ssl::ServerBump *srvBump) {
252 if (!sslServerBump)
253 sslServerBump = srvBump;
254 else
255 assert(sslServerBump == srvBump);
256 }
69f69080
CT
257 const SBuf &sslCommonName() const {return sslCommonName_;}
258 void resetSslCommonName(const char *name) {sslCommonName_ = name;}
4f6990ec 259 const SBuf &tlsClientSni() const { return tlsClientSni_; }
fb2178bb
CT
260 /// Fill the certAdaptParams with the required data for certificate adaptation
261 /// and create the key for storing/retrieve the certificate to/from the cache
06997a38 262 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
7a957a93
AR
263 /// Called when the client sends the first request on a bumped connection.
264 /// Returns false if no [delayed] error should be written to the client.
265 /// Otherwise, writes the error to the client and returns true. Also checks
266 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
d3dddfb5 267 bool serveDelayedError(Http::Stream *);
08097970
AR
268
269 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
d9219c2b
CT
270
271 /// Tls parser to use for client HELLO messages parsing on bumped
272 /// connections.
3cae14a6 273 Security::HandshakeParser tlsParser;
ae7ff0b8 274#else
275 bool switchedToHttps() const { return false; }
276#endif
0a57a661 277 char *prepareTlsSwitchingURL(const Http1::RequestParserPointer &hp);
ae7ff0b8 278
92ae4c86 279 /// handle a control message received by context from a peer and call back
2f97ab10 280 virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
92ae4c86
AR
281
282 /// ClientStream calls this to supply response header (once) and data
d3dddfb5 283 /// for the current Http::Stream.
92ae4c86
AR
284 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) = 0;
285
286 /// remove no longer needed leading bytes from the input buffer
287 void consumeInput(const size_t byteCount);
288
eacfca83
AR
289 /* TODO: Make the methods below (at least) non-public when possible. */
290
291 /// stop parsing the request and create context for relaying error info
d3dddfb5 292 Http::Stream *abortRequestParsing(const char *const errUri);
eacfca83 293
a30b692c
AJ
294 /// generate a fake CONNECT request with the given payload
295 /// at the beginning of the client I/O buffer
efda53c5 296 bool fakeAConnectRequest(const char *reason, const SBuf &payload);
a30b692c 297
6b2b6cfe
CT
298 /// generates and sends to tunnel.cc a fake request with a given payload
299 bool initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload);
300
9ce4a1eb
CT
301 /// whether we should start saving inBuf client bytes in anticipation of
302 /// tunneling them to the server later (on_unsupported_protocol)
303 bool shouldPreserveClientData() const;
304
305 // TODO: move to the protected section when removing clientTunnelOnError()
306 bool tunnelOnError(const HttpRequestMethod &, const err_type);
6b2b6cfe
CT
307
308 /// build a fake http request
309 ClientHttpRequest *buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload);
310
9ce4a1eb
CT
311 /// From-client handshake bytes (including bytes at the beginning of a
312 /// CONNECT tunnel) which we may need to forward as-is if their syntax does
313 /// not match the expected TLS or HTTP protocol (on_unsupported_protocol).
3248e962 314 SBuf preservedClientData;
d442618d
AJ
315
316 /* Registered Runner API */
317 virtual void startShutdown();
318 virtual void endingShutdown();
319
75d47340
CT
320 /// \returns existing non-empty connection annotations,
321 /// creates and returns empty annotations otherwise
322 NotePairs::Pointer notes();
323 bool hasNotes() const { return bool(theNotes) && !theNotes->empty(); }
324
36c774f7
EB
325 const ProxyProtocol::HeaderPointer &proxyProtocolHeader() const { return proxyProtocolHeader_; }
326
39cb8c41
AR
327protected:
328 void startDechunkingRequest();
329 void finishDechunkingRequest(bool withSuccess);
330 void abortChunkedRequestBody(const err_type error);
be29ee33 331 err_type handleChunkedRequestBody();
3ff65596 332
daf80700
CT
333 /// ConnStateData-specific part of BorrowPinnedConnection()
334 Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &);
335
7ac40923
AR
336 void startPinnedConnectionMonitoring();
337 void clientPinnedConnectionRead(const CommIoCbParams &io);
96aedee5
CT
338#if USE_OPENSSL
339 /// Handles a ready-for-reading TLS squid-to-server connection that
340 /// we thought was idle.
341 /// \return false if and only if the connection should be closed.
342 bool handleIdleClientPinnedTlsRead();
343#endif
7ac40923 344
9ce4a1eb
CT
345 /// Parse an HTTP request
346 /// \note Sets result->flags.parsed_ok to 0 if failed to parse the request,
347 /// to 1 if the request was correctly parsed
348 /// \param[in] hp an Http1::RequestParser
349 /// \return NULL on incomplete requests,
350 /// a Http::Stream on success or failure.
351 /// TODO: Move to HttpServer. Warning: Move requires large code nonchanges!
352 Http::Stream *parseHttpRequest(const Http1::RequestParserPointer &);
353
e7ce227f 354 /// parse input buffer prefix into a single transfer protocol request
eacfca83
AR
355 /// return NULL to request more header bytes (after checking any limits)
356 /// use abortRequestParsing() to handle parsing errors w/o creating request
d3dddfb5 357 virtual Http::Stream *parseOneRequest() = 0;
e7ce227f
AR
358
359 /// start processing a freshly parsed request
6b2b6cfe 360 virtual void processParsedRequest(Http::StreamPointer &) = 0;
92ae4c86
AR
361
362 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
363 virtual int pipelinePrefetchMax() const;
364
365 /// timeout to use when waiting for the next request
366 virtual time_t idleTimeout() const = 0;
367
42cbf844 368 /// Perform client data lookups that depend on client src-IP.
85b506ff 369 /// The PROXY protocol may require some data input first.
42cbf844
AJ
370 void whenClientIpKnown();
371
3cc0f4e7
AR
372 BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
373
9ce4a1eb
CT
374 /// whether preservedClientData is valid and should be kept up to date
375 bool preservingClientData_;
376
1cf238db 377private:
fcc444e3
AJ
378 /* ::Server API */
379 virtual bool connFinishedWithConn(int size);
da6dbcd1 380 virtual void checkLogging();
fcc444e3 381
f35961af 382 void clientAfterReadingRequests();
079a8480 383 bool concurrentRequestQueueFilled() const;
1cf238db 384
801cfc26 385 void pinConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest &request);
89b1d7a2 386
00d0ce87 387 /* PROXY protocol functionality */
6658cc16 388 bool proxyProtocolValidateClient();
3d74cb1f 389 bool parseProxyProtocolHeader();
1689cdbc 390 bool proxyProtocolError(const char *reason);
00d0ce87 391
5107d2c4
CT
392#if USE_OPENSSL
393 /// \returns a pointer to the matching cached TLS context or nil
394 Security::ContextPointer getTlsContextFromCache(const SBuf &cacheKey, const Ssl::CertificateProperties &certProperties);
395
396 /// Attempts to add a given TLS context to the cache, replacing the old
397 /// same-key context, if any
398 void storeTlsContextToCache(const SBuf &cacheKey, Security::ContextPointer &ctx);
399#endif
400
3bd97e7e 401 /// whether PROXY protocol header is still expected
00d0ce87
AJ
402 bool needProxyProtocolHeader_;
403
36c774f7
EB
404 /// the parsed PROXY protocol header
405 ProxyProtocol::HeaderPointer proxyProtocolHeader_;
406
cc1e110a
AJ
407#if USE_AUTH
408 /// some user details that can be used to perform authentication on this connection
409 Auth::UserRequest::Pointer auth_;
410#endif
411
cb4f4424 412#if USE_OPENSSL
ae7ff0b8 413 bool switchedToHttps_;
d20cf186 414 bool parsingTlsHandshake; ///< whether we are getting/parsing TLS Hello bytes
9ce4a1eb
CT
415 /// The number of parsed HTTP requests headers on a bumped client connection
416 uint64_t parsedBumpedRequestCount;
d20cf186 417
9ce4a1eb
CT
418 /// The TLS server host name appears in CONNECT request or the server ip address for the intercepted requests
419 SBuf tlsConnectHostOrIp; ///< The TLS server host name as passed in the CONNECT request
0a57a661 420 unsigned short tlsConnectPort; ///< The TLS server port number as passed in the CONNECT request
69f69080 421 SBuf sslCommonName_; ///< CN name for SSL certificate generation
4f6990ec
CT
422
423 /// TLS client delivered SNI value. Empty string if none has been received.
424 SBuf tlsClientSni_;
5107d2c4 425 SBuf sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
d7ce0bcd 426
fd4624d7
CT
427 /// HTTPS server cert. fetching state for bump-ssl-server-first
428 Ssl::ServerBump *sslServerBump;
aebe6888 429 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
d7ce0bcd
AR
430#endif
431
cf6eb29e
CT
432 /// the reason why we no longer write the response or nil
433 const char *stoppedSending_;
434 /// the reason why we no longer read the request or nil
435 const char *stoppedReceiving_;
75d47340
CT
436 /// Connection annotations, clt_conn_tag and other tags are stored here.
437 /// If set, are propagated to the current and all future master transactions
438 /// on the connection.
439 NotePairs::Pointer theNotes;
6039b729 440};
441
8596962e 442const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
443
8a648e8d 444int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
4efc6056 445
e7ce227f 446/// accept requests to a given port and inform subCall about them
92ae4c86
AR
447void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId noteId);
448
8a648e8d 449void clientOpenListenSockets(void);
434a79b0 450void clientConnectionsClose(void);
8a648e8d 451void httpRequestFree(void *);
93da1f99 452
e7ce227f 453/// decide whether to expect multiple requests on the corresponding connection
92ae4c86
AR
454void clientSetKeepaliveFlag(ClientHttpRequest *http);
455
d6fdeb41 456/// append a "part" HTTP header (as in a multi-part/range reply) to the buffer
a0c227a9 457void clientPackRangeHdr(const HttpReplyPointer &, const HttpHdrRangeSpec *, String boundary, MemBuf *);
d6fdeb41
AJ
458
459/// put terminating boundary for multiparts to the buffer
460void clientPackTermBound(String boundary, MemBuf *);
461
92ae4c86
AR
462/* misplaced declaratrions of Stream callbacks provided/used by client side */
463SQUIDCEXTERN CSR clientGetMoreData;
464SQUIDCEXTERN CSS clientReplyStatus;
465SQUIDCEXTERN CSD clientReplyDetach;
466CSCB clientSocketRecipient;
467CSD clientSocketDetach;
468
d3dddfb5 469void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, Http::Stream *);
9bafa70d 470void clientPostHttpsAccept(ConnStateData *);
93da1f99 471
801cfc26
CT
472std::ostream &operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic);
473
6039b729 474#endif /* SQUID_CLIENTSIDE_H */
f53969cc 475