]>
Commit | Line | Data |
---|---|---|
6039b729 | 1 | /* |
262a0e14 | 2 | * $Id$ |
6039b729 | 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. | |
9e008dda | 21 | * |
6039b729 | 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. | |
9e008dda | 26 | * |
6039b729 | 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 | ||
2f1431ea | 36 | #if USE_AUTH |
a33a428a | 37 | #include "auth/UserRequest.h" |
2f1431ea | 38 | #endif |
d1e045c3 | 39 | #include "base/AsyncJob.h" |
a98c2da5 AJ |
40 | #include "BodyPipe.h" |
41 | #include "comm.h" | |
1cf238db | 42 | #include "CommCalls.h" |
655daa06 | 43 | #include "HttpControlMsg.h" |
4c14658e | 44 | #include "HttpParser.h" |
a98c2da5 AJ |
45 | #include "RefCount.h" |
46 | #include "StoreIOBuffer.h" | |
061bbdec CT |
47 | #if USE_SSL |
48 | #include "ssl/support.h" | |
49 | #endif | |
0655fa4d | 50 | |
51 | class ConnStateData; | |
0655fa4d | 52 | class ClientHttpRequest; |
0655fa4d | 53 | class clientStreamNode; |
3ff65596 | 54 | class ChunkedCodingParser; |
3ff65596 | 55 | |
27774cee AJ |
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 | */ | |
0655fa4d | 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 *); | |
0655fa4d | 88 | ClientSocketContext(); |
89 | ~ClientSocketContext(); | |
90 | bool startOfOutput() const; | |
e0d28505 | 91 | void writeComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag); |
0655fa4d | 92 | void keepaliveNextRequest(); |
be364179 AJ |
93 | |
94 | Comm::ConnectionPointer clientConnection; /// details about the client connection socket. | |
0655fa4d | 95 | ClientHttpRequest *http; /* we own this */ |
fedd1531 | 96 | HttpReply *reply; |
0655fa4d | 97 | char reqbuf[HTTP_REQBUF_SZ]; |
98 | Pointer next; | |
99 | ||
9e008dda | 100 | struct { |
0655fa4d | 101 | |
9e008dda | 102 | unsigned deferred:1; /* This is a pipelined request waiting for the current object to complete */ |
0655fa4d | 103 | |
9e008dda | 104 | unsigned parsed_ok:1; /* Was this parsed correctly? */ |
2fadd50d | 105 | } flags; |
0655fa4d | 106 | bool mayUseConnection() const {return mayUseConnection_;} |
107 | ||
9e008dda | 108 | void mayUseConnection(bool aBool) { |
0655fa4d | 109 | mayUseConnection_ = aBool; |
96e03dd8 | 110 | debugs(33,3, HERE << "This " << this << " marked " << aBool); |
0655fa4d | 111 | } |
112 | ||
7d9b0628 | 113 | class DeferredParams |
0655fa4d | 114 | { |
7d9b0628 | 115 | |
116 | public: | |
0655fa4d | 117 | clientStreamNode *node; |
118 | HttpReply *rep; | |
119 | StoreIOBuffer queuedBuffer; | |
7d9b0628 | 120 | }; |
0655fa4d | 121 | |
7d9b0628 | 122 | DeferredParams deferredparams; |
57d55dfa | 123 | int64_t writtenToSocket; |
0655fa4d | 124 | void pullData(); |
47f6e231 | 125 | int64_t getNextRangeOffset() const; |
0655fa4d | 126 | bool canPackMoreRanges() const; |
127 | clientStream_status_t socketState(); | |
128 | void sendBody(HttpReply * rep, StoreIOBuffer bodyData); | |
129 | void sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData); | |
47f6e231 | 130 | size_t lengthToSend(Range<int64_t> const &available); |
0655fa4d | 131 | void noteSentBodyBytes(size_t); |
132 | void buildRangeHeader(HttpReply * rep); | |
0655fa4d | 133 | clientStreamNode * getTail() const; |
134 | clientStreamNode * getClientReplyContext() const; | |
135 | void connIsFinished(); | |
1cf238db | 136 | void removeFromConnectionList(ConnStateData * conn); |
2324cda2 | 137 | void deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer receivedData); |
0655fa4d | 138 | bool multipartRangeRequest() const; |
0655fa4d | 139 | void registerWithConn(); |
f692498b | 140 | void noteIoError(const int xerrno); ///< update state to reflect I/O error |
0655fa4d | 141 | |
655daa06 AR |
142 | /// starts writing 1xx control message to the client |
143 | void writeControlMsg(HttpControlMsg &msg); | |
144 | ||
145 | protected: | |
1b76e6c1 | 146 | static IOCB WroteControlMsg; |
e0d28505 | 147 | void wroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno); |
655daa06 | 148 | |
0655fa4d | 149 | private: |
150 | CBDATA_CLASS(ClientSocketContext); | |
151 | void prepareReply(HttpReply * rep); | |
4ad60609 | 152 | void packChunk(const StoreIOBuffer &bodyData, MemBuf &mb); |
2512d159 | 153 | void packRange(StoreIOBuffer const &, MemBuf * mb); |
0655fa4d | 154 | void deRegisterWithConn(); |
55e44db9 | 155 | void doClose(); |
5f8252d2 | 156 | void initiateClose(const char *reason); |
655daa06 AR |
157 | |
158 | AsyncCall::Pointer cbControlMsgSent; ///< notifies HttpControlMsg Source | |
159 | ||
0655fa4d | 160 | bool mayUseConnection_; /* This request may use the connection. Don't read anymore requests for now */ |
161 | bool connRegistered_; | |
162 | }; | |
163 | ||
a98c2da5 AJ |
164 | |
165 | class ConnectionDetail; | |
061bbdec CT |
166 | #if USE_SSL |
167 | namespace Ssl { | |
fd4624d7 | 168 | class ServerBump; |
061bbdec CT |
169 | } |
170 | #endif | |
27774cee AJ |
171 | /** |
172 | * Manages a connection to a client. | |
173 | * | |
174 | * Multiple requests (up to 2) can be pipelined. This object is responsible for managing | |
175 | * which one is currently being fulfilled and what happens to the queue if the current one | |
176 | * causes the client connection to be closed early. | |
177 | * | |
178 | * Act as a manager for the connection and passes data in buffer to the current parser. | |
179 | * the parser has ambiguous scope at present due to being made from global functions | |
180 | * I believe this object uses the parser to identify boundaries and kick off the | |
181 | * actual HTTP request handling objects (ClientSocketContext, ClientHttpRequest, HttpRequest) | |
182 | * | |
183 | * If the above can be confirmed accurate we can call this object PipelineManager or similar | |
184 | */ | |
655daa06 | 185 | class ConnStateData : public BodyProducer, public HttpControlMsgSink |
6039b729 | 186 | { |
187 | ||
188 | public: | |
6039b729 | 189 | |
190 | ConnStateData(); | |
191 | ~ConnStateData(); | |
192 | ||
193 | void readSomeData(); | |
194 | int getAvailableBufferLength() const; | |
195 | bool areAllContextsForThisConnection() const; | |
196 | void freeAllContexts(); | |
f692498b | 197 | void notifyAllContexts(const int xerrno); ///< tell everybody about the err |
4959e21e | 198 | /// Traffic parsing |
f35961af | 199 | bool clientParseRequests(); |
6039b729 | 200 | void readNextRequest(); |
1368d115 | 201 | bool maybeMakeSpaceAvailable(); |
0655fa4d | 202 | ClientSocketContext::Pointer getCurrentContext() const; |
203 | void addContextToQueue(ClientSocketContext * context); | |
204 | int getConcurrentRequestCount() const; | |
a2ac85d9 | 205 | bool isOpen() const; |
39cb8c41 | 206 | void checkHeaderLimits(); |
6039b729 | 207 | |
655daa06 AR |
208 | // HttpControlMsgSink API |
209 | virtual void sendControlMsg(HttpControlMsg msg); | |
6039b729 | 210 | |
5c336a3b | 211 | // Client TCP connection details from comm layer. |
73c36fd9 | 212 | Comm::ConnectionPointer clientConnection; |
6039b729 | 213 | |
9e008dda | 214 | struct In { |
6039b729 | 215 | In(); |
216 | ~In(); | |
217 | char *addressToReadInto() const; | |
3ff65596 | 218 | |
e1381638 | 219 | ChunkedCodingParser *bodyParser; ///< parses chunked request body |
6039b729 | 220 | char *buf; |
221 | size_t notYetUsed; | |
222 | size_t allocatedSize; | |
0b86805b | 223 | } in; |
6039b729 | 224 | |
39cb8c41 AR |
225 | /** number of body bytes we need to comm_read for the "current" request |
226 | * | |
227 | * \retval 0 We do not need to read any [more] body bytes | |
228 | * \retval negative May need more but do not know how many; could be zero! | |
229 | * \retval positive Need to read exactly that many more body bytes | |
230 | */ | |
231 | int64_t mayNeedToReadMoreBody() const; | |
3b299123 | 232 | |
2f1431ea | 233 | #if USE_AUTH |
63be0a78 | 234 | /** |
a1ce83aa | 235 | * note this is ONLY connection based because NTLM and Negotiate is against HTTP spec. |
3b299123 | 236 | * the user details for connection based authentication |
237 | */ | |
c7baff40 | 238 | Auth::UserRequest::Pointer auth_user_request; |
2f1431ea | 239 | #endif |
63be0a78 | 240 | |
241 | /** | |
3b299123 | 242 | * used by the owner of the connection, opaque otherwise |
243 | * TODO: generalise the connection owner concept. | |
244 | */ | |
245 | ClientSocketContext::Pointer currentobject; | |
6039b729 | 246 | |
b7ac5457 | 247 | Ip::Address log_addr; |
6039b729 | 248 | int nrequests; |
249 | ||
9e008dda | 250 | struct { |
f35961af | 251 | bool readMore; ///< needs comm_read (for this request or new requests) |
6e1d409c | 252 | bool swanSang; // XXX: temporary flag to check proper cleanup |
2fadd50d | 253 | } flags; |
d67acb4e | 254 | struct { |
73c36fd9 | 255 | Comm::ConnectionPointer serverConnection; /* pinned server side connection */ |
d67acb4e AJ |
256 | char *host; /* host name of pinned connection */ |
257 | int port; /* port of pinned connection */ | |
258 | bool pinned; /* this connection was pinned */ | |
259 | bool auth; /* pinned for www authentication */ | |
260 | struct peer *peer; /* peer the connection goes via */ | |
9e008dda AJ |
261 | AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/ |
262 | } pinning; | |
d67acb4e | 263 | |
65d448bc | 264 | AnyP::PortCfg *port; |
6039b729 | 265 | |
266 | bool transparent() const; | |
6039b729 | 267 | bool reading() const; |
f84dd7eb | 268 | void stopReading(); ///< cancels comm_read if it is scheduled |
5f8252d2 | 269 | |
cf6eb29e CT |
270 | /// true if we stopped receiving the request |
271 | const char *stoppedReceiving() const { return stoppedReceiving_; } | |
272 | /// true if we stopped sending the response | |
273 | const char *stoppedSending() const { return stoppedSending_; } | |
274 | /// note request receiving error and close as soon as we write the response | |
275 | void stopReceiving(const char *error); | |
276 | /// note response sending error and close as soon as we read the request | |
277 | void stopSending(const char *error); | |
278 | ||
eb44b2d7 | 279 | void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state |
6039b729 | 280 | |
3e62bd58 | 281 | BodyPipe::Pointer expectRequestBody(int64_t size); |
1cf238db | 282 | virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer); |
283 | virtual void noteBodyConsumerAborted(BodyPipe::Pointer); | |
5f8252d2 | 284 | |
39cb8c41 AR |
285 | bool handleReadData(char *buf, size_t size); |
286 | bool handleRequestBodyData(); | |
0b86805b | 287 | |
d67acb4e AJ |
288 | /** |
289 | * Correlate the current ConnStateData object with the pinning_fd socket descriptor. | |
290 | */ | |
e3a4aecc | 291 | void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, struct peer *peer, bool auth); |
d67acb4e AJ |
292 | /** |
293 | * Decorrelate the ConnStateData object from its pinned peer | |
294 | */ | |
9e008dda | 295 | void unpinConnection(); |
d67acb4e AJ |
296 | /** |
297 | * Checks if there is pinning info if it is valid. It can close the server side connection | |
298 | * if pinned info is not valid. | |
299 | \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest | |
300 | \param peer if it is not NULL also check if the peer is the pinning peer | |
e3a4aecc | 301 | \return The details of the server side connection (may be closed if failures were present). |
d67acb4e | 302 | */ |
e3a4aecc | 303 | const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const struct peer *peer); |
d67acb4e AJ |
304 | /** |
305 | * returts the pinned peer if exists, NULL otherwise | |
306 | */ | |
307 | struct peer *pinnedPeer() const {return pinning.peer;} | |
308 | bool pinnedAuth() const {return pinning.auth;} | |
309 | ||
310 | // pining related comm callbacks | |
311 | void clientPinnedConnectionClosed(const CommCloseCbParams &io); | |
312 | ||
1cf238db | 313 | // comm callbacks |
314 | void clientReadRequest(const CommIoCbParams &io); | |
315 | void connStateClosed(const CommCloseCbParams &io); | |
316 | void requestTimeout(const CommTimeoutCbParams ¶ms); | |
317 | ||
318 | // AsyncJob API | |
319 | virtual bool doneAll() const { return BodyProducer::doneAll() && false;} | |
6e1d409c | 320 | virtual void swanSong(); |
1cf238db | 321 | |
84c77748 AR |
322 | /// Changes state so that we close the connection and quit after serving |
323 | /// the client-side-detected error response instead of getting stuck. | |
324 | void quitAfterError(HttpRequest *request); // meant to be private | |
325 | ||
ae7ff0b8 | 326 | #if USE_SSL |
fd4624d7 | 327 | /// called by FwdState when it is done bumping the server |
d7ce0bcd AR |
328 | void httpsPeeked(Comm::ConnectionPointer serverConnection); |
329 | ||
95d2589c | 330 | /// Start to create dynamic SSL_CTX for host or uses static port SSL context. |
1ce2822d | 331 | void getSslContextStart(); |
95d2589c CT |
332 | /** |
333 | * Done create dynamic ssl certificate. | |
334 | * | |
335 | * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage. | |
336 | */ | |
1ce2822d | 337 | void getSslContextDone(SSL_CTX * sslContext, bool isNew = false); |
95d2589c CT |
338 | /// Callback function. It is called when squid receive message from ssl_crtd. |
339 | static void sslCrtdHandleReplyWrapper(void *data, char *reply); | |
340 | /// Proccess response from ssl_crtd. | |
341 | void sslCrtdHandleReply(const char * reply); | |
342 | ||
caf3666d | 343 | void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode); |
ae7ff0b8 | 344 | bool switchedToHttps() const { return switchedToHttps_; } |
fd4624d7 | 345 | Ssl::ServerBump *serverBump() {return sslServerBump;} |
2bd84e5f | 346 | void setServerBump(Ssl::ServerBump *srvBump) {if (!sslServerBump) sslServerBump = srvBump;} |
fb2178bb CT |
347 | /// Fill the certAdaptParams with the required data for certificate adaptation |
348 | /// and create the key for storing/retrieve the certificate to/from the cache | |
06997a38 | 349 | void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties); |
7a957a93 AR |
350 | /// Called when the client sends the first request on a bumped connection. |
351 | /// Returns false if no [delayed] error should be written to the client. | |
352 | /// Otherwise, writes the error to the client and returns true. Also checks | |
353 | /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests. | |
8eb0a7ee | 354 | bool serveDelayedError(ClientSocketContext *context); |
ae7ff0b8 | 355 | #else |
356 | bool switchedToHttps() const { return false; } | |
357 | #endif | |
358 | ||
39cb8c41 AR |
359 | protected: |
360 | void startDechunkingRequest(); | |
361 | void finishDechunkingRequest(bool withSuccess); | |
362 | void abortChunkedRequestBody(const err_type error); | |
363 | err_type handleChunkedRequestBody(size_t &putSize); | |
3ff65596 | 364 | |
1cf238db | 365 | private: |
366 | int connReadWasError(comm_err_t flag, int size, int xerrno); | |
367 | int connFinishedWithConn(int size); | |
f35961af | 368 | void clientAfterReadingRequests(); |
1cf238db | 369 | |
6039b729 | 370 | private: |
4959e21e | 371 | HttpParser parser_; |
89aec9b6 | 372 | |
4959e21e | 373 | // XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :( |
0b86805b | 374 | CBDATA_CLASS2(ConnStateData); |
1cf238db | 375 | |
d7ce0bcd | 376 | #if USE_SSL |
ae7ff0b8 | 377 | bool switchedToHttps_; |
fb2178bb CT |
378 | /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests |
379 | String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request | |
380 | String sslCommonName; ///< CN name for SSL certificate generation | |
381 | String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate | |
d7ce0bcd | 382 | |
fd4624d7 CT |
383 | /// HTTPS server cert. fetching state for bump-ssl-server-first |
384 | Ssl::ServerBump *sslServerBump; | |
aebe6888 | 385 | Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use |
d7ce0bcd AR |
386 | #endif |
387 | ||
cf6eb29e CT |
388 | /// the reason why we no longer write the response or nil |
389 | const char *stoppedSending_; | |
390 | /// the reason why we no longer read the request or nil | |
391 | const char *stoppedReceiving_; | |
392 | ||
f84dd7eb | 393 | AsyncCall::Pointer reader; ///< set when we are reading |
5f8252d2 | 394 | BodyPipe::Pointer bodyPipe; // set when we are reading request body |
6039b729 | 395 | }; |
396 | ||
55e44db9 | 397 | /* convenience class while splitting up body handling */ |
398 | /* temporary existence only - on stack use expected */ | |
399 | ||
727552f4 | 400 | void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false); |
de31d06f | 401 | |
8596962e | 402 | const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL); |
403 | ||
6039b729 | 404 | #endif /* SQUID_CLIENTSIDE_H */ |