summaryrefslogtreecommitdiffstats
path: root/net/tools
diff options
context:
space:
mode:
authormbelshe@google.com <mbelshe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 00:17:50 +0000
committermbelshe@google.com <mbelshe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 00:17:50 +0000
commitacc9a6def1c4c7d8b54149667e0c476d0c85a8f4 (patch)
tree2028d25f0ea02000d572de224e91bc5201510baa /net/tools
parent914b40352efbf491c6bc98e624ad9cf00c7d9b79 (diff)
downloadchromium_src-acc9a6def1c4c7d8b54149667e0c476d0c85a8f4.zip
chromium_src-acc9a6def1c4c7d8b54149667e0c476d0c85a8f4.tar.gz
chromium_src-acc9a6def1c4c7d8b54149667e0c476d0c85a8f4.tar.bz2
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
Diffstat (limited to 'net/tools')
-rw-r--r--net/tools/fetch/fetch_client.cc185
-rw-r--r--net/tools/fetch/fetch_server.cc54
-rw-r--r--net/tools/fetch/http_listen_socket.cc241
-rw-r--r--net/tools/fetch/http_listen_socket.h55
-rw-r--r--net/tools/fetch/http_server.cc13
-rw-r--r--net/tools/fetch/http_server.h25
-rw-r--r--net/tools/fetch/http_server_request_info.h24
-rw-r--r--net/tools/fetch/http_server_response_info.h40
-rw-r--r--net/tools/fetch/http_session.cc34
-rw-r--r--net/tools/fetch/http_session.h27
10 files changed, 698 insertions, 0 deletions
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=<url> [--n=<clients>] [--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<net::HttpTransaction> transaction_;
+ scoped_ptr<net::IOBuffer> buffer_;
+ net::CompletionCallbackImpl<Client> connect_callback_;
+ net::CompletionCallbackImpl<Client> read_callback_;
+ Singleton<Driver> 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<net::ProxyService> 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<StatsCounterTimer> 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<float>(bytes_read * 8) /
+ (static_cast<float>(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("<stats>\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("</stats>\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("<stats>\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("</stats>\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<HttpListenSocket> 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<HttpSession> 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 <string>
+
+#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<std::string, std::string> 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 <string>
+#include <map>
+
+// 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<std::string, std::string> 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<HttpListenSocket> socket_;
+ DISALLOW_EVIL_CONSTRUCTORS(HttpSession);
+};
+
+#endif // NET_BASE_TOOLS_HTTP_SESSION_H_
+