]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
Enable source-formatting tools to collapse multiple whitelines in the source to one.
[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 #include "base/AsyncJob.h"
37 #include "BodyPipe.h"
38 #include "comm.h"
39 #include "CommCalls.h"
40 #include "HttpRequest.h"
41 #include "HttpControlMsg.h"
42 #include "HttpParser.h"
43 #include "RefCount.h"
44 #include "StoreIOBuffer.h"
45 #if USE_AUTH
46 #include "auth/UserRequest.h"
47 #endif
48 #if USE_SSL
49 #include "ssl/support.h"
50 #endif
51
52 class ConnStateData;
53 class ClientHttpRequest;
54 class clientStreamNode;
55 class ChunkedCodingParser;
56
57 /**
58 * Badly named.
59 * This is in fact the processing context for a single HTTP request.
60 *
61 * Managing what has been done, and what happens next to the data buffer
62 * holding what we hope is an HTTP request.
63 *
64 * Parsing is still a mess of global functions done in conjunction with the
65 * real socket controller which generated ClientHttpRequest.
66 * It also generates one of us and passes us control from there based on
67 * the results of the parse.
68 *
69 * After that all the request interpretation and adaptation is in our scope.
70 * Then finally the reply fetcher is created by this and we get the result
71 * back. Which we then have to manage writing of it to the ConnStateData.
72 *
73 * The socket level management is done by a ConnStateData which owns us.
74 * The scope of this objects control over a socket consists of the data
75 * buffer received from ConnStateData with an initially unknown length.
76 * When that length is known it sets the end bounary of our acces to the
77 * buffer.
78 *
79 * The individual processing actions are done by other Jobs which we
80 * kick off as needed.
81 */
82 class ClientSocketContext : public RefCountable
83 {
84
85 public:
86 typedef RefCount<ClientSocketContext> Pointer;
87 void *operator new(size_t);
88 void operator delete(void *);
89 ClientSocketContext();
90 ~ClientSocketContext();
91 bool startOfOutput() const;
92 void writeComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag);
93 void keepaliveNextRequest();
94
95 Comm::ConnectionPointer clientConnection; /// details about the client connection socket.
96 ClientHttpRequest *http; /* we own this */
97 HttpReply *reply;
98 char reqbuf[HTTP_REQBUF_SZ];
99 Pointer next;
100
101 struct {
102
103 unsigned deferred:1; /* This is a pipelined request waiting for the current object to complete */
104
105 unsigned parsed_ok:1; /* Was this parsed correctly? */
106 } flags;
107 bool mayUseConnection() const {return mayUseConnection_;}
108
109 void mayUseConnection(bool aBool) {
110 mayUseConnection_ = aBool;
111 debugs(33,3, HERE << "This " << this << " marked " << aBool);
112 }
113
114 class DeferredParams
115 {
116
117 public:
118 clientStreamNode *node;
119 HttpReply *rep;
120 StoreIOBuffer queuedBuffer;
121 };
122
123 DeferredParams deferredparams;
124 int64_t writtenToSocket;
125 void pullData();
126 int64_t getNextRangeOffset() const;
127 bool canPackMoreRanges() const;
128 clientStream_status_t socketState();
129 void sendBody(HttpReply * rep, StoreIOBuffer bodyData);
130 void sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData);
131 size_t lengthToSend(Range<int64_t> const &available);
132 void noteSentBodyBytes(size_t);
133 void buildRangeHeader(HttpReply * rep);
134 clientStreamNode * getTail() const;
135 clientStreamNode * getClientReplyContext() const;
136 void connIsFinished();
137 void removeFromConnectionList(ConnStateData * conn);
138 void deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer receivedData);
139 bool multipartRangeRequest() const;
140 void registerWithConn();
141 void noteIoError(const int xerrno); ///< update state to reflect I/O error
142
143 /// starts writing 1xx control message to the client
144 void writeControlMsg(HttpControlMsg &msg);
145
146 protected:
147 static IOCB WroteControlMsg;
148 void wroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno);
149
150 private:
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 CBDATA_CLASS(ClientSocketContext);
164 };
165
166
167 class ConnectionDetail;
168 #if USE_SSL
169 namespace Ssl
170 {
171 class ServerBump;
172 }
173 #endif
174 /**
175 * Manages a connection to a client.
176 *
177 * Multiple requests (up to 2) can be pipelined. This object is responsible for managing
178 * which one is currently being fulfilled and what happens to the queue if the current one
179 * causes the client connection to be closed early.
180 *
181 * Act as a manager for the connection and passes data in buffer to the current parser.
182 * the parser has ambiguous scope at present due to being made from global functions
183 * I believe this object uses the parser to identify boundaries and kick off the
184 * actual HTTP request handling objects (ClientSocketContext, ClientHttpRequest, HttpRequest)
185 *
186 * If the above can be confirmed accurate we can call this object PipelineManager or similar
187 */
188 class ConnStateData : public BodyProducer, public HttpControlMsgSink
189 {
190
191 public:
192
193 ConnStateData();
194 ~ConnStateData();
195
196 void readSomeData();
197 int getAvailableBufferLength() const;
198 bool areAllContextsForThisConnection() const;
199 void freeAllContexts();
200 void notifyAllContexts(const int xerrno); ///< tell everybody about the err
201 /// Traffic parsing
202 bool clientParseRequests();
203 void readNextRequest();
204 bool maybeMakeSpaceAvailable();
205 ClientSocketContext::Pointer getCurrentContext() const;
206 void addContextToQueue(ClientSocketContext * context);
207 int getConcurrentRequestCount() const;
208 bool isOpen() const;
209 void checkHeaderLimits();
210
211 // HttpControlMsgSink API
212 virtual void sendControlMsg(HttpControlMsg msg);
213
214 // Client TCP connection details from comm layer.
215 Comm::ConnectionPointer clientConnection;
216
217 struct In {
218 In();
219 ~In();
220 char *addressToReadInto() const;
221
222 ChunkedCodingParser *bodyParser; ///< parses chunked request body
223 char *buf;
224 size_t notYetUsed;
225 size_t allocatedSize;
226 } in;
227
228 /** number of body bytes we need to comm_read for the "current" request
229 *
230 * \retval 0 We do not need to read any [more] body bytes
231 * \retval negative May need more but do not know how many; could be zero!
232 * \retval positive Need to read exactly that many more body bytes
233 */
234 int64_t mayNeedToReadMoreBody() const;
235
236 #if USE_AUTH
237 /**
238 * note this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
239 * the user details for connection based authentication
240 */
241 Auth::UserRequest::Pointer auth_user_request;
242 #endif
243
244 /**
245 * used by the owner of the connection, opaque otherwise
246 * TODO: generalise the connection owner concept.
247 */
248 ClientSocketContext::Pointer currentobject;
249
250 Ip::Address log_addr;
251 int nrequests;
252
253 struct {
254 bool readMore; ///< needs comm_read (for this request or new requests)
255 bool swanSang; // XXX: temporary flag to check proper cleanup
256 } flags;
257 struct {
258 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
259 char *host; /* host name of pinned connection */
260 int port; /* port of pinned connection */
261 bool pinned; /* this connection was pinned */
262 bool auth; /* pinned for www authentication */
263 struct peer *peer; /* peer the connection goes via */
264 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
265 } pinning;
266
267 AnyP::PortCfg *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::Pointer expectRequestBody(int64_t size);
285 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer);
286 virtual void noteBodyConsumerAborted(BodyPipe::Pointer);
287
288 bool handleReadData(char *buf, size_t size);
289 bool handleRequestBodyData();
290
291 /**
292 * Correlate the current ConnStateData object with the pinning_fd socket descriptor.
293 */
294 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, struct peer *peer, bool auth);
295 /**
296 * Decorrelate the ConnStateData object from its pinned peer
297 */
298 void unpinConnection();
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 peer if it is not NULL also check if the peer is the pinning peer
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 struct peer *peer);
307 /**
308 * returts the pinned peer if exists, NULL otherwise
309 */
310 struct peer *pinnedPeer() const {return pinning.peer;}
311 bool pinnedAuth() const {return pinning.auth;}
312
313 // pining related comm callbacks
314 void clientPinnedConnectionClosed(const CommCloseCbParams &io);
315
316 // comm callbacks
317 void clientReadRequest(const CommIoCbParams &io);
318 void connStateClosed(const CommCloseCbParams &io);
319 void requestTimeout(const CommTimeoutCbParams &params);
320
321 // AsyncJob API
322 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
323 virtual void swanSong();
324
325 /// Changes state so that we close the connection and quit after serving
326 /// the client-side-detected error response instead of getting stuck.
327 void quitAfterError(HttpRequest *request); // meant to be private
328
329 #if USE_SSL
330 /// called by FwdState when it is done bumping the server
331 void httpsPeeked(Comm::ConnectionPointer serverConnection);
332
333 /// Start to create dynamic SSL_CTX for host or uses static port SSL context.
334 void getSslContextStart();
335 /**
336 * Done create dynamic ssl certificate.
337 *
338 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
339 */
340 void getSslContextDone(SSL_CTX * sslContext, bool isNew = false);
341 /// Callback function. It is called when squid receive message from ssl_crtd.
342 static void sslCrtdHandleReplyWrapper(void *data, char *reply);
343 /// Proccess response from ssl_crtd.
344 void sslCrtdHandleReply(const char * reply);
345
346 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
347 bool switchedToHttps() const { return switchedToHttps_; }
348 Ssl::ServerBump *serverBump() {return sslServerBump;}
349 inline void setServerBump(Ssl::ServerBump *srvBump) {
350 if (!sslServerBump)
351 sslServerBump = srvBump;
352 else
353 assert(sslServerBump == srvBump);
354 }
355 /// Fill the certAdaptParams with the required data for certificate adaptation
356 /// and create the key for storing/retrieve the certificate to/from the cache
357 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
358 /// Called when the client sends the first request on a bumped connection.
359 /// Returns false if no [delayed] error should be written to the client.
360 /// Otherwise, writes the error to the client and returns true. Also checks
361 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
362 bool serveDelayedError(ClientSocketContext *context);
363
364 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
365
366 #else
367 bool switchedToHttps() const { return false; }
368 #endif
369
370 protected:
371 void startDechunkingRequest();
372 void finishDechunkingRequest(bool withSuccess);
373 void abortChunkedRequestBody(const err_type error);
374 err_type handleChunkedRequestBody(size_t &putSize);
375
376 private:
377 int connReadWasError(comm_err_t flag, int size, int xerrno);
378 int connFinishedWithConn(int size);
379 void clientAfterReadingRequests();
380
381 private:
382 HttpParser parser_;
383
384 // XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :(
385
386 #if USE_SSL
387 bool switchedToHttps_;
388 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
389 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
390 String sslCommonName; ///< CN name for SSL certificate generation
391 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
392
393 /// HTTPS server cert. fetching state for bump-ssl-server-first
394 Ssl::ServerBump *sslServerBump;
395 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
396 #endif
397
398 /// the reason why we no longer write the response or nil
399 const char *stoppedSending_;
400 /// the reason why we no longer read the request or nil
401 const char *stoppedReceiving_;
402
403 AsyncCall::Pointer reader; ///< set when we are reading
404 BodyPipe::Pointer bodyPipe; // set when we are reading request body
405
406 CBDATA_CLASS2(ConnStateData);
407 };
408
409 /* convenience class while splitting up body handling */
410 /* temporary existence only - on stack use expected */
411
412 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
413
414 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
415
416 #endif /* SQUID_CLIENTSIDE_H */