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