blob: 4a19f6a4408312c5302e496ae0bd84314f48fdbf [file] [log] [blame]
Peter Qiuc0beca52015-09-03 11:25:46 -07001//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Paul Stewartf65320c2011-10-13 14:34:52 -070016
17#include "shill/http_proxy.h"
18
19#include <errno.h>
20#include <netinet/in.h>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070021#include <linux/if.h> // NOLINT - Needs definitions from netinet/in.h
Paul Stewartf65320c2011-10-13 14:34:52 -070022#include <stdio.h>
23#include <time.h>
24
25#include <string>
26#include <vector>
27
Eric Shienbrood3e20a232012-02-16 11:35:56 -050028#include <base/bind.h>
Ben Chana0ddf462014-02-06 11:32:42 -080029#include <base/strings/string_number_conversions.h>
30#include <base/strings/string_split.h>
31#include <base/strings/string_util.h>
32#include <base/strings/stringprintf.h>
Paul Stewartf65320c2011-10-13 14:34:52 -070033
34#include "shill/async_connection.h"
Paul Stewartc8f4bef2011-12-13 09:45:51 -080035#include "shill/connection.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070036#include "shill/dns_client.h"
37#include "shill/event_dispatcher.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070038#include "shill/logging.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070039#include "shill/net/ip_address.h"
40#include "shill/net/sockets.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070041
Eric Shienbrood3e20a232012-02-16 11:35:56 -050042using base::Bind;
Paul Stewartf65320c2011-10-13 14:34:52 -070043using base::StringPrintf;
44using std::string;
45using std::vector;
46
47namespace shill {
48
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070049namespace Logging {
50static auto kModuleLogScope = ScopeLogger::kHTTPProxy;
Paul Stewart8ae18742015-06-16 13:13:10 -070051static string ObjectID(Connection* c) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070052 return c->interface_name();
53}
54}
55
Paul Stewartf65320c2011-10-13 14:34:52 -070056const int HTTPProxy::kClientHeaderTimeoutSeconds = 1;
57const int HTTPProxy::kConnectTimeoutSeconds = 10;
58const int HTTPProxy::kDNSTimeoutSeconds = 5;
59const int HTTPProxy::kDefaultServerPort = 80;
60const int HTTPProxy::kInputTimeoutSeconds = 30;
61const size_t HTTPProxy::kMaxClientQueue = 10;
62const size_t HTTPProxy::kMaxHeaderCount = 128;
63const size_t HTTPProxy::kMaxHeaderSize = 2048;
64const int HTTPProxy::kTransactionTimeoutSeconds = 600;
65
Paul Stewart58a577b2012-01-10 11:18:52 -080066const char HTTPProxy::kHTTPMethodConnect[] = "connect";
67const char HTTPProxy::kHTTPMethodTerminator[] = " ";
Paul Stewartf65320c2011-10-13 14:34:52 -070068const char HTTPProxy::kHTTPURLDelimiters[] = " /#?";
69const char HTTPProxy::kHTTPURLPrefix[] = "http://";
70const char HTTPProxy::kHTTPVersionPrefix[] = " HTTP/1";
71const char HTTPProxy::kInternalErrorMsg[] = "Proxy Failed: Internal Error";
72
Paul Stewartc8f4bef2011-12-13 09:45:51 -080073HTTPProxy::HTTPProxy(ConnectionRefPtr connection)
Paul Stewartf65320c2011-10-13 14:34:52 -070074 : state_(kStateIdle),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080075 connection_(connection),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050076 weak_ptr_factory_(this),
Eric Shienbrood9a245532012-03-07 14:20:39 -050077 accept_callback_(Bind(&HTTPProxy::AcceptClient,
78 weak_ptr_factory_.GetWeakPtr())),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050079 connect_completion_callback_(Bind(&HTTPProxy::OnConnectCompletion,
Eric Shienbrood9a245532012-03-07 14:20:39 -050080 weak_ptr_factory_.GetWeakPtr())),
81 dns_client_callback_(Bind(&HTTPProxy::GetDNSResult,
82 weak_ptr_factory_.GetWeakPtr())),
83 read_client_callback_(Bind(&HTTPProxy::ReadFromClient,
84 weak_ptr_factory_.GetWeakPtr())),
85 read_server_callback_(Bind(&HTTPProxy::ReadFromServer,
86 weak_ptr_factory_.GetWeakPtr())),
87 write_client_callback_(Bind(&HTTPProxy::WriteToClient,
88 weak_ptr_factory_.GetWeakPtr())),
89 write_server_callback_(Bind(&HTTPProxy::WriteToServer,
90 weak_ptr_factory_.GetWeakPtr())),
Ben Chancc225ef2014-09-30 13:26:51 -070091 dispatcher_(nullptr),
Paul Stewartf65320c2011-10-13 14:34:52 -070092 proxy_port_(-1),
93 proxy_socket_(-1),
Ben Chancc225ef2014-09-30 13:26:51 -070094 sockets_(nullptr),
Paul Stewartf65320c2011-10-13 14:34:52 -070095 client_socket_(-1),
96 server_port_(kDefaultServerPort),
97 server_socket_(-1),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050098 is_route_requested_(false) { }
Paul Stewartf65320c2011-10-13 14:34:52 -070099
100HTTPProxy::~HTTPProxy() {
101 Stop();
102}
103
Paul Stewart8ae18742015-06-16 13:13:10 -0700104bool HTTPProxy::Start(EventDispatcher* dispatcher,
105 Sockets* sockets) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800106 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700107
108 if (sockets_) {
109 // We are already running.
110 return true;
111 }
112
113 proxy_socket_ = sockets->Socket(PF_INET, SOCK_STREAM, 0);
114 if (proxy_socket_ < 0) {
115 PLOG(ERROR) << "Failed to open proxy socket";
116 return false;
117 }
118
119 struct sockaddr_in addr;
120 socklen_t addrlen = sizeof(addr);
121 memset(&addr, 0, sizeof(addr));
122 addr.sin_family = AF_INET;
123 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
124 if (sockets->Bind(proxy_socket_,
Paul Stewart8ae18742015-06-16 13:13:10 -0700125 reinterpret_cast<struct sockaddr*>(&addr),
Paul Stewartf65320c2011-10-13 14:34:52 -0700126 sizeof(addr)) < 0 ||
127 sockets->GetSockName(proxy_socket_,
Paul Stewart8ae18742015-06-16 13:13:10 -0700128 reinterpret_cast<struct sockaddr*>(&addr),
Paul Stewartf65320c2011-10-13 14:34:52 -0700129 &addrlen) < 0 ||
130 sockets->SetNonBlocking(proxy_socket_) < 0 ||
131 sockets->Listen(proxy_socket_, kMaxClientQueue) < 0) {
132 sockets->Close(proxy_socket_);
133 proxy_socket_ = -1;
134 PLOG(ERROR) << "HTTPProxy socket setup failed";
135 return false;
136 }
137
138 accept_handler_.reset(
139 dispatcher->CreateReadyHandler(proxy_socket_, IOHandler::kModeInput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500140 accept_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700141 dispatcher_ = dispatcher;
142 dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800143 connection_->interface_name(),
144 connection_->dns_servers(),
Paul Stewartf65320c2011-10-13 14:34:52 -0700145 kDNSTimeoutSeconds * 1000,
146 dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500147 dns_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700148 proxy_port_ = ntohs(addr.sin_port);
149 server_async_connection_.reset(
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800150 new AsyncConnection(connection_->interface_name(), dispatcher, sockets,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500151 connect_completion_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700152 sockets_ = sockets;
153 state_ = kStateWaitConnection;
154 return true;
155}
156
157void HTTPProxy::Stop() {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800158 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700159
Alex Vakulenko8a532292014-06-16 17:18:44 -0700160 if (!sockets_) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700161 return;
162 }
163
164 StopClient();
165
166 accept_handler_.reset();
Ben Chancc225ef2014-09-30 13:26:51 -0700167 dispatcher_ = nullptr;
Paul Stewartf65320c2011-10-13 14:34:52 -0700168 dns_client_.reset();
169 proxy_port_ = -1;
170 server_async_connection_.reset();
171 sockets_->Close(proxy_socket_);
172 proxy_socket_ = -1;
Ben Chancc225ef2014-09-30 13:26:51 -0700173 sockets_ = nullptr;
Paul Stewartf65320c2011-10-13 14:34:52 -0700174 state_ = kStateIdle;
175}
176
177// IOReadyHandler callback routine fired when a client connects to the
178// proxy's socket. We Accept() the client and start reading a request
179// from it.
180void HTTPProxy::AcceptClient(int fd) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800181 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700182
Ben Chancc225ef2014-09-30 13:26:51 -0700183 int client_fd = sockets_->Accept(fd, nullptr, nullptr);
Paul Stewartf65320c2011-10-13 14:34:52 -0700184 if (client_fd < 0) {
185 PLOG(ERROR) << "Client accept failed";
186 return;
187 }
188
189 accept_handler_->Stop();
190
191 client_socket_ = client_fd;
192
193 sockets_->SetNonBlocking(client_socket_);
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800194 read_client_handler_.reset(dispatcher_->CreateInputHandler(
195 client_socket_,
196 read_client_callback_,
197 Bind(&HTTPProxy::OnReadError, weak_ptr_factory_.GetWeakPtr())));
Paul Stewartf65320c2011-10-13 14:34:52 -0700198 // Overall transaction timeout.
Paul Stewartf582b502012-04-04 21:39:22 -0700199 transaction_timeout_.Reset(Bind(&HTTPProxy::StopClient,
200 weak_ptr_factory_.GetWeakPtr()));
201 dispatcher_->PostDelayedTask(transaction_timeout_.callback(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500202 kTransactionTimeoutSeconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700203
204 state_ = kStateReadClientHeader;
205 StartIdleTimeout();
206}
207
Paul Stewart8ae18742015-06-16 13:13:10 -0700208bool HTTPProxy::ConnectServer(const IPAddress& address, int port) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700209 state_ = kStateConnectServer;
210 if (!server_async_connection_->Start(address, port)) {
211 SendClientError(500, "Could not create socket to connect to server");
212 return false;
213 }
214 StartIdleTimeout();
215 return true;
216}
217
218// DNSClient callback that fires when the DNS request completes.
Paul Stewart8ae18742015-06-16 13:13:10 -0700219void HTTPProxy::GetDNSResult(const Error& error, const IPAddress& address) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800220 if (!error.IsSuccess()) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700221 SendClientError(502, string("Could not resolve hostname: ") +
Paul Stewartbdb02e62012-02-22 16:24:33 -0800222 error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700223 return;
224 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800225 ConnectServer(address, server_port_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700226}
227
228// IOReadyHandler callback routine which fires when the asynchronous Connect()
229// to the remote server completes (or fails).
230void HTTPProxy::OnConnectCompletion(bool success, int fd) {
231 if (!success) {
232 SendClientError(500, string("Socket connection delayed failure: ") +
233 server_async_connection_->error());
234 return;
235 }
236 server_socket_ = fd;
237 state_ = kStateTunnelData;
Paul Stewart58a577b2012-01-10 11:18:52 -0800238
239 // If this was a "CONNECT" request, notify the client that the connection
240 // has been established by sending an "OK" response.
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700241 if (base::LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800242 SetClientResponse(200, "OK", "", "");
243 StartReceive();
244 }
245
Paul Stewartf65320c2011-10-13 14:34:52 -0700246 StartTransmit();
247}
248
Paul Stewart8ae18742015-06-16 13:13:10 -0700249void HTTPProxy::OnReadError(const string& error_msg) {
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800250 StopClient();
251}
252
Paul Stewartf65320c2011-10-13 14:34:52 -0700253// Read through the header lines from the client, modifying or adding
254// lines as necessary. Perform final determination of the hostname/port
255// we should connect to and either start a DNS request or connect to a
256// numeric address.
257bool HTTPProxy::ParseClientRequest() {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800258 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700259
260 string host;
261 bool found_via = false;
262 bool found_connection = false;
Paul Stewart8ae18742015-06-16 13:13:10 -0700263 for (auto& header : client_headers_) {
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700264 if (base::StartsWithASCII(header, "Host:", false)) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700265 host = header.substr(5);
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700266 } else if (base::StartsWithASCII(header, "Via:", false)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700267 found_via = true;
Paul Stewart6db7b242014-05-02 15:34:21 -0700268 header.append(StringPrintf(", %s shill-proxy", client_version_.c_str()));
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700269 } else if (base::StartsWithASCII(header, "Connection:", false)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700270 found_connection = true;
Paul Stewart6db7b242014-05-02 15:34:21 -0700271 header.assign("Connection: close");
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700272 } else if (base::StartsWithASCII(header, "Proxy-Connection:", false)) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700273 header.assign("Proxy-Connection: close");
Paul Stewartf65320c2011-10-13 14:34:52 -0700274 }
275 }
276
277 if (!found_connection) {
278 client_headers_.push_back("Connection: close");
279 }
280 if (!found_via) {
281 client_headers_.push_back(
282 StringPrintf("Via: %s shill-proxy", client_version_.c_str()));
283 }
284
285 // Assemble the request as it will be sent to the server.
286 client_data_.Clear();
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700287 if (!base::LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
Paul Stewart8ae18742015-06-16 13:13:10 -0700288 for (const auto& header : client_headers_) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700289 client_data_.Append(ByteString(header + "\r\n", false));
Paul Stewart58a577b2012-01-10 11:18:52 -0800290 }
291 client_data_.Append(ByteString(string("\r\n"), false));
Paul Stewartf65320c2011-10-13 14:34:52 -0700292 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700293
Ben Chan6fbf64f2014-05-21 18:07:01 -0700294 base::TrimWhitespaceASCII(host, base::TRIM_ALL, &host);
Paul Stewartf65320c2011-10-13 14:34:52 -0700295 if (host.empty()) {
296 // Revert to using the hostname in the URL if no "Host:" header exists.
297 host = server_hostname_;
298 }
299
300 if (host.empty()) {
301 SendClientError(400, "I don't know what host you want me to connect to");
302 return false;
303 }
304
305 server_port_ = 80;
306 vector<string> host_parts;
307 base::SplitString(host, ':', &host_parts);
308
309 if (host_parts.size() > 2) {
310 SendClientError(400, "Too many colons in hostname");
311 return false;
312 } else if (host_parts.size() == 2) {
313 server_hostname_ = host_parts[0];
314 if (!base::StringToInt(host_parts[1], &server_port_)) {
315 SendClientError(400, "Could not parse port number");
316 return false;
317 }
318 } else {
319 server_hostname_ = host;
320 }
321
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800322 connection_->RequestRouting();
323 is_route_requested_ = true;
324
Paul Stewartf65320c2011-10-13 14:34:52 -0700325 IPAddress addr(IPAddress::kFamilyIPv4);
326 if (addr.SetAddressFromString(server_hostname_)) {
327 if (!ConnectServer(addr, server_port_)) {
328 return false;
329 }
330 } else {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800331 SLOG(connection_.get(), 3) << "Looking up host: " << server_hostname_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800332 Error error;
333 if (!dns_client_->Start(server_hostname_, &error)) {
334 SendClientError(502, "Could not resolve hostname: " + error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700335 return false;
336 }
337 state_ = kStateLookupServer;
338 }
339 return true;
340}
341
342// Accept a new line into the client headers. Returns false if a parse
343// error occurs.
344bool HTTPProxy::ProcessLastHeaderLine() {
Paul Stewart8ae18742015-06-16 13:13:10 -0700345 string* header = &client_headers_.back();
Ben Chana0ddf462014-02-06 11:32:42 -0800346 base::TrimString(*header, "\r", header);
Paul Stewartf65320c2011-10-13 14:34:52 -0700347
348 if (header->empty()) {
349 // Empty line terminates client headers.
350 client_headers_.pop_back();
351 if (!ParseClientRequest()) {
352 return false;
353 }
354 }
355
356 // Is this is the first header line?
357 if (client_headers_.size() == 1) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800358 if (!ReadClientHTTPMethod(header) ||
359 !ReadClientHTTPVersion(header) ||
360 !ReadClientHostname(header)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700361 return false;
362 }
363 }
364
365 if (client_headers_.size() >= kMaxHeaderCount) {
366 SendClientError(500, kInternalErrorMsg);
367 return false;
368 }
369
370 return true;
371}
372
373// Split input from client into header lines, and consume parsed lines
374// from InputData. The passed in |data| is modified to indicate the
375// characters consumed.
Paul Stewart8ae18742015-06-16 13:13:10 -0700376bool HTTPProxy::ReadClientHeaders(InputData* data) {
377 unsigned char* ptr = data->buf;
378 unsigned char* end = ptr + data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700379
380 if (client_headers_.empty()) {
381 client_headers_.push_back(string());
382 }
383
384 for (; ptr < end && state_ == kStateReadClientHeader; ++ptr) {
385 if (*ptr == '\n') {
386 if (!ProcessLastHeaderLine()) {
387 return false;
388 }
389
390 // Start a new line. New chararacters we receive will be appended there.
391 client_headers_.push_back(string());
392 continue;
393 }
394
Paul Stewart8ae18742015-06-16 13:13:10 -0700395 string* header = &client_headers_.back();
Paul Stewartf65320c2011-10-13 14:34:52 -0700396 // Is the first character of the header line a space or tab character?
397 if (header->empty() && (*ptr == ' ' || *ptr == '\t') &&
398 client_headers_.size() > 1) {
399 // Line Continuation: Add this character to the previous header line.
400 // This way, all of the data (including newlines and line continuation
401 // characters) related to a specific header will be contained within
402 // a single element of |client_headers_|, and manipulation of headers
403 // such as appending will be simpler. This is accomplished by removing
404 // the empty line we started, and instead appending the whitespace
405 // and following characters to the previous line.
406 client_headers_.pop_back();
407 header = &client_headers_.back();
408 header->append("\r\n");
409 }
410
411 if (header->length() >= kMaxHeaderSize) {
412 SendClientError(500, kInternalErrorMsg);
413 return false;
414 }
415 header->push_back(*ptr);
416 }
417
418 // Return the remaining data to the caller -- this could be POST data
419 // or other non-header data sent with the client request.
420 data->buf = ptr;
421 data->len = end - ptr;
422
423 return true;
424}
425
426// Finds the URL in the first line of an HTTP client header, and extracts
427// and removes the hostname (and port) from the URL. Returns false if a
428// parse error occurs, and true otherwise (whether or not the hostname was
429// found).
Paul Stewart8ae18742015-06-16 13:13:10 -0700430bool HTTPProxy::ReadClientHostname(string* header) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700431 const string http_url_prefix(kHTTPURLPrefix);
432 size_t url_idx = header->find(http_url_prefix);
433 if (url_idx != string::npos) {
434 size_t host_start = url_idx + http_url_prefix.length();
435 size_t host_end =
436 header->find_first_of(kHTTPURLDelimiters, host_start);
437 if (host_end != string::npos) {
438 server_hostname_ = header->substr(host_start,
439 host_end - host_start);
440 // Modify the URL passed upstream to remove "http://<hostname>".
441 header->erase(url_idx, host_end - url_idx);
442 if ((*header)[url_idx] != '/') {
443 header->insert(url_idx, "/");
444 }
445 } else {
446 LOG(ERROR) << "Could not find end of hostname in request. Line was: "
447 << *header;
448 SendClientError(500, kInternalErrorMsg);
449 return false;
450 }
451 }
452 return true;
453}
454
Paul Stewart8ae18742015-06-16 13:13:10 -0700455bool HTTPProxy::ReadClientHTTPMethod(string* header) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800456 size_t method_end = header->find(kHTTPMethodTerminator);
457 if (method_end == string::npos || method_end == 0) {
458 LOG(ERROR) << "Could not parse HTTP method. Line was: " << *header;
459 SendClientError(501, "Server could not parse HTTP method");
460 return false;
461 }
462 client_method_ = header->substr(0, method_end);
463 return true;
464}
465
Paul Stewartf65320c2011-10-13 14:34:52 -0700466// Extract the HTTP version number from the first line of the client headers.
467// Returns true if found.
Paul Stewart8ae18742015-06-16 13:13:10 -0700468bool HTTPProxy::ReadClientHTTPVersion(string* header) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700469 const string http_version_prefix(kHTTPVersionPrefix);
470 size_t http_ver_pos = header->find(http_version_prefix);
471 if (http_ver_pos != string::npos) {
472 client_version_ =
473 header->substr(http_ver_pos + http_version_prefix.length() - 1);
474 } else {
475 SendClientError(501, "Server only accepts HTTP/1.x requests");
476 return false;
477 }
478 return true;
479}
480
481// IOInputHandler callback that fires when data is read from the client.
482// This could be header data, or perhaps POST data that follows the headers.
Paul Stewart8ae18742015-06-16 13:13:10 -0700483void HTTPProxy::ReadFromClient(InputData* data) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800484 SLOG(connection_.get(), 3) << "In " << __func__ << " length " << data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700485
486 if (data->len == 0) {
487 // EOF from client.
488 StopClient();
489 return;
490 }
491
492 if (state_ == kStateReadClientHeader) {
493 if (!ReadClientHeaders(data)) {
494 return;
495 }
496 if (state_ == kStateReadClientHeader) {
497 // Still consuming client headers; restart the input timer.
498 StartIdleTimeout();
499 return;
500 }
501 }
502
503 // Check data->len again since ReadClientHeaders() may have consumed some
504 // part of it.
505 if (data->len != 0) {
506 // The client sent some information after its headers. Buffer the client
507 // input and temporarily disable input events from the client.
508 client_data_.Append(ByteString(data->buf, data->len));
509 read_client_handler_->Stop();
510 StartTransmit();
511 }
512}
513
514// IOInputHandler callback which fires when data has been read from the
515// server.
Paul Stewart8ae18742015-06-16 13:13:10 -0700516void HTTPProxy::ReadFromServer(InputData* data) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800517 SLOG(connection_.get(), 3) << "In " << __func__ << " length " << data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700518 if (data->len == 0) {
519 // Server closed connection.
520 if (server_data_.IsEmpty()) {
521 StopClient();
522 return;
523 }
524 state_ = kStateFlushResponse;
525 } else {
526 read_server_handler_->Stop();
527 }
528
529 server_data_.Append(ByteString(data->buf, data->len));
530
531 StartTransmit();
532}
533
534// Return an HTTP error message back to the client.
Paul Stewart8ae18742015-06-16 13:13:10 -0700535void HTTPProxy::SendClientError(int code, const string& error) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800536 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700537 LOG(ERROR) << "Sending error " << error;
Paul Stewart58a577b2012-01-10 11:18:52 -0800538 SetClientResponse(code, "ERROR", "text/plain", error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700539 state_ = kStateFlushResponse;
540 StartTransmit();
541}
542
Paul Stewart58a577b2012-01-10 11:18:52 -0800543// Create an HTTP response message to be sent to the client.
Paul Stewart8ae18742015-06-16 13:13:10 -0700544void HTTPProxy::SetClientResponse(int code, const string& type,
545 const string& content_type,
546 const string& message) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800547 string content_line;
548 if (!message.empty() && !content_type.empty()) {
549 content_line = StringPrintf("Content-Type: %s\r\n", content_type.c_str());
550 }
551 string response = StringPrintf("HTTP/1.1 %d %s\r\n"
552 "%s\r\n"
553 "%s", code, type.c_str(),
554 content_line.c_str(),
555 message.c_str());
556 server_data_ = ByteString(response, false);
557}
558
Paul Stewartf65320c2011-10-13 14:34:52 -0700559// Start a timeout for "the next event". This timeout augments the overall
560// transaction timeout to make sure there is some activity occurring at
561// reasonable intervals.
562void HTTPProxy::StartIdleTimeout() {
563 int timeout_seconds = 0;
564 switch (state_) {
565 case kStateReadClientHeader:
566 timeout_seconds = kClientHeaderTimeoutSeconds;
567 break;
568 case kStateConnectServer:
569 timeout_seconds = kConnectTimeoutSeconds;
570 break;
571 case kStateLookupServer:
572 // DNSClient has its own internal timeout, so we need not set one here.
573 timeout_seconds = 0;
574 break;
575 default:
576 timeout_seconds = kInputTimeoutSeconds;
577 break;
578 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500579 idle_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700580 if (timeout_seconds != 0) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500581 idle_timeout_.Reset(Bind(&HTTPProxy::StopClient,
582 weak_ptr_factory_.GetWeakPtr()));
583 dispatcher_->PostDelayedTask(idle_timeout_.callback(),
584 timeout_seconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700585 }
586}
587
588// Start the various input handlers. Listen for new data only if we have
589// completely written the last data we've received to the other end.
590void HTTPProxy::StartReceive() {
591 if (state_ == kStateTunnelData && client_data_.IsEmpty()) {
592 read_client_handler_->Start();
593 }
594 if (server_data_.IsEmpty()) {
595 if (state_ == kStateTunnelData) {
596 if (read_server_handler_.get()) {
597 read_server_handler_->Start();
598 } else {
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800599 read_server_handler_.reset(dispatcher_->CreateInputHandler(
600 server_socket_,
601 read_server_callback_,
602 Bind(&HTTPProxy::OnReadError, weak_ptr_factory_.GetWeakPtr())));
Paul Stewartf65320c2011-10-13 14:34:52 -0700603 }
604 } else if (state_ == kStateFlushResponse) {
605 StopClient();
606 return;
607 }
608 }
609 StartIdleTimeout();
610}
611
612// Start the various output-ready handlers for the endpoints we have
613// data waiting for.
614void HTTPProxy::StartTransmit() {
615 if (state_ == kStateTunnelData && !client_data_.IsEmpty()) {
616 if (write_server_handler_.get()) {
617 write_server_handler_->Start();
618 } else {
619 write_server_handler_.reset(
620 dispatcher_->CreateReadyHandler(server_socket_,
621 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500622 write_server_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700623 }
624 }
625 if ((state_ == kStateFlushResponse || state_ == kStateTunnelData) &&
626 !server_data_.IsEmpty()) {
627 if (write_client_handler_.get()) {
628 write_client_handler_->Start();
629 } else {
630 write_client_handler_.reset(
631 dispatcher_->CreateReadyHandler(client_socket_,
632 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500633 write_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700634 }
635 }
636 StartIdleTimeout();
637}
638
639// End the transaction with the current client, restart the IOHandler
640// which alerts us to new clients connecting. This function is called
641// during various error conditions and is a callback for all timeouts.
642void HTTPProxy::StopClient() {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800643 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700644
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800645 if (is_route_requested_) {
646 connection_->ReleaseRouting();
647 is_route_requested_ = false;
648 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700649 write_client_handler_.reset();
650 read_client_handler_.reset();
651 if (client_socket_ != -1) {
652 sockets_->Close(client_socket_);
653 client_socket_ = -1;
654 }
655 client_headers_.clear();
Paul Stewart58a577b2012-01-10 11:18:52 -0800656 client_method_.clear();
Paul Stewartf65320c2011-10-13 14:34:52 -0700657 client_version_.clear();
658 server_port_ = kDefaultServerPort;
659 write_server_handler_.reset();
660 read_server_handler_.reset();
661 if (server_socket_ != -1) {
662 sockets_->Close(server_socket_);
663 server_socket_ = -1;
664 }
665 server_hostname_.clear();
666 client_data_.Clear();
667 server_data_.Clear();
668 dns_client_->Stop();
669 server_async_connection_->Stop();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500670 idle_timeout_.Cancel();
Paul Stewartf582b502012-04-04 21:39:22 -0700671 transaction_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700672 accept_handler_->Start();
673 state_ = kStateWaitConnection;
674}
675
676// Output ReadyHandler callback which fires when the client socket is
677// ready for data to be sent to it.
678void HTTPProxy::WriteToClient(int fd) {
679 CHECK_EQ(client_socket_, fd);
680 int ret = sockets_->Send(fd, server_data_.GetConstData(),
681 server_data_.GetLength(), 0);
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800682 SLOG(connection_.get(), 3) << "In " << __func__ << " wrote " << ret << " of "
683 << server_data_.GetLength();
Paul Stewartf65320c2011-10-13 14:34:52 -0700684 if (ret < 0) {
685 LOG(ERROR) << "Server write failed";
686 StopClient();
687 return;
688 }
689
690 server_data_ = ByteString(server_data_.GetConstData() + ret,
691 server_data_.GetLength() - ret);
692
693 if (server_data_.IsEmpty()) {
694 write_client_handler_->Stop();
695 }
696
697 StartReceive();
698}
699
700// Output ReadyHandler callback which fires when the server socket is
701// ready for data to be sent to it.
702void HTTPProxy::WriteToServer(int fd) {
703 CHECK_EQ(server_socket_, fd);
704 int ret = sockets_->Send(fd, client_data_.GetConstData(),
705 client_data_.GetLength(), 0);
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800706 SLOG(connection_.get(), 3) << "In " << __func__ << " wrote " << ret << " of "
707 << client_data_.GetLength();
Paul Stewartf65320c2011-10-13 14:34:52 -0700708
709 if (ret < 0) {
710 LOG(ERROR) << "Client write failed";
711 StopClient();
712 return;
713 }
714
715 client_data_ = ByteString(client_data_.GetConstData() + ret,
716 client_data_.GetLength() - ret);
717
718 if (client_data_.IsEmpty()) {
719 write_server_handler_->Stop();
720 }
721
722 StartReceive();
723}
724
725} // namespace shill