blob: 5aa1f9ea8cd87a643656b179e52377f91b2d7a48 [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/logging.h>
18#include <base/string_number_conversions.h>
19#include <base/string_split.h>
20#include <base/string_util.h>
21#include <base/stringprintf.h>
22
23#include "shill/async_connection.h"
Paul Stewartc8f4bef2011-12-13 09:45:51 -080024#include "shill/connection.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070025#include "shill/dns_client.h"
26#include "shill/event_dispatcher.h"
27#include "shill/ip_address.h"
28#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;
Eric Shienbrood3e20a232012-02-16 11:35:56 -050032using base::Unretained;
Paul Stewartf65320c2011-10-13 14:34:52 -070033using std::string;
34using std::vector;
35
36namespace shill {
37
38const int HTTPProxy::kClientHeaderTimeoutSeconds = 1;
39const int HTTPProxy::kConnectTimeoutSeconds = 10;
40const int HTTPProxy::kDNSTimeoutSeconds = 5;
41const int HTTPProxy::kDefaultServerPort = 80;
42const int HTTPProxy::kInputTimeoutSeconds = 30;
43const size_t HTTPProxy::kMaxClientQueue = 10;
44const size_t HTTPProxy::kMaxHeaderCount = 128;
45const size_t HTTPProxy::kMaxHeaderSize = 2048;
46const int HTTPProxy::kTransactionTimeoutSeconds = 600;
47
Paul Stewart58a577b2012-01-10 11:18:52 -080048const char HTTPProxy::kHTTPMethodConnect[] = "connect";
49const char HTTPProxy::kHTTPMethodTerminator[] = " ";
Paul Stewartf65320c2011-10-13 14:34:52 -070050const char HTTPProxy::kHTTPURLDelimiters[] = " /#?";
51const char HTTPProxy::kHTTPURLPrefix[] = "http://";
52const char HTTPProxy::kHTTPVersionPrefix[] = " HTTP/1";
53const char HTTPProxy::kInternalErrorMsg[] = "Proxy Failed: Internal Error";
54
Paul Stewartc8f4bef2011-12-13 09:45:51 -080055HTTPProxy::HTTPProxy(ConnectionRefPtr connection)
Paul Stewartf65320c2011-10-13 14:34:52 -070056 : state_(kStateIdle),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080057 connection_(connection),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050058 weak_ptr_factory_(this),
59 accept_callback_(Bind(&HTTPProxy::AcceptClient, Unretained(this))),
60 connect_completion_callback_(Bind(&HTTPProxy::OnConnectCompletion,
61 Unretained(this))),
62 dns_client_callback_(Bind(&HTTPProxy::GetDNSResult, Unretained(this))),
63 read_client_callback_(Bind(&HTTPProxy::ReadFromClient, Unretained(this))),
64 read_server_callback_(Bind(&HTTPProxy::ReadFromServer, Unretained(this))),
65 write_client_callback_(Bind(&HTTPProxy::WriteToClient, Unretained(this))),
66 write_server_callback_(Bind(&HTTPProxy::WriteToServer, Unretained(this))),
Paul Stewartf65320c2011-10-13 14:34:52 -070067 dispatcher_(NULL),
68 dns_client_(NULL),
69 proxy_port_(-1),
70 proxy_socket_(-1),
71 server_async_connection_(NULL),
72 sockets_(NULL),
73 client_socket_(-1),
74 server_port_(kDefaultServerPort),
75 server_socket_(-1),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050076 is_route_requested_(false) { }
Paul Stewartf65320c2011-10-13 14:34:52 -070077
78HTTPProxy::~HTTPProxy() {
79 Stop();
80}
81
82bool HTTPProxy::Start(EventDispatcher *dispatcher,
83 Sockets *sockets) {
84 VLOG(3) << "In " << __func__;
85
86 if (sockets_) {
87 // We are already running.
88 return true;
89 }
90
91 proxy_socket_ = sockets->Socket(PF_INET, SOCK_STREAM, 0);
92 if (proxy_socket_ < 0) {
93 PLOG(ERROR) << "Failed to open proxy socket";
94 return false;
95 }
96
97 struct sockaddr_in addr;
98 socklen_t addrlen = sizeof(addr);
99 memset(&addr, 0, sizeof(addr));
100 addr.sin_family = AF_INET;
101 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
102 if (sockets->Bind(proxy_socket_,
103 reinterpret_cast<struct sockaddr *>(&addr),
104 sizeof(addr)) < 0 ||
105 sockets->GetSockName(proxy_socket_,
106 reinterpret_cast<struct sockaddr *>(&addr),
107 &addrlen) < 0 ||
108 sockets->SetNonBlocking(proxy_socket_) < 0 ||
109 sockets->Listen(proxy_socket_, kMaxClientQueue) < 0) {
110 sockets->Close(proxy_socket_);
111 proxy_socket_ = -1;
112 PLOG(ERROR) << "HTTPProxy socket setup failed";
113 return false;
114 }
115
116 accept_handler_.reset(
117 dispatcher->CreateReadyHandler(proxy_socket_, IOHandler::kModeInput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500118 accept_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700119 dispatcher_ = dispatcher;
120 dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800121 connection_->interface_name(),
122 connection_->dns_servers(),
Paul Stewartf65320c2011-10-13 14:34:52 -0700123 kDNSTimeoutSeconds * 1000,
124 dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500125 dns_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700126 proxy_port_ = ntohs(addr.sin_port);
127 server_async_connection_.reset(
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800128 new AsyncConnection(connection_->interface_name(), dispatcher, sockets,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500129 connect_completion_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700130 sockets_ = sockets;
131 state_ = kStateWaitConnection;
132 return true;
133}
134
135void HTTPProxy::Stop() {
136 VLOG(3) << "In " << __func__;
137
138 if (!sockets_ ) {
139 return;
140 }
141
142 StopClient();
143
144 accept_handler_.reset();
145 dispatcher_ = NULL;
146 dns_client_.reset();
147 proxy_port_ = -1;
148 server_async_connection_.reset();
149 sockets_->Close(proxy_socket_);
150 proxy_socket_ = -1;
151 sockets_ = NULL;
152 state_ = kStateIdle;
153}
154
155// IOReadyHandler callback routine fired when a client connects to the
156// proxy's socket. We Accept() the client and start reading a request
157// from it.
158void HTTPProxy::AcceptClient(int fd) {
159 VLOG(3) << "In " << __func__;
160
161 int client_fd = sockets_->Accept(fd, NULL, NULL);
162 if (client_fd < 0) {
163 PLOG(ERROR) << "Client accept failed";
164 return;
165 }
166
167 accept_handler_->Stop();
168
169 client_socket_ = client_fd;
170
171 sockets_->SetNonBlocking(client_socket_);
172 read_client_handler_.reset(
173 dispatcher_->CreateInputHandler(client_socket_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500174 read_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700175 // Overall transaction timeout.
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500176 dispatcher_->PostDelayedTask(Bind(&HTTPProxy::StopClient,
177 weak_ptr_factory_.GetWeakPtr()),
178 kTransactionTimeoutSeconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700179
180 state_ = kStateReadClientHeader;
181 StartIdleTimeout();
182}
183
184bool HTTPProxy::ConnectServer(const IPAddress &address, int port) {
185 state_ = kStateConnectServer;
186 if (!server_async_connection_->Start(address, port)) {
187 SendClientError(500, "Could not create socket to connect to server");
188 return false;
189 }
190 StartIdleTimeout();
191 return true;
192}
193
194// DNSClient callback that fires when the DNS request completes.
Paul Stewartbdb02e62012-02-22 16:24:33 -0800195void HTTPProxy::GetDNSResult(const Error &error, const IPAddress &address) {
196 if (!error.IsSuccess()) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700197 SendClientError(502, string("Could not resolve hostname: ") +
Paul Stewartbdb02e62012-02-22 16:24:33 -0800198 error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700199 return;
200 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800201 ConnectServer(address, server_port_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700202}
203
204// IOReadyHandler callback routine which fires when the asynchronous Connect()
205// to the remote server completes (or fails).
206void HTTPProxy::OnConnectCompletion(bool success, int fd) {
207 if (!success) {
208 SendClientError(500, string("Socket connection delayed failure: ") +
209 server_async_connection_->error());
210 return;
211 }
212 server_socket_ = fd;
213 state_ = kStateTunnelData;
Paul Stewart58a577b2012-01-10 11:18:52 -0800214
215 // If this was a "CONNECT" request, notify the client that the connection
216 // has been established by sending an "OK" response.
217 if (LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
218 SetClientResponse(200, "OK", "", "");
219 StartReceive();
220 }
221
Paul Stewartf65320c2011-10-13 14:34:52 -0700222 StartTransmit();
223}
224
225// Read through the header lines from the client, modifying or adding
226// lines as necessary. Perform final determination of the hostname/port
227// we should connect to and either start a DNS request or connect to a
228// numeric address.
229bool HTTPProxy::ParseClientRequest() {
230 VLOG(3) << "In " << __func__;
231
232 string host;
233 bool found_via = false;
234 bool found_connection = false;
235 for (vector<string>::iterator it = client_headers_.begin();
236 it != client_headers_.end(); ++it) {
237 if (StartsWithASCII(*it, "Host:", false)) {
238 host = it->substr(5);
239 } else if (StartsWithASCII(*it, "Via:", false)) {
240 found_via = true;
241 (*it).append(StringPrintf(", %s shill-proxy", client_version_.c_str()));
242 } else if (StartsWithASCII(*it, "Connection:", false)) {
243 found_connection = true;
244 (*it).assign("Connection: close");
245 } else if (StartsWithASCII(*it, "Proxy-Connection:", false)) {
246 (*it).assign("Proxy-Connection: close");
247 }
248 }
249
250 if (!found_connection) {
251 client_headers_.push_back("Connection: close");
252 }
253 if (!found_via) {
254 client_headers_.push_back(
255 StringPrintf("Via: %s shill-proxy", client_version_.c_str()));
256 }
257
258 // Assemble the request as it will be sent to the server.
259 client_data_.Clear();
Paul Stewart58a577b2012-01-10 11:18:52 -0800260 if (!LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
261 for (vector<string>::iterator it = client_headers_.begin();
262 it != client_headers_.end(); ++it) {
263 client_data_.Append(ByteString(*it + "\r\n", false));
264 }
265 client_data_.Append(ByteString(string("\r\n"), false));
Paul Stewartf65320c2011-10-13 14:34:52 -0700266 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700267
268 TrimWhitespaceASCII(host, TRIM_ALL, &host);
269 if (host.empty()) {
270 // Revert to using the hostname in the URL if no "Host:" header exists.
271 host = server_hostname_;
272 }
273
274 if (host.empty()) {
275 SendClientError(400, "I don't know what host you want me to connect to");
276 return false;
277 }
278
279 server_port_ = 80;
280 vector<string> host_parts;
281 base::SplitString(host, ':', &host_parts);
282
283 if (host_parts.size() > 2) {
284 SendClientError(400, "Too many colons in hostname");
285 return false;
286 } else if (host_parts.size() == 2) {
287 server_hostname_ = host_parts[0];
288 if (!base::StringToInt(host_parts[1], &server_port_)) {
289 SendClientError(400, "Could not parse port number");
290 return false;
291 }
292 } else {
293 server_hostname_ = host;
294 }
295
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800296 connection_->RequestRouting();
297 is_route_requested_ = true;
298
Paul Stewartf65320c2011-10-13 14:34:52 -0700299 IPAddress addr(IPAddress::kFamilyIPv4);
300 if (addr.SetAddressFromString(server_hostname_)) {
301 if (!ConnectServer(addr, server_port_)) {
302 return false;
303 }
304 } else {
305 VLOG(3) << "Looking up host: " << server_hostname_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800306 Error error;
307 if (!dns_client_->Start(server_hostname_, &error)) {
308 SendClientError(502, "Could not resolve hostname: " + error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700309 return false;
310 }
311 state_ = kStateLookupServer;
312 }
313 return true;
314}
315
316// Accept a new line into the client headers. Returns false if a parse
317// error occurs.
318bool HTTPProxy::ProcessLastHeaderLine() {
319 string *header = &client_headers_.back();
320 TrimString(*header, "\r", header);
321
322 if (header->empty()) {
323 // Empty line terminates client headers.
324 client_headers_.pop_back();
325 if (!ParseClientRequest()) {
326 return false;
327 }
328 }
329
330 // Is this is the first header line?
331 if (client_headers_.size() == 1) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800332 if (!ReadClientHTTPMethod(header) ||
333 !ReadClientHTTPVersion(header) ||
334 !ReadClientHostname(header)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700335 return false;
336 }
337 }
338
339 if (client_headers_.size() >= kMaxHeaderCount) {
340 SendClientError(500, kInternalErrorMsg);
341 return false;
342 }
343
344 return true;
345}
346
347// Split input from client into header lines, and consume parsed lines
348// from InputData. The passed in |data| is modified to indicate the
349// characters consumed.
350bool HTTPProxy::ReadClientHeaders(InputData *data) {
351 unsigned char *ptr = data->buf;
352 unsigned char *end = ptr + data->len;
353
354 if (client_headers_.empty()) {
355 client_headers_.push_back(string());
356 }
357
358 for (; ptr < end && state_ == kStateReadClientHeader; ++ptr) {
359 if (*ptr == '\n') {
360 if (!ProcessLastHeaderLine()) {
361 return false;
362 }
363
364 // Start a new line. New chararacters we receive will be appended there.
365 client_headers_.push_back(string());
366 continue;
367 }
368
369 string *header = &client_headers_.back();
370 // Is the first character of the header line a space or tab character?
371 if (header->empty() && (*ptr == ' ' || *ptr == '\t') &&
372 client_headers_.size() > 1) {
373 // Line Continuation: Add this character to the previous header line.
374 // This way, all of the data (including newlines and line continuation
375 // characters) related to a specific header will be contained within
376 // a single element of |client_headers_|, and manipulation of headers
377 // such as appending will be simpler. This is accomplished by removing
378 // the empty line we started, and instead appending the whitespace
379 // and following characters to the previous line.
380 client_headers_.pop_back();
381 header = &client_headers_.back();
382 header->append("\r\n");
383 }
384
385 if (header->length() >= kMaxHeaderSize) {
386 SendClientError(500, kInternalErrorMsg);
387 return false;
388 }
389 header->push_back(*ptr);
390 }
391
392 // Return the remaining data to the caller -- this could be POST data
393 // or other non-header data sent with the client request.
394 data->buf = ptr;
395 data->len = end - ptr;
396
397 return true;
398}
399
400// Finds the URL in the first line of an HTTP client header, and extracts
401// and removes the hostname (and port) from the URL. Returns false if a
402// parse error occurs, and true otherwise (whether or not the hostname was
403// found).
404bool HTTPProxy::ReadClientHostname(string *header) {
405 const string http_url_prefix(kHTTPURLPrefix);
406 size_t url_idx = header->find(http_url_prefix);
407 if (url_idx != string::npos) {
408 size_t host_start = url_idx + http_url_prefix.length();
409 size_t host_end =
410 header->find_first_of(kHTTPURLDelimiters, host_start);
411 if (host_end != string::npos) {
412 server_hostname_ = header->substr(host_start,
413 host_end - host_start);
414 // Modify the URL passed upstream to remove "http://<hostname>".
415 header->erase(url_idx, host_end - url_idx);
416 if ((*header)[url_idx] != '/') {
417 header->insert(url_idx, "/");
418 }
419 } else {
420 LOG(ERROR) << "Could not find end of hostname in request. Line was: "
421 << *header;
422 SendClientError(500, kInternalErrorMsg);
423 return false;
424 }
425 }
426 return true;
427}
428
Paul Stewart58a577b2012-01-10 11:18:52 -0800429bool HTTPProxy::ReadClientHTTPMethod(string *header) {
430 size_t method_end = header->find(kHTTPMethodTerminator);
431 if (method_end == string::npos || method_end == 0) {
432 LOG(ERROR) << "Could not parse HTTP method. Line was: " << *header;
433 SendClientError(501, "Server could not parse HTTP method");
434 return false;
435 }
436 client_method_ = header->substr(0, method_end);
437 return true;
438}
439
Paul Stewartf65320c2011-10-13 14:34:52 -0700440// Extract the HTTP version number from the first line of the client headers.
441// Returns true if found.
442bool HTTPProxy::ReadClientHTTPVersion(string *header) {
443 const string http_version_prefix(kHTTPVersionPrefix);
444 size_t http_ver_pos = header->find(http_version_prefix);
445 if (http_ver_pos != string::npos) {
446 client_version_ =
447 header->substr(http_ver_pos + http_version_prefix.length() - 1);
448 } else {
449 SendClientError(501, "Server only accepts HTTP/1.x requests");
450 return false;
451 }
452 return true;
453}
454
455// IOInputHandler callback that fires when data is read from the client.
456// This could be header data, or perhaps POST data that follows the headers.
457void HTTPProxy::ReadFromClient(InputData *data) {
458 VLOG(3) << "In " << __func__ << " length " << data->len;
459
460 if (data->len == 0) {
461 // EOF from client.
462 StopClient();
463 return;
464 }
465
466 if (state_ == kStateReadClientHeader) {
467 if (!ReadClientHeaders(data)) {
468 return;
469 }
470 if (state_ == kStateReadClientHeader) {
471 // Still consuming client headers; restart the input timer.
472 StartIdleTimeout();
473 return;
474 }
475 }
476
477 // Check data->len again since ReadClientHeaders() may have consumed some
478 // part of it.
479 if (data->len != 0) {
480 // The client sent some information after its headers. Buffer the client
481 // input and temporarily disable input events from the client.
482 client_data_.Append(ByteString(data->buf, data->len));
483 read_client_handler_->Stop();
484 StartTransmit();
485 }
486}
487
488// IOInputHandler callback which fires when data has been read from the
489// server.
490void HTTPProxy::ReadFromServer(InputData *data) {
491 VLOG(3) << "In " << __func__ << " length " << data->len;
492 if (data->len == 0) {
493 // Server closed connection.
494 if (server_data_.IsEmpty()) {
495 StopClient();
496 return;
497 }
498 state_ = kStateFlushResponse;
499 } else {
500 read_server_handler_->Stop();
501 }
502
503 server_data_.Append(ByteString(data->buf, data->len));
504
505 StartTransmit();
506}
507
508// Return an HTTP error message back to the client.
509void HTTPProxy::SendClientError(int code, const string &error) {
510 VLOG(3) << "In " << __func__;
511 LOG(ERROR) << "Sending error " << error;
Paul Stewart58a577b2012-01-10 11:18:52 -0800512 SetClientResponse(code, "ERROR", "text/plain", error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700513 state_ = kStateFlushResponse;
514 StartTransmit();
515}
516
Paul Stewart58a577b2012-01-10 11:18:52 -0800517// Create an HTTP response message to be sent to the client.
518void HTTPProxy::SetClientResponse(int code, const string &type,
519 const string &content_type,
520 const string &message) {
521 string content_line;
522 if (!message.empty() && !content_type.empty()) {
523 content_line = StringPrintf("Content-Type: %s\r\n", content_type.c_str());
524 }
525 string response = StringPrintf("HTTP/1.1 %d %s\r\n"
526 "%s\r\n"
527 "%s", code, type.c_str(),
528 content_line.c_str(),
529 message.c_str());
530 server_data_ = ByteString(response, false);
531}
532
Paul Stewartf65320c2011-10-13 14:34:52 -0700533// Start a timeout for "the next event". This timeout augments the overall
534// transaction timeout to make sure there is some activity occurring at
535// reasonable intervals.
536void HTTPProxy::StartIdleTimeout() {
537 int timeout_seconds = 0;
538 switch (state_) {
539 case kStateReadClientHeader:
540 timeout_seconds = kClientHeaderTimeoutSeconds;
541 break;
542 case kStateConnectServer:
543 timeout_seconds = kConnectTimeoutSeconds;
544 break;
545 case kStateLookupServer:
546 // DNSClient has its own internal timeout, so we need not set one here.
547 timeout_seconds = 0;
548 break;
549 default:
550 timeout_seconds = kInputTimeoutSeconds;
551 break;
552 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500553 idle_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700554 if (timeout_seconds != 0) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500555 idle_timeout_.Reset(Bind(&HTTPProxy::StopClient,
556 weak_ptr_factory_.GetWeakPtr()));
557 dispatcher_->PostDelayedTask(idle_timeout_.callback(),
558 timeout_seconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700559 }
560}
561
562// Start the various input handlers. Listen for new data only if we have
563// completely written the last data we've received to the other end.
564void HTTPProxy::StartReceive() {
565 if (state_ == kStateTunnelData && client_data_.IsEmpty()) {
566 read_client_handler_->Start();
567 }
568 if (server_data_.IsEmpty()) {
569 if (state_ == kStateTunnelData) {
570 if (read_server_handler_.get()) {
571 read_server_handler_->Start();
572 } else {
573 read_server_handler_.reset(
574 dispatcher_->CreateInputHandler(server_socket_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500575 read_server_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700576 }
577 } else if (state_ == kStateFlushResponse) {
578 StopClient();
579 return;
580 }
581 }
582 StartIdleTimeout();
583}
584
585// Start the various output-ready handlers for the endpoints we have
586// data waiting for.
587void HTTPProxy::StartTransmit() {
588 if (state_ == kStateTunnelData && !client_data_.IsEmpty()) {
589 if (write_server_handler_.get()) {
590 write_server_handler_->Start();
591 } else {
592 write_server_handler_.reset(
593 dispatcher_->CreateReadyHandler(server_socket_,
594 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500595 write_server_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700596 }
597 }
598 if ((state_ == kStateFlushResponse || state_ == kStateTunnelData) &&
599 !server_data_.IsEmpty()) {
600 if (write_client_handler_.get()) {
601 write_client_handler_->Start();
602 } else {
603 write_client_handler_.reset(
604 dispatcher_->CreateReadyHandler(client_socket_,
605 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500606 write_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700607 }
608 }
609 StartIdleTimeout();
610}
611
612// End the transaction with the current client, restart the IOHandler
613// which alerts us to new clients connecting. This function is called
614// during various error conditions and is a callback for all timeouts.
615void HTTPProxy::StopClient() {
616 VLOG(3) << "In " << __func__;
617
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800618 if (is_route_requested_) {
619 connection_->ReleaseRouting();
620 is_route_requested_ = false;
621 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700622 write_client_handler_.reset();
623 read_client_handler_.reset();
624 if (client_socket_ != -1) {
625 sockets_->Close(client_socket_);
626 client_socket_ = -1;
627 }
628 client_headers_.clear();
Paul Stewart58a577b2012-01-10 11:18:52 -0800629 client_method_.clear();
Paul Stewartf65320c2011-10-13 14:34:52 -0700630 client_version_.clear();
631 server_port_ = kDefaultServerPort;
632 write_server_handler_.reset();
633 read_server_handler_.reset();
634 if (server_socket_ != -1) {
635 sockets_->Close(server_socket_);
636 server_socket_ = -1;
637 }
638 server_hostname_.clear();
639 client_data_.Clear();
640 server_data_.Clear();
641 dns_client_->Stop();
642 server_async_connection_->Stop();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500643 idle_timeout_.Cancel();
644 weak_ptr_factory_.InvalidateWeakPtrs();
Paul Stewartf65320c2011-10-13 14:34:52 -0700645 accept_handler_->Start();
646 state_ = kStateWaitConnection;
647}
648
649// Output ReadyHandler callback which fires when the client socket is
650// ready for data to be sent to it.
651void HTTPProxy::WriteToClient(int fd) {
652 CHECK_EQ(client_socket_, fd);
653 int ret = sockets_->Send(fd, server_data_.GetConstData(),
654 server_data_.GetLength(), 0);
655 VLOG(3) << "In " << __func__ << " wrote " << ret << " of " <<
656 server_data_.GetLength();
657 if (ret < 0) {
658 LOG(ERROR) << "Server write failed";
659 StopClient();
660 return;
661 }
662
663 server_data_ = ByteString(server_data_.GetConstData() + ret,
664 server_data_.GetLength() - ret);
665
666 if (server_data_.IsEmpty()) {
667 write_client_handler_->Stop();
668 }
669
670 StartReceive();
671}
672
673// Output ReadyHandler callback which fires when the server socket is
674// ready for data to be sent to it.
675void HTTPProxy::WriteToServer(int fd) {
676 CHECK_EQ(server_socket_, fd);
677 int ret = sockets_->Send(fd, client_data_.GetConstData(),
678 client_data_.GetLength(), 0);
679 VLOG(3) << "In " << __func__ << " wrote " << ret << " of " <<
680 client_data_.GetLength();
681
682 if (ret < 0) {
683 LOG(ERROR) << "Client write failed";
684 StopClient();
685 return;
686 }
687
688 client_data_ = ByteString(client_data_.GetConstData() + ret,
689 client_data_.GetLength() - ret);
690
691 if (client_data_.IsEmpty()) {
692 write_server_handler_->Stop();
693 }
694
695 StartReceive();
696}
697
698} // namespace shill