embedded_test_server.cc revision f2477e01787aa58f445919b809d89e252beef54f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/test/embedded_test_server/embedded_test_server.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_path.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop/message_loop.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/run_loop.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string_util.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/stringprintf.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/test/embedded_test_server/http_connection.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/test/embedded_test_server/http_request.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/test/embedded_test_server/http_response.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/tools/fetch/http_listen_socket.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace test_server {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CustomHttpResponse : public HttpResponse {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CustomHttpResponse(const std::string& headers, const std::string& contents)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : headers_(headers), contents_(contents) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual std::string ToResponseString() const OVERRIDE {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return headers_ + "\r\n" + contents_;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string headers_;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string contents_;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CustomHttpResponse);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handles |request| by serving a file from under |server_root|.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<HttpResponse> HandleFileRequest(
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::FilePath& server_root,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HttpRequest& request) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is a test-only server. Ignore I/O thread restrictions.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::ScopedAllowIO allow_io;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Trim the first byte ('/').
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string request_path(request.relative_url.substr(1));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the query string if present.
57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  size_t query_pos = request_path.find('?');
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (query_pos != std::string::npos)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_path = request_path.substr(0, query_pos);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FilePath file_path(server_root.AppendASCII(request_path));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string file_contents;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::ReadFileToString(file_path, &file_contents))
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<HttpResponse>();
65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FilePath headers_path(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::PathExists(headers_path)) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string headers_contents;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!base::ReadFileToString(headers_path, &headers_contents))
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return scoped_ptr<HttpResponse>();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<CustomHttpResponse> http_response(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new CustomHttpResponse(headers_contents, file_contents));
76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return http_response.PassAs<HttpResponse>();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http_response->set_code(HTTP_OK);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http_response->set_content(file_contents);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return http_response.PassAs<HttpResponse>();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   StreamListenSocket::Delegate* delegate)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : TCPListenSocket(socket_descriptor, delegate) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpListenSocket::Listen() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TCPListenSocket::Listen();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpListenSocket::~HttpListenSocket() {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochEmbeddedTestServer::EmbeddedTestServer()
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : port_(-1),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      weak_factory_(this) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EmbeddedTestServer::~EmbeddedTestServer() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Started() && !ShutdownAndWaitUntilComplete()) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Thread::Options thread_options;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_thread_.reset(new base::Thread("EmbeddedTestServer io thread"));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(io_thread_->StartWithOptions(thread_options));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PostTaskToIOThreadAndWait(base::Bind(
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &EmbeddedTestServer::InitializeOnIOThread, base::Unretained(this)))) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Started() && base_url_.is_valid();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PostTaskToIOThreadAndWait(base::Bind(
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this)));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::InitializeOnIOThread() {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!Started());
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SocketDescriptor socket_descriptor =
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_descriptor == kInvalidSocket)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listen_socket_.reset(new HttpListenSocket(socket_descriptor, this));
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listen_socket_->Listen();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPEndPoint address;
152ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int result = listen_socket_->GetLocalAddress(&address);
153ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (result == OK) {
154ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    base_url_ = GURL(std::string("http://") + address.ToString());
155ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  } else {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::ShutdownOnIOThread() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listen_socket_.reset();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteContainerPairSecondPointers(connections_.begin(),
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       connections_.end());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connections_.clear();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               scoped_ptr<HttpRequest> request) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool request_handled = false;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (size_t i = 0; i < request_handlers_.size(); ++i) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<HttpResponse> response =
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_handlers_[i].Run(*request.get());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response.get()) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connection->SendResponse(response.Pass());
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_handled = true;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!request_handled) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Request not handled. Returning 404: "
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << request->relative_url;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    not_found_response->set_code(HTTP_NOT_FOUND);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connection->SendResponse(
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        not_found_response.PassAs<HttpResponse>());
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop the connection, since we do not support multiple requests per
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // connection.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connections_.erase(connection->socket_.get());
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete connection;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Started()) << "You must start the server first.";
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */))
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << relative_url;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base_url_.Resolve(relative_url);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::ServeFilesFromDirectory(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::FilePath& directory) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterRequestHandler(base::Bind(&HandleFileRequest, directory));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::RegisterRequestHandler(
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HandleRequestCallback& callback) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_handlers_.push_back(callback);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::DidAccept(
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StreamListenSocket* server,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<StreamListenSocket> connection) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpConnection* http_connection = new HttpConnection(
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connection.Pass(),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&EmbeddedTestServer::HandleRequest,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr()));
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(szym): Make HttpConnection the StreamListenSocket delegate.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connections_[http_connection->socket_.get()] = http_connection;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const char* data,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int length) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (http_connection == NULL) {
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    LOG(WARNING) << "Unknown connection.";
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http_connection->ReceiveData(std::string(data, length));
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_connection == NULL) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Unknown connection.";
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete http_connection;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connections_.erase(connection);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpConnection* EmbeddedTestServer::FindConnection(
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StreamListenSocket* socket) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<StreamListenSocket*, HttpConnection*>::iterator it =
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connections_.find(socket);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == connections_.end()) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
263ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return it->second;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EmbeddedTestServer::PostTaskToIOThreadAndWait(
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& closure) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that PostTaskAndReply below requires base::MessageLoopProxy::current()
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to return a loop for posting the reply task. However, in order to make
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // EmbeddedTestServer universally usable, it needs to cope with the situation
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // where it's running on a thread on which a message loop is not (yet)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // available or as has been destroyed already.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To handle this situation, create temporary message loop to support the
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PostTaskAndReply operation if the current thread as no message loop.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::MessageLoop> temporary_loop;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::MessageLoop::current())
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    temporary_loop.reset(new base::MessageLoop());
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::RunLoop run_loop;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!io_thread_->message_loop_proxy()->PostTaskAndReply(
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE, closure, run_loop.QuitClosure())) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  run_loop.Run();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
291ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}  // namespace test_server
292ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}  // namespace net
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)