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