From acc9a6def1c4c7d8b54149667e0c476d0c85a8f4 Mon Sep 17 00:00:00 2001 From: "mbelshe@google.com" Date: Wed, 6 May 2009 00:17:50 +0000 Subject: A utility driver for doing client/server HTTP transaction tests. This is an initial codebase - there is a lot of work to do. But I wanted to get an initial version checked in. http://crbug.com/6754 Review URL: http://codereview.chromium.org/99333 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15360 0039d316-1c4b-4281-b951-d872f2087c98 --- net/tools/fetch/fetch_client.cc | 185 +++++++++++++++++++++ net/tools/fetch/fetch_server.cc | 54 +++++++ net/tools/fetch/http_listen_socket.cc | 241 ++++++++++++++++++++++++++++ net/tools/fetch/http_listen_socket.h | 55 +++++++ net/tools/fetch/http_server.cc | 13 ++ net/tools/fetch/http_server.h | 25 +++ net/tools/fetch/http_server_request_info.h | 24 +++ net/tools/fetch/http_server_response_info.h | 40 +++++ net/tools/fetch/http_session.cc | 34 ++++ net/tools/fetch/http_session.h | 27 ++++ 10 files changed, 698 insertions(+) create mode 100644 net/tools/fetch/fetch_client.cc create mode 100644 net/tools/fetch/fetch_server.cc create mode 100644 net/tools/fetch/http_listen_socket.cc create mode 100644 net/tools/fetch/http_listen_socket.h create mode 100644 net/tools/fetch/http_server.cc create mode 100644 net/tools/fetch/http_server.h create mode 100644 net/tools/fetch/http_server_request_info.h create mode 100644 net/tools/fetch/http_server_response_info.h create mode 100644 net/tools/fetch/http_session.cc create mode 100644 net/tools/fetch/http_session.h (limited to 'net/tools/fetch') diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc new file mode 100644 index 0000000..a8917e6 --- /dev/null +++ b/net/tools/fetch/fetch_client.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/singleton.h" +#include "base/stats_counters.h" +#include "base/string_util.h" +#include "net/base/completion_callback.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/http/http_cache.h" +#include "net/http/http_network_layer.h" +#include "net/http/http_request_info.h" +#include "net/http/http_transaction.h" +#include "net/proxy/proxy_service.h" + +void usage(const char* program_name) { + printf("usage: %s --url= [--n=] [--stats] [--use_cache]\n", + program_name); + exit(1); +} + +// Test Driver +class Driver { + public: + Driver() + : clients_(0) {} + + void ClientStarted() { clients_++; } + void ClientStopped() { + if (!--clients_) { + MessageLoop::current()->Quit(); + } + } + + private: + int clients_; +}; + +// A network client +class Client { + public: + Client(net::HttpTransactionFactory* factory, const std::string& url) : + url_(url), + transaction_(factory->CreateTransaction()), + buffer_(new net::IOBuffer(kBufferSize)), + ALLOW_THIS_IN_INITIALIZER_LIST( + connect_callback_(this, &Client::OnConnectComplete)), + ALLOW_THIS_IN_INITIALIZER_LIST( + read_callback_(this, &Client::OnReadComplete)) { + buffer_->AddRef(); + driver_->ClientStarted(); + request_info_.url = url_; + request_info_.method = "GET"; + int state = transaction_->Start(&request_info_, &connect_callback_); + DCHECK(state == net::ERR_IO_PENDING); + }; + + private: + void OnConnectComplete(int result) { + // Do work here. + int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); + if (state == net::ERR_IO_PENDING) + return; // IO has started. + if (state < 0) + return; // ERROR! + OnReadComplete(state); + } + + void OnReadComplete(int result) { + if (result == 0) { + OnRequestComplete(result); + return; + } + + // Deal with received data here. + static StatsCounter bytes_read("FetchClient.bytes_read"); + bytes_read.Add(result); + + // Issue a read for more data. + int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); + if (state == net::ERR_IO_PENDING) + return; // IO has started. + if (state < 0) + return; // ERROR! + OnReadComplete(state); + } + + void OnRequestComplete(int result) { + static StatsCounter requests("FetchClient.requests"); + requests.Increment(); + driver_->ClientStopped(); + printf("."); + } + + static const int kBufferSize = (16 * 1024); + GURL url_; + net::HttpRequestInfo request_info_; + scoped_ptr transaction_; + scoped_ptr buffer_; + net::CompletionCallbackImpl connect_callback_; + net::CompletionCallbackImpl read_callback_; + Singleton driver_; +}; + +int main(int argc, char**argv) { + base::AtExitManager exit; + StatsTable table("fetchclient", 50, 1000); + table.set_current(&table); + + CommandLine::Init(0, NULL); + const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + std::string url = WideToASCII(parsed_command_line.GetSwitchValue(L"url")); + if (!url.length()) + usage(argv[0]); + int client_limit = 1; + if (parsed_command_line.HasSwitch(L"n")) + StringToInt(WideToASCII(parsed_command_line.GetSwitchValue(L"n")), + &client_limit); + bool use_cache = parsed_command_line.HasSwitch(L"use-cache"); + + // Do work here. + MessageLoop loop; + + scoped_ptr proxy_service(net::ProxyService::CreateNull()); + net::HttpTransactionFactory* factory = NULL; + if (use_cache) + factory = new net::HttpCache(proxy_service.get(), 0); + else + factory = new net::HttpNetworkLayer(proxy_service.get()); + + { + StatsCounterTimer driver_time("FetchClient.total_time"); + StatsScope scope(driver_time); + + Client** clients = new Client*[client_limit]; + for (int i = 0; i < client_limit; i++) + clients[i] = new Client(factory, url); + + MessageLoop::current()->Run(); + } + + // Print Statistics here. + int num_clients = table.GetCounterValue("c:FetchClient.requests"); + int test_time = table.GetCounterValue("t:FetchClient.total_time"); + int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read"); + + printf("\n"); + printf("Clients : %d\n", num_clients); + printf("Time : %dms\n", test_time); + printf("Bytes Read : %d\n", bytes_read); + if (test_time > 0) { + const char *units = "bps"; + double bps = static_cast(bytes_read * 8) / + (static_cast(test_time) / 1000.0); + + if (bps > (1024*1024)) { + bps /= (1024*1024); + units = "Mbps"; + } else if (bps > 1024) { + bps /= 1024; + units = "Kbps"; + } + printf("Bandwidth : %.2f%s\n", bps, units); + } + + if (parsed_command_line.HasSwitch(L"stats")) { + // Dump the stats table. + printf("\n"); + int counter_max = table.GetMaxCounters(); + for (int index=0; index < counter_max; index++) { + std::string name(table.GetRowName(index)); + if (name.length() > 0) { + int value = table.GetRowValue(index); + printf("%s:\t%d\n", name.c_str(), value); + + } + } + printf("\n"); + } + return 0; +} diff --git a/net/tools/fetch/fetch_server.cc b/net/tools/fetch/fetch_server.cc new file mode 100644 index 0000000..ed284f9 --- /dev/null +++ b/net/tools/fetch/fetch_server.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/singleton.h" +#include "base/stats_counters.h" +#include "net/base/completion_callback.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/base/winsock_init.h" +#include "net/http/http_network_layer.h" +#include "net/http/http_request_info.h" +#include "net/http/http_transaction.h" +#include "net/proxy/proxy_service.h" +#include "net/tools/fetch/http_server.h" + +void usage(const char* program_name) { + printf("usage: %s\n", program_name); + exit(-1); +} + +int main(int argc, char**argv) { + base::AtExitManager exit; + StatsTable table("fetchserver", 50, 1000); + table.set_current(&table); + + net::EnsureWinsockInit(); + + CommandLine::Init(0, NULL); + const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + + // Do work here. + MessageLoop loop; + HttpServer server("", 80); // TODO(mbelshe): make port configurable + MessageLoop::current()->Run(); + + if (parsed_command_line.HasSwitch(L"stats")) { + // Dump the stats table. + printf("\n"); + int counter_max = table.GetMaxCounters(); + for (int index=0; index < counter_max; index++) { + std::string name(table.GetRowName(index)); + if (name.length() > 0) { + int value = table.GetRowValue(index); + printf("%s:\t%d\n", name.c_str(), value); + } + } + printf("\n"); + } + +} diff --git a/net/tools/fetch/http_listen_socket.cc b/net/tools/fetch/http_listen_socket.cc new file mode 100644 index 0000000..e64a5f2 --- /dev/null +++ b/net/tools/fetch/http_listen_socket.cc @@ -0,0 +1,241 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/compiler_specific.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "net/tools/fetch/http_listen_socket.h" +#include "net/tools/fetch/http_server_request_info.h" +#include "net/tools/fetch/http_server_response_info.h" + +// must run in the IO thread +HttpListenSocket::HttpListenSocket(SOCKET s, + HttpListenSocket::Delegate* delegate) + : ALLOW_THIS_IN_INITIALIZER_LIST(ListenSocket(s, this)), + delegate_(delegate) { +} + +// must run in the IO thread +HttpListenSocket::~HttpListenSocket() { +} + +void HttpListenSocket::Accept() { + SOCKET conn = ListenSocket::Accept(socket_); + DCHECK(conn != INVALID_SOCKET); + if (conn == INVALID_SOCKET) { + // TODO + } else { + scoped_refptr sock = + new HttpListenSocket(conn, delegate_); + // it's up to the delegate to AddRef if it wants to keep it around + DidAccept(this, sock); + } +} + +HttpListenSocket* HttpListenSocket::Listen(const std::string& ip, int port, + HttpListenSocket::Delegate* delegate) { + SOCKET s = ListenSocket::Listen(ip, port); + if (s == INVALID_SOCKET) { + // TODO (ibrar): error handling + } else { + HttpListenSocket *serv = new HttpListenSocket(s, delegate); + serv->Listen(); + return serv; + } + return NULL; +} + +// +// HTTP Request Parser +// This HTTP request parser uses a simple state machine to quickly parse +// through the headers. The parser is not 100% complete, as it is designed +// for use in this simple test driver. +// +// Known issues: +// - does not handle whitespace on first HTTP line correctly. Expects +// a single space between the method/url and url/protocol. + +// Input character types. +enum header_parse_inputs { + INPUT_SPACE, + INPUT_CR, + INPUT_LF, + INPUT_COLON, + INPUT_DEFAULT, + MAX_INPUTS +}; + +// Parser states. +enum header_parse_states { + ST_METHOD, // Receiving the method + ST_URL, // Receiving the URL + ST_PROTO, // Receiving the protocol + ST_HEADER, // Starting a Request Header + ST_NAME, // Receiving a request header name + ST_SEPARATOR, // Receiving the separator between header name and value + ST_VALUE, // Receiving a request header value + ST_DONE, // Parsing is complete and successful + ST_ERR, // Parsing encountered invalid syntax. + MAX_STATES +}; + +// State transition table +int parser_state[MAX_STATES][MAX_INPUTS] = { +/* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD }, +/* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL }, +/* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO }, +/* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR }, +/* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_NAME }, +/* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_VALUE }, +/* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, +/* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, +/* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } +}; + +// Convert an input character to the parser's input token. +int charToInput(char ch) { + switch(ch) { + case ' ': + return INPUT_SPACE; + case '\r': + return INPUT_CR; + case '\n': + return INPUT_LF; + case ':': + return INPUT_COLON; + } + return INPUT_DEFAULT; +} + +HttpServerRequestInfo* HttpListenSocket::ParseHeaders() { + int pos = 0; + int data_len = recv_data_.length(); + int state = ST_METHOD; + HttpServerRequestInfo* info = new HttpServerRequestInfo(); + std::string buffer; + std::string header_name; + std::string header_value; + while (pos < data_len) { + char ch = recv_data_[pos++]; + int input = charToInput(ch); + int next_state = parser_state[state][input]; + + bool transition = (next_state != state); + if (transition) { + // Do any actions based on state transitions. + switch (state) { + case ST_METHOD: + info->method = buffer; + buffer.clear(); + break; + case ST_URL: + info->url = GURL(buffer); + buffer.clear(); + break; + case ST_PROTO: + // TODO(mbelshe): Deal better with parsing protocol. + DCHECK(buffer == "HTTP/1.1"); + buffer.clear(); + break; + case ST_NAME: + header_name = buffer; + buffer.clear(); + break; + case ST_VALUE: + header_value = buffer; + // TODO(mbelshe): Deal better with duplicate headers + DCHECK(info->headers.find(header_name) == info->headers.end()); + info->headers[header_name] = header_value; + buffer.clear(); + break; + } + state = next_state; + } else { + // Do any actions based on current state + switch (state) { + case ST_METHOD: + case ST_URL: + case ST_PROTO: + case ST_VALUE: + case ST_NAME: + buffer.append(&ch, 1); + break; + case ST_DONE: + recv_data_ = recv_data_.substr(pos); + return info; + case ST_ERR: + delete info; + return NULL; + } + } + } + // No more characters, but we haven't finished parsing yet. + delete info; + return NULL; +} + +void HttpListenSocket::DidAccept(ListenSocket* server, + ListenSocket* connection) { + connection->AddRef(); +} + +void HttpListenSocket::DidRead(ListenSocket* connection, + const std::string& data) { + recv_data_ += data; + while (recv_data_.length()) { + HttpServerRequestInfo* request = ParseHeaders(); + if (!request) + break; + delegate_->OnRequest(this, request); + delete request; + } +} + +void HttpListenSocket::DidClose(ListenSocket* sock) { + sock->Release(); +} + +// Convert the numeric status code to a string. +// e.g. 200 -> "200 OK" +std::string ServerStatus(int code) { + switch(code) { + case 200: + return std::string("200 OK"); + // TODO(mbelshe): handle other codes. + } + NOTREACHED(); + return std::string(); +} + +void HttpListenSocket::Respond(HttpServerResponseInfo* info, + std::string& data) { + std::string response; + + // status line + response = info->protocol + " "; + response += ServerStatus(info->status); + response += "\r\n"; + + // standard headers + if (info->content_type.length()) + response += "Content-type: " + info->content_type + "\r\n"; + + if (info->content_length > 0) + response += "Content-length: " + IntToString(info->content_length) + + "\r\n"; + + if (info->connection_close) + response += "Connection: close\r\n"; + + // TODO(mbelshe): support additional headers + + // End of headers + response += "\r\n"; + + // Add data + response += data; + + // Write it all out. + this->Send(response, false); +} diff --git a/net/tools/fetch/http_listen_socket.h b/net/tools/fetch/http_listen_socket.h new file mode 100644 index 0000000..f31df20 --- /dev/null +++ b/net/tools/fetch/http_listen_socket.h @@ -0,0 +1,55 @@ +// Copyright (c) 2009 The Chromium 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 NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_ +#define NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_ + +#include "base/message_loop.h" +#include "net/base/listen_socket.h" + +class HttpServerRequestInfo; +class HttpServerResponseInfo; + +// Implements a simple HTTP listen socket on top of the raw socket interface. +class HttpListenSocket : public ListenSocket, + public ListenSocket::ListenSocketDelegate { +public: + class Delegate { + public: + virtual void OnRequest(HttpListenSocket* connection, + HttpServerRequestInfo* info) = 0; + }; + + static HttpListenSocket* Listen(const std::string& ip, int port, + HttpListenSocket::Delegate* delegate); + virtual ~HttpListenSocket(); + + void Listen() { ListenSocket::Listen(); } + virtual void Accept(); + + // Send a server response. + // TODO(mbelshe): make this capable of non-ascii data. + void Respond(HttpServerResponseInfo* info, std::string& data); + + // ListenSocketDelegate + virtual void DidAccept(ListenSocket* server, ListenSocket* connection); + virtual void DidRead(ListenSocket* connection, const std::string& data); + virtual void DidClose(ListenSocket* sock); + +private: + static const int kReadBufSize = 16 * 1024; + HttpListenSocket(SOCKET s, HttpListenSocket::Delegate* del); + + // Expects the raw data to be stored in recv_data_. If parsing is successful, + // will remove the data parsed from recv_data_, leaving only the unused + // recv data. + HttpServerRequestInfo* ParseHeaders(); + + HttpListenSocket::Delegate* delegate_; + std::string recv_data_; + + DISALLOW_EVIL_CONSTRUCTORS(HttpListenSocket); +}; + +#endif // NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_ diff --git a/net/tools/fetch/http_server.cc b/net/tools/fetch/http_server.cc new file mode 100644 index 0000000..7102805 --- /dev/null +++ b/net/tools/fetch/http_server.cc @@ -0,0 +1,13 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/tools/fetch/http_server.h" +#include "net/tools/fetch/http_listen_socket.h" + +HttpServer::HttpServer(std::string ip, int port) + : ALLOW_THIS_IN_INITIALIZER_LIST(session_(new HttpSession(ip, port))) { +} + +HttpServer::~HttpServer() { +} diff --git a/net/tools/fetch/http_server.h b/net/tools/fetch/http_server.h new file mode 100644 index 0000000..6b8e719 --- /dev/null +++ b/net/tools/fetch/http_server.h @@ -0,0 +1,25 @@ +// Copyright (c) 2009 The Chromium 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 NET_BASE_TOOLS_HTTP_SERVER_H_ +#define NET_BASE_TOOLS_HTTP_SERVER_H_ + +#include "base/basictypes.h" +#include "net/tools/fetch/http_session.h" + +// Implements a simple, single-threaded HttpServer. +// Right now, this class implements no functionality above and beyond +// the HttpSession. +class HttpServer { +public: + HttpServer(std::string ip, int port); + ~HttpServer(); + +private: + scoped_ptr session_; + DISALLOW_EVIL_CONSTRUCTORS(HttpServer); +}; + +#endif // NET_BASE_TOOLS_HTTP_SERVER_H_ + diff --git a/net/tools/fetch/http_server_request_info.h b/net/tools/fetch/http_server_request_info.h new file mode 100644 index 0000000..7af161f --- /dev/null +++ b/net/tools/fetch/http_server_request_info.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 The Chromium 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 NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_ +#define NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_ + +#include + +#include "net/http/http_request_info.h" + +// Meta information about an HTTP request. +// This is geared toward servers in that it keeps a map of the headers and +// values rather than just a list of header strings (which net::HttpRequestInfo +// does). +class HttpServerRequestInfo : public net::HttpRequestInfo { + public: + HttpServerRequestInfo() : net::HttpRequestInfo() {} + + // A map of the names -> values for HTTP headers. + std::map headers; +}; + +#endif // NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_ diff --git a/net/tools/fetch/http_server_response_info.h b/net/tools/fetch/http_server_response_info.h new file mode 100644 index 0000000..03015c8 --- /dev/null +++ b/net/tools/fetch/http_server_response_info.h @@ -0,0 +1,40 @@ +// Copyright (c) 2009 The Chromium 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 NET_HTTP_HTTP_RESPONSE_INFO_H__ +#define NET_HTTP_HTTP_RESPONSE_INFO_H__ + +#include +#include + +// Meta information about a server response. +class HttpServerResponseInfo { + public: + HttpServerResponseInfo() + : status(200), content_length(0), connection_close(false) { + } + + // The response protocol + std::string protocol; + + // The status code + int status; + + // The server identifier + std::string server_name; + + // The content type + std::string content_type; + + // The content length + int content_length; + + // Should we close the connection + bool connection_close; + + // Additional response headers + std::map headers; +}; + +#endif // NET_HTTP_HTTP_RESPONSE_INFO_H__ diff --git a/net/tools/fetch/http_session.cc b/net/tools/fetch/http_session.cc new file mode 100644 index 0000000..f740289 --- /dev/null +++ b/net/tools/fetch/http_session.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/tools/fetch/http_session.h" +#include "net/tools/fetch/http_server_response_info.h" + +HttpSession::HttpSession(const std::string& ip, int port) + : ALLOW_THIS_IN_INITIALIZER_LIST( + socket_(HttpListenSocket::Listen(ip, port, this))) { +} + +HttpSession::~HttpSession() { +} + +void HttpSession::OnRequest(HttpListenSocket* connection, + HttpServerRequestInfo* info) { + // TODO(mbelshe): Make this function more interesting. + + // Generate a 10KB sequence of data. + static std::string data; + if (data.length() == 0) { + while (data.length() < (10 * 1024)) + data += 'a' + (rand() % 26); + } + + HttpServerResponseInfo response_info; + response_info.protocol = "HTTP/1.1"; + response_info.status = 200; + response_info.content_type = "text/plain"; + response_info.content_length = data.length(); + + connection->Respond(&response_info, data); +} diff --git a/net/tools/fetch/http_session.h b/net/tools/fetch/http_session.h new file mode 100644 index 0000000..2289b30 --- /dev/null +++ b/net/tools/fetch/http_session.h @@ -0,0 +1,27 @@ +// Copyright (c) 2009 The Chromium 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 NET_BASE_TOOLS_HTTP_SESSION_H_ +#define NET_BASE_TOOLS_HTTP_SESSION_H_ + +#include "base/basictypes.h" +#include "net/http/http_request_info.h" +#include "net/tools/fetch/http_listen_socket.h" + +// An HttpSession encapsulates a server-side HTTP listen socket. +class HttpSession : HttpListenSocket::Delegate { +public: + HttpSession(const std::string& ip, int port); + virtual ~HttpSession(); + + virtual void OnRequest(HttpListenSocket* connection, + HttpServerRequestInfo* info); + +private: + scoped_ptr socket_; + DISALLOW_EVIL_CONSTRUCTORS(HttpSession); +}; + +#endif // NET_BASE_TOOLS_HTTP_SESSION_H_ + -- cgit v1.1