blob: 339c5fb72b3e15bf9a35b718e63ab7b603e2789c [file] [log] [blame]
Paul Stewart58a577b2012-01-10 11:18:52 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartf65320c2011-10-13 14:34:52 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/http_proxy.h"
6
7#include <errno.h>
8#include <netinet/in.h>
9#include <linux/if.h> // Needs definitions from netinet/in.h
10#include <stdio.h>
11#include <time.h>
12
13#include <string>
14#include <vector>
15
Eric Shienbrood3e20a232012-02-16 11:35:56 -050016#include <base/bind.h>
Paul Stewartf65320c2011-10-13 14:34:52 -070017#include <base/string_number_conversions.h>
18#include <base/string_split.h>
19#include <base/string_util.h>
20#include <base/stringprintf.h>
21
22#include "shill/async_connection.h"
Paul Stewartc8f4bef2011-12-13 09:45:51 -080023#include "shill/connection.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070024#include "shill/dns_client.h"
25#include "shill/event_dispatcher.h"
26#include "shill/ip_address.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070027#include "shill/logging.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070028#include "shill/sockets.h"
29
Eric Shienbrood3e20a232012-02-16 11:35:56 -050030using base::Bind;
Paul Stewartf65320c2011-10-13 14:34:52 -070031using base::StringPrintf;
32using std::string;
33using std::vector;
34
35namespace shill {
36
37const int HTTPProxy::kClientHeaderTimeoutSeconds = 1;
38const int HTTPProxy::kConnectTimeoutSeconds = 10;
39const int HTTPProxy::kDNSTimeoutSeconds = 5;
40const int HTTPProxy::kDefaultServerPort = 80;
41const int HTTPProxy::kInputTimeoutSeconds = 30;
42const size_t HTTPProxy::kMaxClientQueue = 10;
43const size_t HTTPProxy::kMaxHeaderCount = 128;
44const size_t HTTPProxy::kMaxHeaderSize = 2048;
45const int HTTPProxy::kTransactionTimeoutSeconds = 600;
46
Paul Stewart58a577b2012-01-10 11:18:52 -080047const char HTTPProxy::kHTTPMethodConnect[] = "connect";
48const char HTTPProxy::kHTTPMethodTerminator[] = " ";
Paul Stewartf65320c2011-10-13 14:34:52 -070049const char HTTPProxy::kHTTPURLDelimiters[] = " /#?";
50const char HTTPProxy::kHTTPURLPrefix[] = "http://";
51const char HTTPProxy::kHTTPVersionPrefix[] = " HTTP/1";
52const char HTTPProxy::kInternalErrorMsg[] = "Proxy Failed: Internal Error";
53
Paul Stewartc8f4bef2011-12-13 09:45:51 -080054HTTPProxy::HTTPProxy(ConnectionRefPtr connection)
Paul Stewartf65320c2011-10-13 14:34:52 -070055 : state_(kStateIdle),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080056 connection_(connection),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050057 weak_ptr_factory_(this),
Eric Shienbrood9a245532012-03-07 14:20:39 -050058 accept_callback_(Bind(&HTTPProxy::AcceptClient,
59 weak_ptr_factory_.GetWeakPtr())),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050060 connect_completion_callback_(Bind(&HTTPProxy::OnConnectCompletion,
Eric Shienbrood9a245532012-03-07 14:20:39 -050061 weak_ptr_factory_.GetWeakPtr())),
62 dns_client_callback_(Bind(&HTTPProxy::GetDNSResult,
63 weak_ptr_factory_.GetWeakPtr())),
64 read_client_callback_(Bind(&HTTPProxy::ReadFromClient,
65 weak_ptr_factory_.GetWeakPtr())),
66 read_server_callback_(Bind(&HTTPProxy::ReadFromServer,
67 weak_ptr_factory_.GetWeakPtr())),
68 write_client_callback_(Bind(&HTTPProxy::WriteToClient,
69 weak_ptr_factory_.GetWeakPtr())),
70 write_server_callback_(Bind(&HTTPProxy::WriteToServer,
71 weak_ptr_factory_.GetWeakPtr())),
Paul Stewartf65320c2011-10-13 14:34:52 -070072 dispatcher_(NULL),
73 dns_client_(NULL),
74 proxy_port_(-1),
75 proxy_socket_(-1),
76 server_async_connection_(NULL),
77 sockets_(NULL),
78 client_socket_(-1),
79 server_port_(kDefaultServerPort),
80 server_socket_(-1),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050081 is_route_requested_(false) { }
Paul Stewartf65320c2011-10-13 14:34:52 -070082
83HTTPProxy::~HTTPProxy() {
84 Stop();
85}
86
87bool HTTPProxy::Start(EventDispatcher *dispatcher,
88 Sockets *sockets) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070089 SLOG(HTTPProxy, 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -070090
91 if (sockets_) {
92 // We are already running.
93 return true;
94 }
95
96 proxy_socket_ = sockets->Socket(PF_INET, SOCK_STREAM, 0);
97 if (proxy_socket_ < 0) {
98 PLOG(ERROR) << "Failed to open proxy socket";
99 return false;
100 }
101
102 struct sockaddr_in addr;
103 socklen_t addrlen = sizeof(addr);
104 memset(&addr, 0, sizeof(addr));
105 addr.sin_family = AF_INET;
106 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
107 if (sockets->Bind(proxy_socket_,
108 reinterpret_cast<struct sockaddr *>(&addr),
109 sizeof(addr)) < 0 ||
110 sockets->GetSockName(proxy_socket_,
111 reinterpret_cast<struct sockaddr *>(&addr),
112 &addrlen) < 0 ||
113 sockets->SetNonBlocking(proxy_socket_) < 0 ||
114 sockets->Listen(proxy_socket_, kMaxClientQueue) < 0) {
115 sockets->Close(proxy_socket_);
116 proxy_socket_ = -1;
117 PLOG(ERROR) << "HTTPProxy socket setup failed";
118 return false;
119 }
120
121 accept_handler_.reset(
122 dispatcher->CreateReadyHandler(proxy_socket_, IOHandler::kModeInput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500123 accept_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700124 dispatcher_ = dispatcher;
125 dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800126 connection_->interface_name(),
127 connection_->dns_servers(),
Paul Stewartf65320c2011-10-13 14:34:52 -0700128 kDNSTimeoutSeconds * 1000,
129 dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500130 dns_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700131 proxy_port_ = ntohs(addr.sin_port);
132 server_async_connection_.reset(
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800133 new AsyncConnection(connection_->interface_name(), dispatcher, sockets,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500134 connect_completion_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700135 sockets_ = sockets;
136 state_ = kStateWaitConnection;
137 return true;
138}
139
140void HTTPProxy::Stop() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700141 SLOG(HTTPProxy, 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700142
143 if (!sockets_ ) {
144 return;
145 }
146
147 StopClient();
148
149 accept_handler_.reset();
150 dispatcher_ = NULL;
151 dns_client_.reset();
152 proxy_port_ = -1;
153 server_async_connection_.reset();
154 sockets_->Close(proxy_socket_);
155 proxy_socket_ = -1;
156 sockets_ = NULL;
157 state_ = kStateIdle;
158}
159
160// IOReadyHandler callback routine fired when a client connects to the
161// proxy's socket. We Accept() the client and start reading a request
162// from it.
163void HTTPProxy::AcceptClient(int fd) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700164 SLOG(HTTPProxy, 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700165
166 int client_fd = sockets_->Accept(fd, NULL, NULL);
167 if (client_fd < 0) {
168 PLOG(ERROR) << "Client accept failed";
169 return;
170 }
171
172 accept_handler_->Stop();
173
174 client_socket_ = client_fd;
175
176 sockets_->SetNonBlocking(client_socket_);
177 read_client_handler_.reset(
178 dispatcher_->CreateInputHandler(client_socket_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500179 read_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700180 // Overall transaction timeout.
Paul Stewartf582b502012-04-04 21:39:22 -0700181 transaction_timeout_.Reset(Bind(&HTTPProxy::StopClient,
182 weak_ptr_factory_.GetWeakPtr()));
183 dispatcher_->PostDelayedTask(transaction_timeout_.callback(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500184 kTransactionTimeoutSeconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700185
186 state_ = kStateReadClientHeader;
187 StartIdleTimeout();
188}
189
190bool HTTPProxy::ConnectServer(const IPAddress &address, int port) {
191 state_ = kStateConnectServer;
192 if (!server_async_connection_->Start(address, port)) {
193 SendClientError(500, "Could not create socket to connect to server");
194 return false;
195 }
196 StartIdleTimeout();
197 return true;
198}
199
200// DNSClient callback that fires when the DNS request completes.
Paul Stewartbdb02e62012-02-22 16:24:33 -0800201void HTTPProxy::GetDNSResult(const Error &error, const IPAddress &address) {
202 if (!error.IsSuccess()) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700203 SendClientError(502, string("Could not resolve hostname: ") +
Paul Stewartbdb02e62012-02-22 16:24:33 -0800204 error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700205 return;
206 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800207 ConnectServer(address, server_port_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700208}
209
210// IOReadyHandler callback routine which fires when the asynchronous Connect()
211// to the remote server completes (or fails).
212void HTTPProxy::OnConnectCompletion(bool success, int fd) {
213 if (!success) {
214 SendClientError(500, string("Socket connection delayed failure: ") +
215 server_async_connection_->error());
216 return;
217 }
218 server_socket_ = fd;
219 state_ = kStateTunnelData;
Paul Stewart58a577b2012-01-10 11:18:52 -0800220
221 // If this was a "CONNECT" request, notify the client that the connection
222 // has been established by sending an "OK" response.
223 if (LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
224 SetClientResponse(200, "OK", "", "");
225 StartReceive();
226 }
227
Paul Stewartf65320c2011-10-13 14:34:52 -0700228 StartTransmit();
229}
230
231// Read through the header lines from the client, modifying or adding
232// lines as necessary. Perform final determination of the hostname/port
233// we should connect to and either start a DNS request or connect to a
234// numeric address.
235bool HTTPProxy::ParseClientRequest() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700236 SLOG(HTTPProxy, 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700237
238 string host;
239 bool found_via = false;
240 bool found_connection = false;
241 for (vector<string>::iterator it = client_headers_.begin();
242 it != client_headers_.end(); ++it) {
243 if (StartsWithASCII(*it, "Host:", false)) {
244 host = it->substr(5);
245 } else if (StartsWithASCII(*it, "Via:", false)) {
246 found_via = true;
247 (*it).append(StringPrintf(", %s shill-proxy", client_version_.c_str()));
248 } else if (StartsWithASCII(*it, "Connection:", false)) {
249 found_connection = true;
250 (*it).assign("Connection: close");
251 } else if (StartsWithASCII(*it, "Proxy-Connection:", false)) {
252 (*it).assign("Proxy-Connection: close");
253 }
254 }
255
256 if (!found_connection) {
257 client_headers_.push_back("Connection: close");
258 }
259 if (!found_via) {
260 client_headers_.push_back(
261 StringPrintf("Via: %s shill-proxy", client_version_.c_str()));
262 }
263
264 // Assemble the request as it will be sent to the server.
265 client_data_.Clear();
Paul Stewart58a577b2012-01-10 11:18:52 -0800266 if (!LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
267 for (vector<string>::iterator it = client_headers_.begin();
268 it != client_headers_.end(); ++it) {
269 client_data_.Append(ByteString(*it + "\r\n", false));
270 }
271 client_data_.Append(ByteString(string("\r\n"), false));
Paul Stewartf65320c2011-10-13 14:34:52 -0700272 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700273
274 TrimWhitespaceASCII(host, TRIM_ALL, &host);
275 if (host.empty()) {
276 // Revert to using the hostname in the URL if no "Host:" header exists.
277 host = server_hostname_;
278 }
279
280 if (host.empty()) {
281 SendClientError(400, "I don't know what host you want me to connect to");
282 return false;
283 }
284
285 server_port_ = 80;
286 vector<string> host_parts;
287 base::SplitString(host, ':', &host_parts);
288
289 if (host_parts.size() > 2) {
290 SendClientError(400, "Too many colons in hostname");
291 return false;
292 } else if (host_parts.size() == 2) {
293 server_hostname_ = host_parts[0];
294 if (!base::StringToInt(host_parts[1], &server_port_)) {
295 SendClientError(400, "Could not parse port number");
296 return false;
297 }
298 } else {
299 server_hostname_ = host;
300 }
301
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800302 connection_->RequestRouting();
303 is_route_requested_ = true;
304
Paul Stewartf65320c2011-10-13 14:34:52 -0700305 IPAddress addr(IPAddress::kFamilyIPv4);
306 if (addr.SetAddressFromString(server_hostname_)) {
307 if (!ConnectServer(addr, server_port_)) {
308 return false;
309 }
310 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700311 SLOG(HTTPProxy, 3) << "Looking up host: " << server_hostname_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800312 Error error;
313 if (!dns_client_->Start(server_hostname_, &error)) {
314 SendClientError(502, "Could not resolve hostname: " + error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700315 return false;
316 }
317 state_ = kStateLookupServer;
318 }
319 return true;
320}
321
322// Accept a new line into the client headers. Returns false if a parse
323// error occurs.
324bool HTTPProxy::ProcessLastHeaderLine() {
325 string *header = &client_headers_.back();
326 TrimString(*header, "\r", header);
327
328 if (header->empty()) {
329 // Empty line terminates client headers.
330 client_headers_.pop_back();
331 if (!ParseClientRequest()) {
332 return false;
333 }
334 }
335
336 // Is this is the first header line?
337 if (client_headers_.size() == 1) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800338 if (!ReadClientHTTPMethod(header) ||
339 !ReadClientHTTPVersion(header) ||
340 !ReadClientHostname(header)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700341 return false;
342 }
343 }
344
345 if (client_headers_.size() >= kMaxHeaderCount) {
346 SendClientError(500, kInternalErrorMsg);
347 return false;
348 }
349
350 return true;
351}
352
353// Split input from client into header lines, and consume parsed lines
354// from InputData. The passed in |data| is modified to indicate the
355// characters consumed.
356bool HTTPProxy::ReadClientHeaders(InputData *data) {
357 unsigned char *ptr = data->buf;
358 unsigned char *end = ptr + data->len;
359
360 if (client_headers_.empty()) {
361 client_headers_.push_back(string());
362 }
363
364 for (; ptr < end && state_ == kStateReadClientHeader; ++ptr) {
365 if (*ptr == '\n') {
366 if (!ProcessLastHeaderLine()) {
367 return false;
368 }
369
370 // Start a new line. New chararacters we receive will be appended there.
371 client_headers_.push_back(string());
372 continue;
373 }
374
375 string *header = &client_headers_.back();
376 // Is the first character of the header line a space or tab character?
377 if (header->empty() && (*ptr == ' ' || *ptr == '\t') &&
378 client_headers_.size() > 1) {
379 // Line Continuation: Add this character to the previous header line.
380 // This way, all of the data (including newlines and line continuation
381 // characters) related to a specific header will be contained within
382 // a single element of |client_headers_|, and manipulation of headers
383 // such as appending will be simpler. This is accomplished by removing
384 // the empty line we started, and instead appending the whitespace
385 // and following characters to the previous line.
386 client_headers_.pop_back();
387 header = &client_headers_.back();
388 header->append("\r\n");
389 }
390
391 if (header->length() >= kMaxHeaderSize) {
392 SendClientError(500, kInternalErrorMsg);
393 return false;
394 }
395 header->push_back(*ptr);
396 }
397
398 // Return the remaining data to the caller -- this could be POST data
399 // or other non-header data sent with the client request.
400 data->buf = ptr;
401 data->len = end - ptr;
402
403 return true;
404}
405
406// Finds the URL in the first line of an HTTP client header, and extracts
407// and removes the hostname (and port) from the URL. Returns false if a
408// parse error occurs, and true otherwise (whether or not the hostname was
409// found).
410bool HTTPProxy::ReadClientHostname(string *header) {
411 const string http_url_prefix(kHTTPURLPrefix);
412 size_t url_idx = header->find(http_url_prefix);
413 if (url_idx != string::npos) {
414 size_t host_start = url_idx + http_url_prefix.length();
415 size_t host_end =
416 header->find_first_of(kHTTPURLDelimiters, host_start);
417 if (host_end != string::npos) {
418 server_hostname_ = header->substr(host_start,
419 host_end - host_start);
420 // Modify the URL passed upstream to remove "http://<hostname>".
421 header->erase(url_idx, host_end - url_idx);
422 if ((*header)[url_idx] != '/') {
423 header->insert(url_idx, "/");
424 }
425 } else {
426 LOG(ERROR) << "Could not find end of hostname in request. Line was: "
427 << *header;
428 SendClientError(500, kInternalErrorMsg);
429 return false;
430 }
431 }
432 return true;
433}
434
Paul Stewart58a577b2012-01-10 11:18:52 -0800435bool HTTPProxy::ReadClientHTTPMethod(string *header) {
436 size_t method_end = header->find(kHTTPMethodTerminator);
437 if (method_end == string::npos || method_end == 0) {
438 LOG(ERROR) << "Could not parse HTTP method. Line was: " << *header;
439 SendClientError(501, "Server could not parse HTTP method");
440 return false;
441 }
442 client_method_ = header->substr(0, method_end);
443 return true;
444}
445
Paul Stewartf65320c2011-10-13 14:34:52 -0700446// Extract the HTTP version number from the first line of the client headers.
447// Returns true if found.
448bool HTTPProxy::ReadClientHTTPVersion(string *header) {
449 const string http_version_prefix(kHTTPVersionPrefix);
450 size_t http_ver_pos = header->find(http_version_prefix);
451 if (http_ver_pos != string::npos) {
452 client_version_ =
453 header->substr(http_ver_pos + http_version_prefix.length() - 1);
454 } else {
455 SendClientError(501, "Server only accepts HTTP/1.x requests");
456 return false;
457 }
458 return true;
459}
460
461// IOInputHandler callback that fires when data is read from the client.
462// This could be header data, or perhaps POST data that follows the headers.
463void HTTPProxy::ReadFromClient(InputData *data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700464 SLOG(HTTPProxy, 3) << "In " << __func__ << " length " << data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700465
466 if (data->len == 0) {
467 // EOF from client.
468 StopClient();
469 return;
470 }
471
472 if (state_ == kStateReadClientHeader) {
473 if (!ReadClientHeaders(data)) {
474 return;
475 }
476 if (state_ == kStateReadClientHeader) {
477 // Still consuming client headers; restart the input timer.
478 StartIdleTimeout();
479 return;
480 }
481 }
482
483 // Check data->len again since ReadClientHeaders() may have consumed some
484 // part of it.
485 if (data->len != 0) {
486 // The client sent some information after its headers. Buffer the client
487 // input and temporarily disable input events from the client.
488 client_data_.Append(ByteString(data->buf, data->len));
489 read_client_handler_->Stop();
490 StartTransmit();
491 }
492}
493
494// IOInputHandler callback which fires when data has been read from the
495// server.
496void HTTPProxy::ReadFromServer(InputData *data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700497 SLOG(HTTPProxy, 3) << "In " << __func__ << " length " << data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700498 if (data->len == 0) {
499 // Server closed connection.
500 if (server_data_.IsEmpty()) {
501 StopClient();
502 return;
503 }
504 state_ = kStateFlushResponse;
505 } else {
506 read_server_handler_->Stop();
507 }
508
509 server_data_.Append(ByteString(data->buf, data->len));
510
511 StartTransmit();
512}
513
514// Return an HTTP error message back to the client.
515void HTTPProxy::SendClientError(int code, const string &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700516 SLOG(HTTPProxy, 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700517 LOG(ERROR) << "Sending error " << error;
Paul Stewart58a577b2012-01-10 11:18:52 -0800518 SetClientResponse(code, "ERROR", "text/plain", error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700519 state_ = kStateFlushResponse;
520 StartTransmit();
521}
522
Paul Stewart58a577b2012-01-10 11:18:52 -0800523// Create an HTTP response message to be sent to the client.
524void HTTPProxy::SetClientResponse(int code, const string &type,
525 const string &content_type,
526 const string &message) {
527 string content_line;
528 if (!message.empty() && !content_type.empty()) {
529 content_line = StringPrintf("Content-Type: %s\r\n", content_type.c_str());
530 }
531 string response = StringPrintf("HTTP/1.1 %d %s\r\n"
532 "%s\r\n"
533 "%s", code, type.c_str(),
534 content_line.c_str(),
535 message.c_str());
536 server_data_ = ByteString(response, false);
537}
538
Paul Stewartf65320c2011-10-13 14:34:52 -0700539// Start a timeout for "the next event". This timeout augments the overall
540// transaction timeout to make sure there is some activity occurring at
541// reasonable intervals.
542void HTTPProxy::StartIdleTimeout() {
543 int timeout_seconds = 0;
544 switch (state_) {
545 case kStateReadClientHeader:
546 timeout_seconds = kClientHeaderTimeoutSeconds;
547 break;
548 case kStateConnectServer:
549 timeout_seconds = kConnectTimeoutSeconds;
550 break;
551 case kStateLookupServer:
552 // DNSClient has its own internal timeout, so we need not set one here.
553 timeout_seconds = 0;
554 break;
555 default:
556 timeout_seconds = kInputTimeoutSeconds;
557 break;
558 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500559 idle_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700560 if (timeout_seconds != 0) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500561 idle_timeout_.Reset(Bind(&HTTPProxy::StopClient,
562 weak_ptr_factory_.GetWeakPtr()));
563 dispatcher_->PostDelayedTask(idle_timeout_.callback(),
564 timeout_seconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700565 }
566}
567
568// Start the various input handlers. Listen for new data only if we have
569// completely written the last data we've received to the other end.
570void HTTPProxy::StartReceive() {
571 if (state_ == kStateTunnelData && client_data_.IsEmpty()) {
572 read_client_handler_->Start();
573 }
574 if (server_data_.IsEmpty()) {
575 if (state_ == kStateTunnelData) {
576 if (read_server_handler_.get()) {
577 read_server_handler_->Start();
578 } else {
579 read_server_handler_.reset(
580 dispatcher_->CreateInputHandler(server_socket_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500581 read_server_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700582 }
583 } else if (state_ == kStateFlushResponse) {
584 StopClient();
585 return;
586 }
587 }
588 StartIdleTimeout();
589}
590
591// Start the various output-ready handlers for the endpoints we have
592// data waiting for.
593void HTTPProxy::StartTransmit() {
594 if (state_ == kStateTunnelData && !client_data_.IsEmpty()) {
595 if (write_server_handler_.get()) {
596 write_server_handler_->Start();
597 } else {
598 write_server_handler_.reset(
599 dispatcher_->CreateReadyHandler(server_socket_,
600 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500601 write_server_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700602 }
603 }
604 if ((state_ == kStateFlushResponse || state_ == kStateTunnelData) &&
605 !server_data_.IsEmpty()) {
606 if (write_client_handler_.get()) {
607 write_client_handler_->Start();
608 } else {
609 write_client_handler_.reset(
610 dispatcher_->CreateReadyHandler(client_socket_,
611 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500612 write_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700613 }
614 }
615 StartIdleTimeout();
616}
617
618// End the transaction with the current client, restart the IOHandler
619// which alerts us to new clients connecting. This function is called
620// during various error conditions and is a callback for all timeouts.
621void HTTPProxy::StopClient() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700622 SLOG(HTTPProxy, 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700623
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800624 if (is_route_requested_) {
625 connection_->ReleaseRouting();
626 is_route_requested_ = false;
627 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700628 write_client_handler_.reset();
629 read_client_handler_.reset();
630 if (client_socket_ != -1) {
631 sockets_->Close(client_socket_);
632 client_socket_ = -1;
633 }
634 client_headers_.clear();
Paul Stewart58a577b2012-01-10 11:18:52 -0800635 client_method_.clear();
Paul Stewartf65320c2011-10-13 14:34:52 -0700636 client_version_.clear();
637 server_port_ = kDefaultServerPort;
638 write_server_handler_.reset();
639 read_server_handler_.reset();
640 if (server_socket_ != -1) {
641 sockets_->Close(server_socket_);
642 server_socket_ = -1;
643 }
644 server_hostname_.clear();
645 client_data_.Clear();
646 server_data_.Clear();
647 dns_client_->Stop();
648 server_async_connection_->Stop();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500649 idle_timeout_.Cancel();
Paul Stewartf582b502012-04-04 21:39:22 -0700650 transaction_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700651 accept_handler_->Start();
652 state_ = kStateWaitConnection;
653}
654
655// Output ReadyHandler callback which fires when the client socket is
656// ready for data to be sent to it.
657void HTTPProxy::WriteToClient(int fd) {
658 CHECK_EQ(client_socket_, fd);
659 int ret = sockets_->Send(fd, server_data_.GetConstData(),
660 server_data_.GetLength(), 0);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700661 SLOG(HTTPProxy, 3) << "In " << __func__ << " wrote " << ret << " of "
662 << server_data_.GetLength();
Paul Stewartf65320c2011-10-13 14:34:52 -0700663 if (ret < 0) {
664 LOG(ERROR) << "Server write failed";
665 StopClient();
666 return;
667 }
668
669 server_data_ = ByteString(server_data_.GetConstData() + ret,
670 server_data_.GetLength() - ret);
671
672 if (server_data_.IsEmpty()) {
673 write_client_handler_->Stop();
674 }
675
676 StartReceive();
677}
678
679// Output ReadyHandler callback which fires when the server socket is
680// ready for data to be sent to it.
681void HTTPProxy::WriteToServer(int fd) {
682 CHECK_EQ(server_socket_, fd);
683 int ret = sockets_->Send(fd, client_data_.GetConstData(),
684 client_data_.GetLength(), 0);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700685 SLOG(HTTPProxy, 3) << "In " << __func__ << " wrote " << ret << " of "
686 << client_data_.GetLength();
Paul Stewartf65320c2011-10-13 14:34:52 -0700687
688 if (ret < 0) {
689 LOG(ERROR) << "Client write failed";
690 StopClient();
691 return;
692 }
693
694 client_data_ = ByteString(client_data_.GetConstData() + ret,
695 client_data_.GetLength() - ret);
696
697 if (client_data_.IsEmpty()) {
698 write_server_handler_->Stop();
699 }
700
701 StartReceive();
702}
703
704} // namespace shill