5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
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.
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.
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.
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.
33 #ifndef SQUID_CLIENTSIDE_H
34 #define SQUID_CLIENTSIDE_H
37 #include "auth/UserRequest.h"
39 #include "base/AsyncJob.h"
42 #include "CommCalls.h"
43 #include "HttpControlMsg.h"
44 #include "HttpParser.h"
46 #include "StoreIOBuffer.h"
48 #include "ssl/support.h"
52 class ClientHttpRequest
;
53 class clientStreamNode
;
54 class ChunkedCodingParser
;
58 * This is in fact the processing context for a single HTTP request.
60 * Managing what has been done, and what happens next to the data buffer
61 * holding what we hope is an HTTP request.
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.
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.
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
78 * The individual processing actions are done by other Jobs which we
81 class ClientSocketContext
: public RefCountable
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();
94 Comm::ConnectionPointer clientConnection
; /// details about the client connection socket.
95 ClientHttpRequest
*http
; /* we own this */
97 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 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
142 /// starts writing 1xx control message to the client
143 void writeControlMsg(HttpControlMsg
&msg
);
146 static IOCB WroteControlMsg
;
147 void wroteControlMsg(const Comm::ConnectionPointer
&conn
, char *bufnotused
, size_t size
, comm_err_t errflag
, int xerrno
);
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();
156 void initiateClose(const char *reason
);
158 AsyncCall::Pointer cbControlMsgSent
; ///< notifies HttpControlMsg Source
160 bool mayUseConnection_
; /* This request may use the connection. Don't read anymore requests for now */
161 bool connRegistered_
;
165 class ConnectionDetail
;
173 * Manages a connection to a client.
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.
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)
184 * If the above can be confirmed accurate we can call this object PipelineManager or similar
186 class ConnStateData
: public BodyProducer
, public HttpControlMsgSink
195 int getAvailableBufferLength() const;
196 bool areAllContextsForThisConnection() const;
197 void freeAllContexts();
198 void notifyAllContexts(const int xerrno
); ///< tell everybody about the err
200 bool clientParseRequests();
201 void readNextRequest();
202 bool maybeMakeSpaceAvailable();
203 ClientSocketContext::Pointer
getCurrentContext() const;
204 void addContextToQueue(ClientSocketContext
* context
);
205 int getConcurrentRequestCount() const;
207 void checkHeaderLimits();
209 // HttpControlMsgSink API
210 virtual void sendControlMsg(HttpControlMsg msg
);
212 // Client TCP connection details from comm layer.
213 Comm::ConnectionPointer clientConnection
;
218 char *addressToReadInto() const;
220 ChunkedCodingParser
*bodyParser
; ///< parses chunked request body
223 size_t allocatedSize
;
226 /** number of body bytes we need to comm_read for the "current" request
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
232 int64_t mayNeedToReadMoreBody() const;
236 * note this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
237 * the user details for connection based authentication
239 Auth::UserRequest::Pointer auth_user_request
;
243 * used by the owner of the connection, opaque otherwise
244 * TODO: generalise the connection owner concept.
246 ClientSocketContext::Pointer currentobject
;
248 Ip::Address log_addr
;
252 bool readMore
; ///< needs comm_read (for this request or new requests)
253 bool swanSang
; // XXX: temporary flag to check proper cleanup
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*/
267 bool transparent() const;
268 bool reading() const;
269 void stopReading(); ///< cancels comm_read if it is scheduled
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
);
280 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
282 BodyPipe::Pointer
expectRequestBody(int64_t size
);
283 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer
);
284 virtual void noteBodyConsumerAborted(BodyPipe::Pointer
);
286 bool handleReadData(char *buf
, size_t size
);
287 bool handleRequestBodyData();
290 * Correlate the current ConnStateData object with the pinning_fd socket descriptor.
292 void pinConnection(const Comm::ConnectionPointer
&pinServerConn
, HttpRequest
*request
, struct peer
*peer
, bool auth
);
294 * Decorrelate the ConnStateData object from its pinned peer
296 void unpinConnection();
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).
304 const Comm::ConnectionPointer
validatePinnedConnection(HttpRequest
*request
, const struct peer
*peer
);
306 * returts the pinned peer if exists, NULL otherwise
308 struct peer
*pinnedPeer() const {return pinning
.peer
;}
309 bool pinnedAuth() const {return pinning
.auth
;}
311 // pining related comm callbacks
312 void clientPinnedConnectionClosed(const CommCloseCbParams
&io
);
315 void clientReadRequest(const CommIoCbParams
&io
);
316 void connStateClosed(const CommCloseCbParams
&io
);
317 void requestTimeout(const CommTimeoutCbParams
¶ms
);
320 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
321 virtual void swanSong();
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
328 /// called by FwdState when it is done bumping the server
329 void httpsPeeked(Comm::ConnectionPointer serverConnection
);
331 /// Start to create dynamic SSL_CTX for host or uses static port SSL context.
332 void getSslContextStart();
334 * Done create dynamic ssl certificate.
336 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
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
);
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
) {
349 sslServerBump
= srvBump
;
351 assert(sslServerBump
== srvBump
);
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
);
362 Ssl::BumpMode sslBumpMode
; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
365 bool switchedToHttps() const { return false; }
369 void startDechunkingRequest();
370 void finishDechunkingRequest(bool withSuccess
);
371 void abortChunkedRequestBody(const err_type error
);
372 err_type
handleChunkedRequestBody(size_t &putSize
);
375 int connReadWasError(comm_err_t flag
, int size
, int xerrno
);
376 int connFinishedWithConn(int size
);
377 void clientAfterReadingRequests();
382 // XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :(
383 CBDATA_CLASS2(ConnStateData
);
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
392 /// HTTPS server cert. fetching state for bump-ssl-server-first
393 Ssl::ServerBump
*sslServerBump
;
394 Ssl::CertSignAlgorithm signAlgorithm
; ///< The signing algorithm to use
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_
;
402 AsyncCall::Pointer reader
; ///< set when we are reading
403 BodyPipe::Pointer bodyPipe
; // set when we are reading request body
406 /* convenience class while splitting up body handling */
407 /* temporary existence only - on stack use expected */
409 void setLogUri(ClientHttpRequest
* http
, char const *uri
, bool cleanUrl
= false);
411 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion
, const char *end
= NULL
);
413 #endif /* SQUID_CLIENTSIDE_H */