// // Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef SHILL_HTTP_PROXY_H_ #define SHILL_HTTP_PROXY_H_ #include <memory> #include <string> #include <vector> #include <base/cancelable_callback.h> #include <base/memory/ref_counted.h> #include <base/memory/weak_ptr.h> #include "shill/net/byte_string.h" #include "shill/refptr_types.h" namespace shill { class AsyncConnection; class DNSClient; class Error; class EventDispatcher; struct 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 OnReadError(const std::string& error_msg); 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_; base::WeakPtrFactory<HTTPProxy> weak_ptr_factory_; base::Callback<void(int)> accept_callback_; base::Callback<void(bool, int)> connect_completion_callback_; base::Callback<void(const Error&, const IPAddress&)> dns_client_callback_; base::Callback<void(InputData*)> read_client_callback_; base::Callback<void(InputData*)> read_server_callback_; base::Callback<void(int)> write_client_callback_; base::Callback<void(int)> write_server_callback_; // State held while proxy is started (even if no transaction is active). std::unique_ptr<IOHandler> accept_handler_; EventDispatcher* dispatcher_; std::unique_ptr<DNSClient> dns_client_; int proxy_port_; int proxy_socket_; std::unique_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_; base::CancelableClosure idle_timeout_; base::CancelableClosure transaction_timeout_; std::vector<std::string> client_headers_; std::string server_hostname_; ByteString client_data_; ByteString server_data_; std::unique_ptr<IOHandler> read_client_handler_; std::unique_ptr<IOHandler> write_client_handler_; std::unique_ptr<IOHandler> read_server_handler_; std::unique_ptr<IOHandler> write_server_handler_; DISALLOW_COPY_AND_ASSIGN(HTTPProxy); }; } // namespace shill #endif // SHILL_HTTP_PROXY_H_