embedded_test_server.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/embedded_test_server.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/file_util.h"
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/files/file_path.h"
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/message_loop/message_loop.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/path_service.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/run_loop.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/ip_endpoint.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/net_errors.h"
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_connection.h"
20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_request.h"
21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_response.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/tools/fetch/http_listen_socket.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace net {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace test_server {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass CustomHttpResponse : public HttpResponse {
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CustomHttpResponse(const std::string& headers, const std::string& contents)
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : headers_(headers), contents_(contents) {
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual std::string ToResponseString() const OVERRIDE {
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return headers_ + "\r\n" + contents_;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string headers_;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string contents_;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DISALLOW_COPY_AND_ASSIGN(CustomHttpResponse);
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Handles |request| by serving a file from under |server_root|.
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)scoped_ptr<HttpResponse> HandleFileRequest(
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::FilePath& server_root,
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const HttpRequest& request) {
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This is a test-only server. Ignore I/O thread restrictions.
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::ThreadRestrictions::ScopedAllowIO allow_io;
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Trim the first byte ('/').
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string request_path(request.relative_url.substr(1));
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Remove the query string if present.
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t query_pos = request_path.find('?');
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (query_pos != std::string::npos)
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    request_path = request_path.substr(0, query_pos);
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath file_path(server_root.AppendASCII(request_path));
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string file_contents;
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::ReadFileToString(file_path, &file_contents))
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return scoped_ptr<HttpResponse>();
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath headers_path(
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (base::PathExists(headers_path)) {
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::string headers_contents;
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!base::ReadFileToString(headers_path, &headers_contents))
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return scoped_ptr<HttpResponse>();
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_ptr<CustomHttpResponse> http_response(
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        new CustomHttpResponse(headers_contents, file_contents));
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return http_response.PassAs<HttpResponse>();
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  http_response->set_code(HTTP_OK);
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  http_response->set_content(file_contents);
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return http_response.PassAs<HttpResponse>();
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor,
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                   StreamListenSocket::Delegate* delegate)
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    : TCPListenSocket(socket_descriptor, delegate) {
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HttpListenSocket::Listen() {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  TCPListenSocket::Listen();
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpListenSocket::~HttpListenSocket() {
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)EmbeddedTestServer::EmbeddedTestServer()
1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    : io_thread_("EmbeddedTestServer io thread"),
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      port_(-1),
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::Thread::Options thread_options;
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CHECK(io_thread_.StartWithOptions(thread_options));
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)EmbeddedTestServer::~EmbeddedTestServer() {
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (Started() && !ShutdownAndWaitUntilComplete()) {
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!PostTaskToIOThreadAndWait(base::Bind(
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          &EmbeddedTestServer::InitializeOnIOThread, base::Unretained(this)))) {
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return Started() && base_url_.is_valid();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() {
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return PostTaskToIOThreadAndWait(base::Bind(
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this)));
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::InitializeOnIOThread() {
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!Started());
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SocketDescriptor socket_descriptor =
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_);
145424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (socket_descriptor == kInvalidSocket)
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  listen_socket_.reset(new HttpListenSocket(socket_descriptor, this));
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  listen_socket_->Listen();
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  IPEndPoint address;
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int result = listen_socket_->GetLocalAddress(&address);
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (result == OK) {
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base_url_ = GURL(std::string("http://") + address.ToString());
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::ShutdownOnIOThread() {
1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  listen_socket_.reset();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(connections_.begin(),
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       connections_.end());
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.clear();
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               scoped_ptr<HttpRequest> request) {
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool request_handled = false;
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < request_handlers_.size(); ++i) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<HttpResponse> response =
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request_handlers_[i].Run(*request.get());
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response.get()) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection->SendResponse(response.Pass());
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      request_handled = true;
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!request_handled) {
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(WARNING) << "Request not handled. Returning 404: "
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << request->relative_url;
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    not_found_response->set_code(HTTP_NOT_FOUND);
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    connection->SendResponse(
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        not_found_response.PassAs<HttpResponse>());
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Drop the connection, since we do not support multiple requests per
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // connection.
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.erase(connection->socket_.get());
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete connection;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(Started()) << "You must start the server first.";
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */))
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << relative_url;
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base_url_.Resolve(relative_url);
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EmbeddedTestServer::ServeFilesFromDirectory(
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::FilePath& directory) {
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  RegisterRequestHandler(base::Bind(&HandleFileRequest, directory));
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::RegisterRequestHandler(
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const HandleRequestCallback& callback) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_handlers_.push_back(callback);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void EmbeddedTestServer::DidAccept(
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    StreamListenSocket* server,
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<StreamListenSocket> connection) {
2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = new HttpConnection(
22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      connection.Pass(),
224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&EmbeddedTestServer::HandleRequest,
225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // TODO(szym): Make HttpConnection the StreamListenSocket delegate.
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  connections_[http_connection->socket_.get()] = http_connection;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
230b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const char* data,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         int length) {
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (http_connection == NULL) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Unknown connection.";
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  http_connection->ReceiveData(std::string(data, length));
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (http_connection == NULL) {
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Unknown connection.";
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete http_connection;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.erase(connection);
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
255b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)HttpConnection* EmbeddedTestServer::FindConnection(
256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    StreamListenSocket* socket) {
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::map<StreamListenSocket*, HttpConnection*>::iterator it =
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connections_.find(socket);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == connections_.end()) {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return it->second;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool EmbeddedTestServer::PostTaskToIOThreadAndWait(
26858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const base::Closure& closure) {
26958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Note that PostTaskAndReply below requires base::MessageLoopProxy::current()
27058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // to return a loop for posting the reply task. However, in order to make
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // EmbeddedTestServer universally usable, it needs to cope with the situation
27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // where it's running on a thread on which a message loop is not (yet)
27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // available or as has been destroyed already.
27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //
27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // To handle this situation, create temporary message loop to support the
27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // PostTaskAndReply operation if the current thread as no message loop.
27758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<base::MessageLoop> temporary_loop;
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::MessageLoop::current())
27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    temporary_loop.reset(new base::MessageLoop());
28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::RunLoop run_loop;
2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!io_thread_.message_loop_proxy()->PostTaskAndReply(
2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          FROM_HERE, closure, run_loop.QuitClosure())) {
28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  run_loop.Run();
28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace test_server
292b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace net
293