]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
SourceFormat Enforcement
[thirdparty/squid.git] / src / client_side.h
1 /*
2 * $Id$
3 *
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
33 #ifndef SQUID_CLIENTSIDE_H
34 #define SQUID_CLIENTSIDE_H
35
36 #if USE_AUTH
37 #include "auth/UserRequest.h"
38 #endif
39 #include "base/AsyncJob.h"
40 #include "BodyPipe.h"
41 #include "comm.h"
42 #include "CommCalls.h"
43 #include "HttpControlMsg.h"
44 #include "HttpParser.h"
45 #include "RefCount.h"
46 #include "StoreIOBuffer.h"
47 #if USE_SSL
48 #include "ssl/support.h"
49 #endif
50
51 class ConnStateData;
52 class ClientHttpRequest;
53 class clientStreamNode;
54 class ChunkedCodingParser;
55
56 /**
57 * Badly named.
58 * This is in fact the processing context for a single HTTP request.
59 *
60 * Managing what has been done, and what happens next to the data buffer
61 * holding what we hope is an HTTP request.
62 *
63 * Parsing is still a mess of global functions done in conjunction with the
64 * real socket controller which generated ClientHttpRequest.
65 * It also generates one of us and passes us control from there based on
66 * the results of the parse.
67 *
68 * After that all the request interpretation and adaptation is in our scope.
69 * Then finally the reply fetcher is created by this and we get the result
70 * back. Which we then have to manage writing of it to the ConnStateData.
71 *
72 * The socket level management is done by a ConnStateData which owns us.
73 * The scope of this objects control over a socket consists of the data
74 * buffer received from ConnStateData with an initially unknown length.
75 * When that length is known it sets the end bounary of our acces to the
76 * buffer.
77 *
78 * The individual processing actions are done by other Jobs which we
79 * kick off as needed.
80 */
81 class ClientSocketContext : public RefCountable
82 {
83
84 public:
85 typedef RefCount<ClientSocketContext> Pointer;
86 void *operator new(size_t);
87 void operator delete(void *);
88 ClientSocketContext();
89 ~ClientSocketContext();
90 bool startOfOutput() const;
91 void writeComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag);
92 void keepaliveNextRequest();
93
94 Comm::ConnectionPointer clientConnection; /// details about the client connection socket.
95 ClientHttpRequest *http; /* we own this */
96 HttpReply *reply;
97 char reqbuf[HTTP_REQBUF_SZ];
98 Pointer next;
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 void connIsFinished();
136 void removeFromConnectionList(ConnStateData * conn);
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_err_t errflag, int xerrno);
148
149 private:
150 CBDATA_CLASS(ClientSocketContext);
151 void prepareReply(HttpReply * rep);
152 void packChunk(const StoreIOBuffer &bodyData, MemBuf &mb);
153 void packRange(StoreIOBuffer const &, MemBuf * mb);
154 void deRegisterWithConn();
155 void doClose();
156 void initiateClose(const char *reason);
157
158 AsyncCall::Pointer cbControlMsgSent; ///< notifies HttpControlMsg Source
159
160 bool mayUseConnection_; /* This request may use the connection. Don't read anymore requests for now */
161 bool connRegistered_;
162 };
163
164
165 class ConnectionDetail;
166 #if USE_SSL
167 namespace Ssl
168 {
169 class ServerBump;
170 }
171 #endif
172 /**
173 * Manages a connection to a client.
174 *
175 * Multiple requests (up to 2) can be pipelined. This object is responsible for managing
176 * which one is currently being fulfilled and what happens to the queue if the current one
177 * causes the client connection to be closed early.
178 *
179 * Act as a manager for the connection and passes data in buffer to the current parser.
180 * the parser has ambiguous scope at present due to being made from global functions
181 * I believe this object uses the parser to identify boundaries and kick off the
182 * actual HTTP request handling objects (ClientSocketContext, ClientHttpRequest, HttpRequest)
183 *
184 * If the above can be confirmed accurate we can call this object PipelineManager or similar
185 */
186 class ConnStateData : public BodyProducer, public HttpControlMsgSink
187 {
188
189 public:
190
191 ConnStateData();
192 ~ConnStateData();
193
194 void readSomeData();
195 int getAvailableBufferLength() const;
196 bool areAllContextsForThisConnection() const;
197 void freeAllContexts();
198 void notifyAllContexts(const int xerrno); ///< tell everybody about the err
199 /// Traffic parsing
200 bool clientParseRequests();
201 void readNextRequest();
202 bool maybeMakeSpaceAvailable();
203 ClientSocketContext::Pointer getCurrentContext() const;
204 void addContextToQueue(ClientSocketContext * context);
205 int getConcurrentRequestCount() const;
206 bool isOpen() const;
207 void checkHeaderLimits();
208
209 // HttpControlMsgSink API
210 virtual void sendControlMsg(HttpControlMsg msg);
211
212 // Client TCP connection details from comm layer.
213 Comm::ConnectionPointer clientConnection;
214
215 struct In {
216 In();
217 ~In();
218 char *addressToReadInto() const;
219
220 ChunkedCodingParser *bodyParser; ///< parses chunked request body
221 char *buf;
222 size_t notYetUsed;
223 size_t allocatedSize;
224 } in;
225
226 /** number of body bytes we need to comm_read for the "current" request
227 *
228 * \retval 0 We do not need to read any [more] body bytes
229 * \retval negative May need more but do not know how many; could be zero!
230 * \retval positive Need to read exactly that many more body bytes
231 */
232 int64_t mayNeedToReadMoreBody() const;
233
234 #if USE_AUTH
235 /**
236 * note this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
237 * the user details for connection based authentication
238 */
239 Auth::UserRequest::Pointer auth_user_request;
240 #endif
241
242 /**
243 * used by the owner of the connection, opaque otherwise
244 * TODO: generalise the connection owner concept.
245 */
246 ClientSocketContext::Pointer currentobject;
247
248 Ip::Address log_addr;
249 int nrequests;
250
251 struct {
252 bool readMore; ///< needs comm_read (for this request or new requests)
253 bool swanSang; // XXX: temporary flag to check proper cleanup
254 } flags;
255 struct {
256 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
257 char *host; /* host name of pinned connection */
258 int port; /* port of pinned connection */
259 bool pinned; /* this connection was pinned */
260 bool auth; /* pinned for www authentication */
261 struct peer *peer; /* peer the connection goes via */
262 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
263 } pinning;
264
265 AnyP::PortCfg *port;
266
267 bool transparent() const;
268 bool reading() const;
269 void stopReading(); ///< cancels comm_read if it is scheduled
270
271 /// true if we stopped receiving the request
272 const char *stoppedReceiving() const { return stoppedReceiving_; }
273 /// true if we stopped sending the response
274 const char *stoppedSending() const { return stoppedSending_; }
275 /// note request receiving error and close as soon as we write the response
276 void stopReceiving(const char *error);
277 /// note response sending error and close as soon as we read the request
278 void stopSending(const char *error);
279
280 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
281
282 BodyPipe::Pointer expectRequestBody(int64_t size);
283 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer);
284 virtual void noteBodyConsumerAborted(BodyPipe::Pointer);
285
286 bool handleReadData(char *buf, size_t size);
287 bool handleRequestBodyData();
288
289 /**
290 * Correlate the current ConnStateData object with the pinning_fd socket descriptor.
291 */
292 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, struct peer *peer, bool auth);
293 /**
294 * Decorrelate the ConnStateData object from its pinned peer
295 */
296 void unpinConnection();
297 /**
298 * Checks if there is pinning info if it is valid. It can close the server side connection
299 * if pinned info is not valid.
300 \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
301 \param peer if it is not NULL also check if the peer is the pinning peer
302 \return The details of the server side connection (may be closed if failures were present).
303 */
304 const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const struct peer *peer);
305 /**
306 * returts the pinned peer if exists, NULL otherwise
307 */
308 struct peer *pinnedPeer() const {return pinning.peer;}
309 bool pinnedAuth() const {return pinning.auth;}
310
311 // pining related comm callbacks
312 void clientPinnedConnectionClosed(const CommCloseCbParams &io);
313
314 // comm callbacks
315 void clientReadRequest(const CommIoCbParams &io);
316 void connStateClosed(const CommCloseCbParams &io);
317 void requestTimeout(const CommTimeoutCbParams &params);
318
319 // AsyncJob API
320 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
321 virtual void swanSong();
322
323 /// Changes state so that we close the connection and quit after serving
324 /// the client-side-detected error response instead of getting stuck.
325 void quitAfterError(HttpRequest *request); // meant to be private
326
327 #if USE_SSL
328 /// called by FwdState when it is done bumping the server
329 void httpsPeeked(Comm::ConnectionPointer serverConnection);
330
331 /// Start to create dynamic SSL_CTX for host or uses static port SSL context.
332 void getSslContextStart();
333 /**
334 * Done create dynamic ssl certificate.
335 *
336 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
337 */
338 void getSslContextDone(SSL_CTX * sslContext, bool isNew = false);
339 /// Callback function. It is called when squid receive message from ssl_crtd.
340 static void sslCrtdHandleReplyWrapper(void *data, char *reply);
341 /// Proccess response from ssl_crtd.
342 void sslCrtdHandleReply(const char * reply);
343
344 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
345 bool switchedToHttps() const { return switchedToHttps_; }
346 Ssl::ServerBump *serverBump() {return sslServerBump;}
347 inline void setServerBump(Ssl::ServerBump *srvBump) {
348 if (!sslServerBump)
349 sslServerBump = srvBump;
350 else
351 assert(sslServerBump == srvBump);
352 }
353 /// Fill the certAdaptParams with the required data for certificate adaptation
354 /// and create the key for storing/retrieve the certificate to/from the cache
355 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
356 /// Called when the client sends the first request on a bumped connection.
357 /// Returns false if no [delayed] error should be written to the client.
358 /// Otherwise, writes the error to the client and returns true. Also checks
359 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
360 bool serveDelayedError(ClientSocketContext *context);
361
362 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
363
364 #else
365 bool switchedToHttps() const { return false; }
366 #endif
367
368 protected:
369 void startDechunkingRequest();
370 void finishDechunkingRequest(bool withSuccess);
371 void abortChunkedRequestBody(const err_type error);
372 err_type handleChunkedRequestBody(size_t &putSize);
373
374 private:
375 int connReadWasError(comm_err_t flag, int size, int xerrno);
376 int connFinishedWithConn(int size);
377 void clientAfterReadingRequests();
378
379 private:
380 HttpParser parser_;
381
382 // XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :(
383 CBDATA_CLASS2(ConnStateData);
384
385 #if USE_SSL
386 bool switchedToHttps_;
387 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
388 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
389 String sslCommonName; ///< CN name for SSL certificate generation
390 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
391
392 /// HTTPS server cert. fetching state for bump-ssl-server-first
393 Ssl::ServerBump *sslServerBump;
394 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
395 #endif
396
397 /// the reason why we no longer write the response or nil
398 const char *stoppedSending_;
399 /// the reason why we no longer read the request or nil
400 const char *stoppedReceiving_;
401
402 AsyncCall::Pointer reader; ///< set when we are reading
403 BodyPipe::Pointer bodyPipe; // set when we are reading request body
404 };
405
406 /* convenience class while splitting up body handling */
407 /* temporary existence only - on stack use expected */
408
409 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
410
411 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
412
413 #endif /* SQUID_CLIENTSIDE_H */