]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
Bug 3247: Domain from URL Stripped when going through peers
[thirdparty/squid.git] / src / tunnel.cc
CommitLineData
95d659f0 1
983061ed 2/*
262a0e14 3 * $Id$
983061ed 4 *
30a4f2a8 5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
26ac0430 24 *
30a4f2a8 25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
26ac0430 29 *
30a4f2a8 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
983061ed 34 */
983061ed 35
30a4f2a8 36#include "squid.h"
aa839030 37#include "errorpage.h"
528b2c61 38#include "HttpRequest.h"
39#include "fde.h"
cfd66529 40#include "Array.h"
9f518b4a 41#include "comm.h"
cfd66529 42#include "comm/Connection.h"
aed188fd 43#include "comm/ConnOpener.h"
ec41b64c 44#include "comm/Write.h"
528b2c61 45#include "client_side_request.h"
c0941a6a 46#include "acl/FilledChecklist.h"
9a0a18de 47#if USE_DELAY_POOLS
b67e2c8c 48#include "DelayId.h"
49#endif
a46d2c0e 50#include "client_side.h"
cfd66529 51#include "MemBuf.h"
e5ee81f0 52#include "http.h"
cfd66529 53#include "PeerSelectState.h"
983061ed 54
fa34dd97 55class TunnelStateData
62e76326 56{
a46d2c0e 57
58public:
59
60 class Connection;
61 void *operator new(size_t);
62 void operator delete (void *);
e0d28505
AJ
63 static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
64 static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
65 static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
66 static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
a46d2c0e 67
68 bool noConnections() const;
983061ed 69 char *url;
190154cf 70 HttpRequest *request;
00ae51e4 71 Comm::ConnectionList serverDestinations;
62e76326 72
fb046c1b
AJ
73 const char * getHost() const {
74 return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->GetHost());
75 };
76
a46d2c0e 77 class Connection
62e76326 78 {
a46d2c0e 79
80 public:
fb046c1b 81 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL) {}
a46d2c0e 82
83 ~Connection();
a46d2c0e 84
a46d2c0e 85 int bytesWanted(int lower=0, int upper = INT_MAX) const;
86 void bytesIn(int const &);
9a0a18de 87#if USE_DELAY_POOLS
a46d2c0e 88
89 void setDelayId(DelayId const &);
90#endif
91
92 void error(int const xerrno);
5c926411 93 int debugLevelForError(int const xerrno) const;
a46d2c0e 94 void closeIfOpen();
95 void dataSent (size_t amount);
62e76326 96 int len;
97 char *buf;
47f6e231 98 int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
62e76326 99
fb046c1b 100 Comm::ConnectionPointer conn; ///< The currently connected connection.
fb046c1b 101
a46d2c0e 102 private:
9a0a18de 103#if USE_DELAY_POOLS
62e76326 104
a46d2c0e 105 DelayId delayId;
59715b38 106#endif
62e76326 107
a46d2c0e 108 };
109
110 Connection client, server;
111 int *status_ptr; /* pointer to status for logging */
112 void copyRead(Connection &from, IOCB *completion);
113
114private:
fa34dd97 115 CBDATA_CLASS(TunnelStateData);
2b663917 116 void copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *);
a46d2c0e 117 void readServer(char *buf, size_t len, comm_err_t errcode, int xerrno);
118 void readClient(char *buf, size_t len, comm_err_t errcode, int xerrno);
119 void writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno);
120 void writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno);
121};
983061ed 122
3c4fcf0f 123static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
983061ed 124
11007d4b 125static CNCB tunnelConnectDone;
126static ERCB tunnelErrorComplete;
127static PF tunnelServerClosed;
128static PF tunnelClientClosed;
8d77a37c 129static CTCB tunnelTimeout;
11007d4b 130static PSC tunnelPeerSelectComplete;
fa34dd97 131static void tunnelStateFree(TunnelStateData * tunnelState);
f01d4b80
AJ
132static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
133static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
30a4f2a8 134
b8d8561b 135static void
11007d4b 136tunnelServerClosed(int fd, void *data)
30a4f2a8 137{
fa34dd97 138 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 139 debugs(26, 3, "tunnelServerClosed: FD " << fd);
fb046c1b 140 tunnelState->server.conn = NULL;
62e76326 141
71a2ced6 142 if (tunnelState->noConnections()) {
11007d4b 143 tunnelStateFree(tunnelState);
26ac0430 144 return;
71a2ced6 145 }
26ac0430 146
71a2ced6 147 if (!tunnelState->server.len) {
fb046c1b 148 tunnelState->client.conn->close();
26ac0430 149 return;
71a2ced6 150 }
30a4f2a8 151}
152
b177367b 153static void
11007d4b 154tunnelClientClosed(int fd, void *data)
30a4f2a8 155{
fa34dd97 156 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 157 debugs(26, 3, "tunnelClientClosed: FD " << fd);
fb046c1b 158 tunnelState->client.conn = NULL;
62e76326 159
71a2ced6 160 if (tunnelState->noConnections()) {
11007d4b 161 tunnelStateFree(tunnelState);
26ac0430 162 return;
71a2ced6 163 }
26ac0430 164
71a2ced6 165 if (!tunnelState->client.len) {
fb046c1b 166 tunnelState->server.conn->close();
26ac0430 167 return;
71a2ced6 168 }
30a4f2a8 169}
983061ed 170
b177367b 171static void
fa34dd97 172tunnelStateFree(TunnelStateData * tunnelState)
983061ed 173{
11007d4b 174 debugs(26, 3, "tunnelStateFree: tunnelState=" << tunnelState);
175 assert(tunnelState != NULL);
176 assert(tunnelState->noConnections());
177 safe_free(tunnelState->url);
00ae51e4 178 tunnelState->serverDestinations.clean();
11007d4b 179 HTTPMSGUNLOCK(tunnelState->request);
180 delete tunnelState;
983061ed 181}
182
fa34dd97 183TunnelStateData::Connection::~Connection()
a46d2c0e 184{
185 safe_free (buf);
186}
187
188int
fa34dd97 189TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
447e176b 190{
9a0a18de 191#if USE_DELAY_POOLS
a46d2c0e 192 return delayId.bytesWanted(lowerbound, upperbound);
193#else
62e76326 194
6b13136a 195 return upperbound;
a46d2c0e 196#endif
197}
62e76326 198
a46d2c0e 199void
fa34dd97 200TunnelStateData::Connection::bytesIn(int const &count)
a46d2c0e 201{
9a0a18de 202#if USE_DELAY_POOLS
a46d2c0e 203 delayId.bytesIn(count);
204#endif
62e76326 205
a46d2c0e 206 len += count;
447e176b 207}
62e76326 208
a46d2c0e 209int
fa34dd97 210TunnelStateData::Connection::debugLevelForError(int const xerrno) const
a46d2c0e 211{
212#ifdef ECONNRESET
213
214 if (xerrno == ECONNRESET)
215 return 2;
216
447e176b 217#endif
218
a46d2c0e 219 if (ignoreErrno(xerrno))
220 return 3;
221
222 return 1;
223}
adb78bd4 224
983061ed 225/* Read from server side and queue it for writing to the client */
a46d2c0e 226void
e0d28505 227TunnelStateData::ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 228{
fa34dd97 229 TunnelStateData *tunnelState = (TunnelStateData *)data;
e0d28505 230 assert(cbdataReferenceValid(tunnelState));
c4b7a5a9 231
11007d4b 232 tunnelState->readServer(buf, len, errcode, xerrno);
a46d2c0e 233}
62e76326 234
a46d2c0e 235void
fa34dd97 236TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 237{
e0d28505 238 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes");
d01053a2 239
a46d2c0e 240 /*
241 * Bail out early on COMM_ERR_CLOSING
26ac0430 242 * - close handlers will tidy up for us
a46d2c0e 243 */
a55f4cea 244
a46d2c0e 245 if (errcode == COMM_ERR_CLOSING)
246 return;
62e76326 247
ee1679df 248 if (len > 0) {
a46d2c0e 249 server.bytesIn(len);
62e76326 250 kb_incr(&statCounter.server.all.kbytes_in, len);
251 kb_incr(&statCounter.server.other.kbytes_in, len);
ee1679df 252 }
62e76326 253
a46d2c0e 254 copy (len, errcode, xerrno, server, client, WriteClientDone);
255}
256
257void
fa34dd97 258TunnelStateData::Connection::error(int const xerrno)
a46d2c0e 259{
260 /* XXX fixme xstrerror and xerrno... */
261 errno = xerrno;
262
e0d28505 263 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror());
62e76326 264
a46d2c0e 265 if (!ignoreErrno(xerrno))
fb046c1b 266 conn->close();
983061ed 267}
268
269/* Read from client side and queue it for writing to the server */
a46d2c0e 270void
e0d28505 271TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 272{
fa34dd97 273 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 274 assert (cbdataReferenceValid (tunnelState));
62e76326 275
11007d4b 276 tunnelState->readClient(buf, len, errcode, xerrno);
a46d2c0e 277}
62e76326 278
a46d2c0e 279void
fa34dd97 280TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 281{
d01053a2
AJ
282 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes");
283
a46d2c0e 284 /*
285 * Bail out early on COMM_ERR_CLOSING
26ac0430 286 * - close handlers will tidy up for us
a46d2c0e 287 */
a55f4cea 288
a46d2c0e 289 if (errcode == COMM_ERR_CLOSING)
290 return;
a55f4cea 291
a46d2c0e 292 if (len > 0) {
293 client.bytesIn(len);
294 kb_incr(&statCounter.client_http.kbytes_in, len);
295 }
62e76326 296
a46d2c0e 297 copy (len, errcode, xerrno, client, server, WriteServerDone);
298}
62e76326 299
a46d2c0e 300void
fa34dd97 301TunnelStateData::copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *completion)
a46d2c0e 302{
303 /* I think this is to prevent free-while-in-a-callback behaviour
26ac0430 304 * - RBC 20030229
fb046c1b 305 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
a46d2c0e 306 */
307 cbdataInternalLock(this); /* ??? should be locked by the caller... */
62e76326 308
60dafd5e 309 /* Bump the source connection read timeout on any activity */
8d77a37c
AJ
310 if (Comm::IsConnOpen(from.conn)) {
311 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 312 CommTimeoutCbPtrFun(tunnelTimeout, this));
8d77a37c
AJ
313 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
314 }
99c02c10 315
58c0b17d 316 if (errcode)
a46d2c0e 317 from.error (xerrno);
60dafd5e 318 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
fb046c1b 319 from.conn->close();
62e76326 320
60dafd5e 321 /* Only close the remote end if we've finished queueing data to it */
97c81191 322 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
fb046c1b 323 to.conn->close();
c4b7a5a9 324 }
ec41b64c
AJ
325 } else if (cbdataReferenceValid(this)) {
326 AsyncCall::Pointer call = commCbCall(5,5, "SomeTunnelWriteHandler",
f31be4b0 327 CommIoCbPtrFun(completion, this));
b0388924 328 Comm::Write(to.conn, from.buf, len, call, NULL);
ec41b64c 329 }
a55f4cea 330
a46d2c0e 331 cbdataInternalUnlock(this); /* ??? */
983061ed 332}
333
334/* Writes data from the client buffer to the server side */
a46d2c0e 335void
e0d28505 336TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 337{
fa34dd97 338 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 339 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 340
11007d4b 341 tunnelState->writeServerDone(buf, len, flag, xerrno);
a46d2c0e 342}
a55f4cea 343
a46d2c0e 344void
fa34dd97 345TunnelStateData::writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 346{
d01053a2 347 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written");
62e76326 348
5dacdf3f 349 /* Error? */
58c0b17d
AJ
350 if (flag != COMM_OK) {
351 if (flag != COMM_ERR_CLOSING)
352 server.error(xerrno); // may call comm_close
5dacdf3f 353 return;
c4b7a5a9 354 }
62e76326 355
5dacdf3f 356 /* EOF? */
a46d2c0e 357 if (len == 0) {
fb046c1b 358 server.conn->close();
a46d2c0e 359 return;
360 }
62e76326 361
5dacdf3f 362 /* Valid data */
363 kb_incr(&statCounter.server.all.kbytes_out, len);
364 kb_incr(&statCounter.server.other.kbytes_out, len);
365 client.dataSent(len);
366
a46d2c0e 367 /* If the other end has closed, so should we */
97c81191 368 if (!Comm::IsConnOpen(client.conn)) {
fb046c1b 369 server.conn->close();
a55f4cea 370 return;
c4b7a5a9 371 }
62e76326 372
a46d2c0e 373 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a46d2c0e 374
5dacdf3f 375 if (cbdataReferenceValid(this))
a46d2c0e 376 copyRead(client, ReadClient);
377
378 cbdataInternalUnlock(this); /* ??? */
983061ed 379}
380
381/* Writes data from the server buffer to the client side */
a46d2c0e 382void
e0d28505 383TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 384{
fa34dd97 385 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 386 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 387
11007d4b 388 tunnelState->writeClientDone(buf, len, flag, xerrno);
a46d2c0e 389}
390
391void
e0d28505 392TunnelStateData::Connection::dataSent(size_t amount)
a46d2c0e 393{
394 assert(amount == (size_t)len);
395 len =0;
396 /* increment total object size */
397
398 if (size_ptr)
399 *size_ptr += amount;
400}
401
402void
fa34dd97 403TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 404{
d01053a2 405 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written");
62e76326 406
5dacdf3f 407 /* Error? */
58c0b17d
AJ
408 if (flag != COMM_OK) {
409 if (flag != COMM_ERR_CLOSING)
410 client.error(xerrno); // may call comm_close
5dacdf3f 411 return;
c4b7a5a9 412 }
62e76326 413
5dacdf3f 414 /* EOF? */
a46d2c0e 415 if (len == 0) {
fb046c1b 416 client.conn->close();
62e76326 417 return;
983061ed 418 }
62e76326 419
5dacdf3f 420 /* Valid data */
421 kb_incr(&statCounter.client_http.kbytes_out, len);
422 server.dataSent(len);
423
a46d2c0e 424 /* If the other end has closed, so should we */
97c81191 425 if (!Comm::IsConnOpen(server.conn)) {
fb046c1b 426 client.conn->close();
a55f4cea 427 return;
983061ed 428 }
62e76326 429
a46d2c0e 430 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a55f4cea 431
5dacdf3f 432 if (cbdataReferenceValid(this))
a46d2c0e 433 copyRead(server, ReadServer);
2c202d66 434
a46d2c0e 435 cbdataInternalUnlock(this); /* ??? */
983061ed 436}
437
b8d8561b 438static void
8d77a37c 439tunnelTimeout(const CommTimeoutCbParams &io)
983061ed 440{
8d77a37c
AJ
441 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
442 debugs(26, 3, HERE << io.conn);
11007d4b 443 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
444 cbdataInternalLock(tunnelState);
a55f4cea 445
11007d4b 446 tunnelState->client.closeIfOpen();
447 tunnelState->server.closeIfOpen();
448 cbdataInternalUnlock(tunnelState);
a46d2c0e 449}
62e76326 450
a46d2c0e 451void
fa34dd97 452TunnelStateData::Connection::closeIfOpen()
a46d2c0e 453{
97c81191 454 if (Comm::IsConnOpen(conn))
fb046c1b 455 conn->close();
a46d2c0e 456}
457
458void
fa34dd97 459TunnelStateData::copyRead(Connection &from, IOCB *completion)
a46d2c0e 460{
461 assert(from.len == 0);
abd8f140
AJ
462 AsyncCall::Pointer call = commCbCall(5,4, "SomeTunnelReadHandler",
463 CommIoCbPtrFun(completion, this));
464 comm_read(from.conn, from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), call);
983061ed 465}
466
b0388924
AJ
467/**
468 * All the pieces we need to write to client and/or server connection
1b76e6c1
AJ
469 * have been written.
470 * - Set the HTTP status for this request.
471 * - Start the blind pump.
b0388924 472 */
c4b7a5a9 473static void
e0d28505 474tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 475{
fa34dd97 476 TunnelStateData *tunnelState = (TunnelStateData *)data;
62e76326 477
478 if (flag != COMM_OK) {
1b76e6c1 479 *tunnelState->status_ptr = HTTP_INTERNAL_SERVER_ERROR;
e0d28505 480 tunnelErrorComplete(conn->fd, data, 0);
62e76326 481 return;
482 }
483
1b76e6c1 484 *tunnelState->status_ptr = HTTP_OK;
11007d4b 485 if (cbdataReferenceValid(tunnelState)) {
fa34dd97 486 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
487 tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
62e76326 488 }
c4b7a5a9 489}
490
c4b7a5a9 491/*
1b76e6c1 492 * handle the write completion from a proxy request to an upstream origin
c4b7a5a9 493 */
b8d8561b 494static void
f01d4b80 495tunnelConnected(const Comm::ConnectionPointer &server, void *data)
983061ed 496{
fa34dd97 497 TunnelStateData *tunnelState = (TunnelStateData *)data;
f01d4b80 498 debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
ec41b64c
AJ
499 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
500 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
b0388924 501 Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
983061ed 502}
503
b8d8561b 504static void
e0d28505 505tunnelErrorComplete(int /*const Comm::ConnectionPointer &*/, void *data, size_t)
30a4f2a8 506{
fa34dd97 507 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 508 assert(tunnelState != NULL);
509 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
510 cbdataInternalLock(tunnelState);
62e76326 511
97c81191 512 if (Comm::IsConnOpen(tunnelState->client.conn))
fb046c1b 513 tunnelState->client.conn->close();
62e76326 514
97c81191 515 if (Comm::IsConnOpen(tunnelState->server.conn))
fb046c1b 516 tunnelState->server.conn->close();
380963c2 517
11007d4b 518 cbdataInternalUnlock(tunnelState);
30a4f2a8 519}
520
983061ed 521
b8d8561b 522static void
f01d4b80 523tunnelConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
983061ed 524{
fa34dd97 525 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 526 HttpRequest *request = tunnelState->request;
9b312a19 527 ErrorState *err = NULL;
62e76326 528
a8b7ec30 529#if USE_DELAY_POOLS
cfd66529 530 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
739b352a 531 if (conn->getPeer() && conn->getPeer()->options.no_delay)
cfd66529
AJ
532 tunnelState->server.setDelayId(DelayId());
533#endif
3ff65596 534
739b352a 535 if (conn != NULL && conn->getPeer())
5229395c 536 hierarchyNote(&tunnelState->request->hier, conn->peerType, conn->getPeer()->host);
890b0fa8 537 else if (Config.onoff.log_ip_on_direct)
5229395c 538 hierarchyNote(&tunnelState->request->hier, conn->peerType, fd_table[conn->fd].ipaddr);
890b0fa8 539 else
fb046c1b 540 hierarchyNote(&tunnelState->request->hier, conn->peerType, tunnelState->getHost());
cfd66529
AJ
541
542 if (status != COMM_OK) {
aed188fd
AJ
543 /* At this point only the TCP handshake has failed. no data has been passed.
544 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
545 */
00ae51e4
AJ
546 tunnelState->serverDestinations.shift();
547 if (status != COMM_TIMEOUT && tunnelState->serverDestinations.size() > 0) {
aed188fd
AJ
548 /* Try another IP of this destination host */
549 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
00ae51e4 550 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
aed188fd 551 cs->setHost(tunnelState->url);
855150a4 552 AsyncJob::Start(cs);
aed188fd
AJ
553 } else {
554 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
555 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
556 err->xerrno = xerrno;
557 // on timeout is this still: err->xerrno = ETIMEDOUT;
558 err->port = conn->remote.GetPort();
559 err->callback = tunnelErrorComplete;
560 err->callback_data = tunnelState;
e0d28505 561 errorSend(tunnelState->client.conn, err);
aed188fd 562 }
cfd66529
AJ
563 return;
564 }
565
fb046c1b 566 tunnelState->server.conn = conn;
739b352a 567 request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
fb046c1b 568 comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
cfd66529 569
739b352a
AJ
570 if (conn->getPeer()) {
571 tunnelState->request->peer_login = conn->getPeer()->login;
1b76e6c1 572 tunnelState->request->flags.proxying = (conn->getPeer()->options.originserver?0:1);
fe40a877 573 } else {
cfd66529
AJ
574 tunnelState->request->peer_login = NULL;
575 tunnelState->request->flags.proxying = 0;
576 }
62e76326 577
1b76e6c1 578 if (tunnelState->request->flags.proxying)
fb046c1b 579 tunnelRelayConnectRequest(conn, tunnelState);
cfd66529 580 else {
fb046c1b 581 tunnelConnected(conn, tunnelState);
983061ed 582 }
cfd66529 583
8d77a37c 584 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 585 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
8d77a37c 586 commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
983061ed 587}
30a4f2a8 588
425de4c8
AJ
589extern tos_t GetTosToServer(HttpRequest * request);
590extern nfmark_t GetNfmarkToServer(HttpRequest * request);
591
770f051d 592void
47f6e231 593tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
30a4f2a8 594{
595 /* Create state structure. */
fa34dd97 596 TunnelStateData *tunnelState = NULL;
9b312a19 597 ErrorState *err = NULL;
f1003989 598 int answer;
190154cf 599 HttpRequest *request = http->request;
d5964d58 600 char *url = http->uri;
fb046c1b 601
f1003989 602 /*
cc192b50 603 * client_addr.IsNoAddr() indicates this is an "internal" request
a4b8110e 604 * from peer_digest.c, asn.c, netdb.c, etc and should always
605 * be allowed. yuck, I know.
606 */
62e76326 607
b50e327b 608 if (!request->client_addr.IsNoAddr() && Config.accessList.miss) {
62e76326 609 /*
610 * Check if this host is allowed to fetch MISSES from us (miss_access)
b50e327b 611 * default is to allow.
62e76326 612 */
c0941a6a 613 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
62e76326 614 ch.src_addr = request->client_addr;
615 ch.my_addr = request->my_addr;
b448c119 616 answer = ch.fastCheck();
62e76326 617
618 if (answer == 0) {
2cc81f1f 619 err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN, request);
62e76326 620 *status_ptr = HTTP_FORBIDDEN;
73c36fd9 621 errorSend(http->getConn()->clientConnection, err);
62e76326 622 return;
623 }
f1003989 624 }
62e76326 625
60745f24 626 debugs(26, 3, "tunnelStart: '" << RequestMethodStr(request->method) << " " << url << "'");
83704487 627 statCounter.server.all.requests++;
628 statCounter.server.other.requests++;
62e76326 629
fa34dd97 630 tunnelState = new TunnelStateData;
9a0a18de 631#if USE_DELAY_POOLS
11007d4b 632 tunnelState->server.setDelayId(DelayId::DelayClient(http));
59715b38 633#endif
11007d4b 634 tunnelState->url = xstrdup(url);
635 tunnelState->request = HTTPMSGLOCK(request);
636 tunnelState->server.size_ptr = size_ptr;
637 tunnelState->status_ptr = status_ptr;
73c36fd9 638 tunnelState->client.conn = http->getConn()->clientConnection;
fb046c1b
AJ
639
640 comm_add_close_handler(tunnelState->client.conn->fd,
11007d4b 641 tunnelClientClosed,
642 tunnelState);
8d77a37c
AJ
643
644 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 645 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
8d77a37c 646 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
cfd66529 647
00ae51e4 648 peerSelect(&(tunnelState->serverDestinations), request,
62e76326 649 NULL,
11007d4b 650 tunnelPeerSelectComplete,
651 tunnelState);
30a4f2a8 652}
98ffb7e4 653
b8d8561b 654static void
b0388924 655tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
98ffb7e4 656{
fa34dd97 657 TunnelStateData *tunnelState = (TunnelStateData *)data;
75faaa7a 658 HttpHeader hdr_out(hoRequest);
e1e72f06 659 Packer p;
b4b5fd95 660 http_state_flags flags;
b0388924 661 debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
b4b5fd95 662 memset(&flags, '\0', sizeof(flags));
11007d4b 663 flags.proxying = tunnelState->request->flags.proxying;
032785bf 664 MemBuf mb;
2fe7eff9 665 mb.init();
3872be7c 666 mb.Printf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
11007d4b 667 HttpStateData::httpBuildRequestHeader(tunnelState->request,
668 tunnelState->request,
e5ee81f0 669 NULL, /* StoreEntry */
670 &hdr_out,
671 flags); /* flags */
e1e72f06 672 packerToMemInit(&p, &mb);
a9925b40 673 hdr_out.packInto(&p);
519e0948 674 hdr_out.clean();
e1e72f06 675 packerClean(&p);
2fe7eff9 676 mb.append("\r\n", 2);
c4b7a5a9 677
8d77a37c 678 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone",
dc49061a 679 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
8d77a37c
AJ
680 Comm::Write(srv, &mb, writeCall);
681
682 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 683 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
8d77a37c 684 commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
98ffb7e4 685}
33ea9fff 686
33ea9fff 687static void
00ae51e4 688tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, void *data)
33ea9fff 689{
fa34dd97 690 TunnelStateData *tunnelState = (TunnelStateData *)data;
62e76326 691
cfd66529 692 if (peer_paths == NULL || peer_paths->size() < 1) {
62e76326 693 ErrorState *err;
855150a4 694 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
11007d4b 695 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
696 err->callback = tunnelErrorComplete;
697 err->callback_data = tunnelState;
e0d28505 698 errorSend(tunnelState->client.conn, err);
62e76326 699 return;
db1cd23c 700 }
62e76326 701
cfd66529 702 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
00ae51e4 703 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
aed188fd 704 cs->setHost(tunnelState->url);
855150a4 705 AsyncJob::Start(cs);
33ea9fff 706}
a46d2c0e 707
fa34dd97 708CBDATA_CLASS_INIT(TunnelStateData);
a46d2c0e 709
710void *
fa34dd97 711TunnelStateData::operator new (size_t)
a46d2c0e 712{
fa34dd97 713 CBDATA_INIT_TYPE(TunnelStateData);
714 TunnelStateData *result = cbdataAlloc(TunnelStateData);
a46d2c0e 715 return result;
716}
717
718void
fa34dd97 719TunnelStateData::operator delete (void *address)
a46d2c0e 720{
fa34dd97 721 TunnelStateData *t = static_cast<TunnelStateData *>(address);
a46d2c0e 722 cbdataFree(t);
723}
724
a46d2c0e 725bool
fa34dd97 726TunnelStateData::noConnections() const
a46d2c0e 727{
97c81191 728 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
a46d2c0e 729}
730
9a0a18de 731#if USE_DELAY_POOLS
a46d2c0e 732void
fa34dd97 733TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
a46d2c0e 734{
735 delayId = newDelay;
736}
737
738#endif