blob: 1016b50362a75f4aa30623b56e25c7e5334b4075 [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 Vakulenko3a62e232016-01-20 07:47:40 -0800264 if (base::StartsWith(header, "Host:",
265 base::CompareCase::INSENSITIVE_ASCII)) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700266 host = header.substr(5);
Alex Vakulenko3a62e232016-01-20 07:47:40 -0800267 } else if (base::StartsWith(header, "Via:",
268 base::CompareCase::INSENSITIVE_ASCII)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700269 found_via = true;
Paul Stewart6db7b242014-05-02 15:34:21 -0700270 header.append(StringPrintf(", %s shill-proxy", client_version_.c_str()));
Alex Vakulenko3a62e232016-01-20 07:47:40 -0800271 } else if (base::StartsWith(header, "Connection:",
272 base::CompareCase::INSENSITIVE_ASCII)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700273 found_connection = true;
Paul Stewart6db7b242014-05-02 15:34:21 -0700274 header.assign("Connection: close");
Alex Vakulenko3a62e232016-01-20 07:47:40 -0800275 } else if (base::StartsWith(header, "Proxy-Connection:",
276 base::CompareCase::INSENSITIVE_ASCII)) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700277 header.assign("Proxy-Connection: close");
Paul Stewartf65320c2011-10-13 14:34:52 -0700278 }
279 }
280
281 if (!found_connection) {
282 client_headers_.push_back("Connection: close");
283 }
284 if (!found_via) {
285 client_headers_.push_back(
286 StringPrintf("Via: %s shill-proxy", client_version_.c_str()));
287 }
288
289 // Assemble the request as it will be sent to the server.
290 client_data_.Clear();
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700291 if (!base::LowerCaseEqualsASCII(client_method_, kHTTPMethodConnect)) {
Paul Stewart8ae18742015-06-16 13:13:10 -0700292 for (const auto& header : client_headers_) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700293 client_data_.Append(ByteString(header + "\r\n", false));
Paul Stewart58a577b2012-01-10 11:18:52 -0800294 }
295 client_data_.Append(ByteString(string("\r\n"), false));
Paul Stewartf65320c2011-10-13 14:34:52 -0700296 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700297
Ben Chan6fbf64f2014-05-21 18:07:01 -0700298 base::TrimWhitespaceASCII(host, base::TRIM_ALL, &host);
Paul Stewartf65320c2011-10-13 14:34:52 -0700299 if (host.empty()) {
300 // Revert to using the hostname in the URL if no "Host:" header exists.
301 host = server_hostname_;
302 }
303
304 if (host.empty()) {
305 SendClientError(400, "I don't know what host you want me to connect to");
306 return false;
307 }
308
309 server_port_ = 80;
Alex Vakulenko3a62e232016-01-20 07:47:40 -0800310 vector<string> host_parts = base::SplitString(
311 host, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
Paul Stewartf65320c2011-10-13 14:34:52 -0700312
313 if (host_parts.size() > 2) {
314 SendClientError(400, "Too many colons in hostname");
315 return false;
316 } else if (host_parts.size() == 2) {
317 server_hostname_ = host_parts[0];
318 if (!base::StringToInt(host_parts[1], &server_port_)) {
319 SendClientError(400, "Could not parse port number");
320 return false;
321 }
322 } else {
323 server_hostname_ = host;
324 }
325
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800326 connection_->RequestRouting();
327 is_route_requested_ = true;
328
Paul Stewartf65320c2011-10-13 14:34:52 -0700329 IPAddress addr(IPAddress::kFamilyIPv4);
330 if (addr.SetAddressFromString(server_hostname_)) {
331 if (!ConnectServer(addr, server_port_)) {
332 return false;
333 }
334 } else {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800335 SLOG(connection_.get(), 3) << "Looking up host: " << server_hostname_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800336 Error error;
337 if (!dns_client_->Start(server_hostname_, &error)) {
338 SendClientError(502, "Could not resolve hostname: " + error.message());
Paul Stewartf65320c2011-10-13 14:34:52 -0700339 return false;
340 }
341 state_ = kStateLookupServer;
342 }
343 return true;
344}
345
346// Accept a new line into the client headers. Returns false if a parse
347// error occurs.
348bool HTTPProxy::ProcessLastHeaderLine() {
Paul Stewart8ae18742015-06-16 13:13:10 -0700349 string* header = &client_headers_.back();
Ben Chana0ddf462014-02-06 11:32:42 -0800350 base::TrimString(*header, "\r", header);
Paul Stewartf65320c2011-10-13 14:34:52 -0700351
352 if (header->empty()) {
353 // Empty line terminates client headers.
354 client_headers_.pop_back();
355 if (!ParseClientRequest()) {
356 return false;
357 }
358 }
359
360 // Is this is the first header line?
361 if (client_headers_.size() == 1) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800362 if (!ReadClientHTTPMethod(header) ||
363 !ReadClientHTTPVersion(header) ||
364 !ReadClientHostname(header)) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700365 return false;
366 }
367 }
368
369 if (client_headers_.size() >= kMaxHeaderCount) {
370 SendClientError(500, kInternalErrorMsg);
371 return false;
372 }
373
374 return true;
375}
376
377// Split input from client into header lines, and consume parsed lines
378// from InputData. The passed in |data| is modified to indicate the
379// characters consumed.
Paul Stewart8ae18742015-06-16 13:13:10 -0700380bool HTTPProxy::ReadClientHeaders(InputData* data) {
381 unsigned char* ptr = data->buf;
382 unsigned char* end = ptr + data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700383
384 if (client_headers_.empty()) {
385 client_headers_.push_back(string());
386 }
387
388 for (; ptr < end && state_ == kStateReadClientHeader; ++ptr) {
389 if (*ptr == '\n') {
390 if (!ProcessLastHeaderLine()) {
391 return false;
392 }
393
394 // Start a new line. New chararacters we receive will be appended there.
395 client_headers_.push_back(string());
396 continue;
397 }
398
Paul Stewart8ae18742015-06-16 13:13:10 -0700399 string* header = &client_headers_.back();
Paul Stewartf65320c2011-10-13 14:34:52 -0700400 // Is the first character of the header line a space or tab character?
401 if (header->empty() && (*ptr == ' ' || *ptr == '\t') &&
402 client_headers_.size() > 1) {
403 // Line Continuation: Add this character to the previous header line.
404 // This way, all of the data (including newlines and line continuation
405 // characters) related to a specific header will be contained within
406 // a single element of |client_headers_|, and manipulation of headers
407 // such as appending will be simpler. This is accomplished by removing
408 // the empty line we started, and instead appending the whitespace
409 // and following characters to the previous line.
410 client_headers_.pop_back();
411 header = &client_headers_.back();
412 header->append("\r\n");
413 }
414
415 if (header->length() >= kMaxHeaderSize) {
416 SendClientError(500, kInternalErrorMsg);
417 return false;
418 }
419 header->push_back(*ptr);
420 }
421
422 // Return the remaining data to the caller -- this could be POST data
423 // or other non-header data sent with the client request.
424 data->buf = ptr;
425 data->len = end - ptr;
426
427 return true;
428}
429
430// Finds the URL in the first line of an HTTP client header, and extracts
431// and removes the hostname (and port) from the URL. Returns false if a
432// parse error occurs, and true otherwise (whether or not the hostname was
433// found).
Paul Stewart8ae18742015-06-16 13:13:10 -0700434bool HTTPProxy::ReadClientHostname(string* header) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700435 const string http_url_prefix(kHTTPURLPrefix);
436 size_t url_idx = header->find(http_url_prefix);
437 if (url_idx != string::npos) {
438 size_t host_start = url_idx + http_url_prefix.length();
439 size_t host_end =
440 header->find_first_of(kHTTPURLDelimiters, host_start);
441 if (host_end != string::npos) {
442 server_hostname_ = header->substr(host_start,
443 host_end - host_start);
444 // Modify the URL passed upstream to remove "http://<hostname>".
445 header->erase(url_idx, host_end - url_idx);
446 if ((*header)[url_idx] != '/') {
447 header->insert(url_idx, "/");
448 }
449 } else {
450 LOG(ERROR) << "Could not find end of hostname in request. Line was: "
451 << *header;
452 SendClientError(500, kInternalErrorMsg);
453 return false;
454 }
455 }
456 return true;
457}
458
Paul Stewart8ae18742015-06-16 13:13:10 -0700459bool HTTPProxy::ReadClientHTTPMethod(string* header) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800460 size_t method_end = header->find(kHTTPMethodTerminator);
461 if (method_end == string::npos || method_end == 0) {
462 LOG(ERROR) << "Could not parse HTTP method. Line was: " << *header;
463 SendClientError(501, "Server could not parse HTTP method");
464 return false;
465 }
466 client_method_ = header->substr(0, method_end);
467 return true;
468}
469
Paul Stewartf65320c2011-10-13 14:34:52 -0700470// Extract the HTTP version number from the first line of the client headers.
471// Returns true if found.
Paul Stewart8ae18742015-06-16 13:13:10 -0700472bool HTTPProxy::ReadClientHTTPVersion(string* header) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700473 const string http_version_prefix(kHTTPVersionPrefix);
474 size_t http_ver_pos = header->find(http_version_prefix);
475 if (http_ver_pos != string::npos) {
476 client_version_ =
477 header->substr(http_ver_pos + http_version_prefix.length() - 1);
478 } else {
479 SendClientError(501, "Server only accepts HTTP/1.x requests");
480 return false;
481 }
482 return true;
483}
484
485// IOInputHandler callback that fires when data is read from the client.
486// This could be header data, or perhaps POST data that follows the headers.
Paul Stewart8ae18742015-06-16 13:13:10 -0700487void HTTPProxy::ReadFromClient(InputData* data) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800488 SLOG(connection_.get(), 3) << "In " << __func__ << " length " << data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700489
490 if (data->len == 0) {
491 // EOF from client.
492 StopClient();
493 return;
494 }
495
496 if (state_ == kStateReadClientHeader) {
497 if (!ReadClientHeaders(data)) {
498 return;
499 }
500 if (state_ == kStateReadClientHeader) {
501 // Still consuming client headers; restart the input timer.
502 StartIdleTimeout();
503 return;
504 }
505 }
506
507 // Check data->len again since ReadClientHeaders() may have consumed some
508 // part of it.
509 if (data->len != 0) {
510 // The client sent some information after its headers. Buffer the client
511 // input and temporarily disable input events from the client.
512 client_data_.Append(ByteString(data->buf, data->len));
513 read_client_handler_->Stop();
514 StartTransmit();
515 }
516}
517
518// IOInputHandler callback which fires when data has been read from the
519// server.
Paul Stewart8ae18742015-06-16 13:13:10 -0700520void HTTPProxy::ReadFromServer(InputData* data) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800521 SLOG(connection_.get(), 3) << "In " << __func__ << " length " << data->len;
Paul Stewartf65320c2011-10-13 14:34:52 -0700522 if (data->len == 0) {
523 // Server closed connection.
524 if (server_data_.IsEmpty()) {
525 StopClient();
526 return;
527 }
528 state_ = kStateFlushResponse;
529 } else {
530 read_server_handler_->Stop();
531 }
532
533 server_data_.Append(ByteString(data->buf, data->len));
534
535 StartTransmit();
536}
537
538// Return an HTTP error message back to the client.
Paul Stewart8ae18742015-06-16 13:13:10 -0700539void HTTPProxy::SendClientError(int code, const string& error) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800540 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700541 LOG(ERROR) << "Sending error " << error;
Paul Stewart58a577b2012-01-10 11:18:52 -0800542 SetClientResponse(code, "ERROR", "text/plain", error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700543 state_ = kStateFlushResponse;
544 StartTransmit();
545}
546
Paul Stewart58a577b2012-01-10 11:18:52 -0800547// Create an HTTP response message to be sent to the client.
Paul Stewart8ae18742015-06-16 13:13:10 -0700548void HTTPProxy::SetClientResponse(int code, const string& type,
549 const string& content_type,
550 const string& message) {
Paul Stewart58a577b2012-01-10 11:18:52 -0800551 string content_line;
552 if (!message.empty() && !content_type.empty()) {
553 content_line = StringPrintf("Content-Type: %s\r\n", content_type.c_str());
554 }
555 string response = StringPrintf("HTTP/1.1 %d %s\r\n"
556 "%s\r\n"
557 "%s", code, type.c_str(),
558 content_line.c_str(),
559 message.c_str());
560 server_data_ = ByteString(response, false);
561}
562
Paul Stewartf65320c2011-10-13 14:34:52 -0700563// Start a timeout for "the next event". This timeout augments the overall
564// transaction timeout to make sure there is some activity occurring at
565// reasonable intervals.
566void HTTPProxy::StartIdleTimeout() {
567 int timeout_seconds = 0;
568 switch (state_) {
569 case kStateReadClientHeader:
570 timeout_seconds = kClientHeaderTimeoutSeconds;
571 break;
572 case kStateConnectServer:
573 timeout_seconds = kConnectTimeoutSeconds;
574 break;
575 case kStateLookupServer:
576 // DNSClient has its own internal timeout, so we need not set one here.
577 timeout_seconds = 0;
578 break;
579 default:
580 timeout_seconds = kInputTimeoutSeconds;
581 break;
582 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500583 idle_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700584 if (timeout_seconds != 0) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500585 idle_timeout_.Reset(Bind(&HTTPProxy::StopClient,
586 weak_ptr_factory_.GetWeakPtr()));
587 dispatcher_->PostDelayedTask(idle_timeout_.callback(),
588 timeout_seconds * 1000);
Paul Stewartf65320c2011-10-13 14:34:52 -0700589 }
590}
591
592// Start the various input handlers. Listen for new data only if we have
593// completely written the last data we've received to the other end.
594void HTTPProxy::StartReceive() {
595 if (state_ == kStateTunnelData && client_data_.IsEmpty()) {
596 read_client_handler_->Start();
597 }
598 if (server_data_.IsEmpty()) {
599 if (state_ == kStateTunnelData) {
600 if (read_server_handler_.get()) {
601 read_server_handler_->Start();
602 } else {
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800603 read_server_handler_.reset(dispatcher_->CreateInputHandler(
604 server_socket_,
605 read_server_callback_,
606 Bind(&HTTPProxy::OnReadError, weak_ptr_factory_.GetWeakPtr())));
Paul Stewartf65320c2011-10-13 14:34:52 -0700607 }
608 } else if (state_ == kStateFlushResponse) {
609 StopClient();
610 return;
611 }
612 }
613 StartIdleTimeout();
614}
615
616// Start the various output-ready handlers for the endpoints we have
617// data waiting for.
618void HTTPProxy::StartTransmit() {
619 if (state_ == kStateTunnelData && !client_data_.IsEmpty()) {
620 if (write_server_handler_.get()) {
621 write_server_handler_->Start();
622 } else {
623 write_server_handler_.reset(
624 dispatcher_->CreateReadyHandler(server_socket_,
625 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500626 write_server_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700627 }
628 }
629 if ((state_ == kStateFlushResponse || state_ == kStateTunnelData) &&
630 !server_data_.IsEmpty()) {
631 if (write_client_handler_.get()) {
632 write_client_handler_->Start();
633 } else {
634 write_client_handler_.reset(
635 dispatcher_->CreateReadyHandler(client_socket_,
636 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500637 write_client_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -0700638 }
639 }
640 StartIdleTimeout();
641}
642
643// End the transaction with the current client, restart the IOHandler
644// which alerts us to new clients connecting. This function is called
645// during various error conditions and is a callback for all timeouts.
646void HTTPProxy::StopClient() {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800647 SLOG(connection_.get(), 3) << "In " << __func__;
Paul Stewartf65320c2011-10-13 14:34:52 -0700648
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800649 if (is_route_requested_) {
650 connection_->ReleaseRouting();
651 is_route_requested_ = false;
652 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700653 write_client_handler_.reset();
654 read_client_handler_.reset();
655 if (client_socket_ != -1) {
656 sockets_->Close(client_socket_);
657 client_socket_ = -1;
658 }
659 client_headers_.clear();
Paul Stewart58a577b2012-01-10 11:18:52 -0800660 client_method_.clear();
Paul Stewartf65320c2011-10-13 14:34:52 -0700661 client_version_.clear();
662 server_port_ = kDefaultServerPort;
663 write_server_handler_.reset();
664 read_server_handler_.reset();
665 if (server_socket_ != -1) {
666 sockets_->Close(server_socket_);
667 server_socket_ = -1;
668 }
669 server_hostname_.clear();
670 client_data_.Clear();
671 server_data_.Clear();
672 dns_client_->Stop();
673 server_async_connection_->Stop();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500674 idle_timeout_.Cancel();
Paul Stewartf582b502012-04-04 21:39:22 -0700675 transaction_timeout_.Cancel();
Paul Stewartf65320c2011-10-13 14:34:52 -0700676 accept_handler_->Start();
677 state_ = kStateWaitConnection;
678}
679
680// Output ReadyHandler callback which fires when the client socket is
681// ready for data to be sent to it.
682void HTTPProxy::WriteToClient(int fd) {
683 CHECK_EQ(client_socket_, fd);
684 int ret = sockets_->Send(fd, server_data_.GetConstData(),
685 server_data_.GetLength(), 0);
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800686 SLOG(connection_.get(), 3) << "In " << __func__ << " wrote " << ret << " of "
687 << server_data_.GetLength();
Paul Stewartf65320c2011-10-13 14:34:52 -0700688 if (ret < 0) {
689 LOG(ERROR) << "Server write failed";
690 StopClient();
691 return;
692 }
693
694 server_data_ = ByteString(server_data_.GetConstData() + ret,
695 server_data_.GetLength() - ret);
696
697 if (server_data_.IsEmpty()) {
698 write_client_handler_->Stop();
699 }
700
701 StartReceive();
702}
703
704// Output ReadyHandler callback which fires when the server socket is
705// ready for data to be sent to it.
706void HTTPProxy::WriteToServer(int fd) {
707 CHECK_EQ(server_socket_, fd);
708 int ret = sockets_->Send(fd, client_data_.GetConstData(),
709 client_data_.GetLength(), 0);
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800710 SLOG(connection_.get(), 3) << "In " << __func__ << " wrote " << ret << " of "
711 << client_data_.GetLength();
Paul Stewartf65320c2011-10-13 14:34:52 -0700712
713 if (ret < 0) {
714 LOG(ERROR) << "Client write failed";
715 StopClient();
716 return;
717 }
718
719 client_data_ = ByteString(client_data_.GetConstData() + ret,
720 client_data_.GetLength() - ret);
721
722 if (client_data_.IsEmpty()) {
723 write_server_handler_->Stop();
724 }
725
726 StartReceive();
727}
728
729} // namespace shill