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