| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SHILL_HTTP_PROXY_ |
| #define SHILL_HTTP_PROXY_ |
| |
| #include <string> |
| #include <vector> |
| |
| #include <base/callback_old.h> |
| #include <base/memory/ref_counted.h> |
| #include <base/memory/scoped_ptr.h> |
| #include <base/task.h> |
| |
| #include "shill/byte_string.h" |
| #include "shill/refptr_types.h" |
| |
| namespace shill { |
| |
| class AsyncConnection; |
| class DNSClient; |
| class Error; |
| class EventDispatcher; |
| class InputData; |
| class IOHandler; |
| class IPAddress; |
| class Sockets; |
| |
| // The HTTPProxy class implements a simple web proxy that |
| // is bound to a specific interface and name server. This |
| // allows us to specify which connection a URL should be |
| // fetched through, even though many connections |
| // could be active at the same time. |
| // |
| // This service is meant to be low-performance, since we |
| // do not want to divert resources from the rest of the |
| // connection manager. As such, we serve one client request |
| // at a time. This is probably okay since the use case is |
| // limited -- only portal detection, activation and Cashew |
| // are planned to be full-time users. |
| class HTTPProxy { |
| public: |
| enum State { |
| kStateIdle, |
| kStateWaitConnection, |
| kStateReadClientHeader, |
| kStateLookupServer, |
| kStateConnectServer, |
| kStateTunnelData, |
| kStateFlushResponse, |
| }; |
| |
| explicit HTTPProxy(ConnectionRefPtr connection); |
| virtual ~HTTPProxy(); |
| |
| // Start HTTP proxy. |
| bool Start(EventDispatcher *dispatcher, Sockets *sockets); |
| |
| // Shutdown. |
| void Stop(); |
| |
| int proxy_port() const { return proxy_port_; } |
| |
| private: |
| friend class HTTPProxyTest; |
| |
| // Time to wait for initial headers from client. |
| static const int kClientHeaderTimeoutSeconds; |
| // Time to wait for connection to remote server. |
| static const int kConnectTimeoutSeconds; |
| // Time to wait for DNS server. |
| static const int kDNSTimeoutSeconds; |
| // Default port on remote server to connect to. |
| static const int kDefaultServerPort; |
| // Time to wait for any input from either server or client. |
| static const int kInputTimeoutSeconds; |
| // Maximum clients to be kept waiting. |
| static const size_t kMaxClientQueue; |
| // Maximum number of header lines to accept. |
| static const size_t kMaxHeaderCount; |
| // Maximum length of an individual header line. |
| static const size_t kMaxHeaderSize; |
| // Timeout for whole transaction. |
| static const int kTransactionTimeoutSeconds; |
| |
| static const char kHTTPMethodConnect[]; |
| static const char kHTTPMethodTerminator[]; |
| static const char kHTTPURLDelimiters[]; |
| static const char kHTTPURLPrefix[]; |
| static const char kHTTPVersionPrefix[]; |
| static const char kHTTPVersionErrorMsg[]; |
| static const char kInternalErrorMsg[]; // Message to send on failure. |
| |
| void AcceptClient(int fd); |
| bool ConnectServer(const IPAddress &address, int port); |
| void GetDNSResult(const Error &error, const IPAddress &address); |
| void OnConnectCompletion(bool success, int fd); |
| bool ParseClientRequest(); |
| bool ProcessLastHeaderLine(); |
| bool ReadClientHeaders(InputData *data); |
| bool ReadClientHostname(std::string *header); |
| bool ReadClientHTTPMethod(std::string *header); |
| bool ReadClientHTTPVersion(std::string *header); |
| void ReadFromClient(InputData *data); |
| void ReadFromServer(InputData *data); |
| void SetClientResponse(int code, const std::string &type, |
| const std::string &content_type, |
| const std::string &message); |
| void SendClientError(int code, const std::string &error); |
| void StartIdleTimeout(); |
| void StartReceive(); |
| void StartTransmit(); |
| void StopClient(); |
| void WriteToClient(int fd); |
| void WriteToServer(int fd); |
| |
| // State held for the lifetime of the proxy. |
| State state_; |
| ConnectionRefPtr connection_; |
| scoped_ptr<Callback1<int>::Type> accept_callback_; |
| scoped_ptr<Callback2<bool, int>::Type> connect_completion_callback_; |
| scoped_ptr<Callback2<const Error &, const IPAddress &>::Type> |
| dns_client_callback_; |
| scoped_ptr<Callback1<InputData *>::Type> read_client_callback_; |
| scoped_ptr<Callback1<InputData *>::Type> read_server_callback_; |
| scoped_ptr<Callback1<int>::Type> write_client_callback_; |
| scoped_ptr<Callback1<int>::Type> write_server_callback_; |
| ScopedRunnableMethodFactory<HTTPProxy> task_factory_; |
| |
| // State held while proxy is started (even if no transaction is active). |
| scoped_ptr<IOHandler> accept_handler_; |
| EventDispatcher *dispatcher_; |
| scoped_ptr<DNSClient> dns_client_; |
| int proxy_port_; |
| int proxy_socket_; |
| scoped_ptr<AsyncConnection> server_async_connection_; |
| Sockets *sockets_; |
| |
| // State held while proxy is started and a transaction is active. |
| int client_socket_; |
| std::string client_method_; |
| std::string client_version_; |
| int server_port_; |
| int server_socket_; |
| bool is_route_requested_; |
| CancelableTask *idle_timeout_; |
| std::vector<std::string> client_headers_; |
| std::string server_hostname_; |
| ByteString client_data_; |
| ByteString server_data_; |
| scoped_ptr<IOHandler> read_client_handler_; |
| scoped_ptr<IOHandler> write_client_handler_; |
| scoped_ptr<IOHandler> read_server_handler_; |
| scoped_ptr<IOHandler> write_server_handler_; |
| |
| DISALLOW_COPY_AND_ASSIGN(HTTPProxy); |
| }; |
| |
| } // namespace shill |
| |
| #endif // SHILL_HTTP_PROXY_ |