embedded_test_server.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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)
102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)EmbeddedTestServer::EmbeddedTestServer(
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const scoped_refptr<base::SingleThreadTaskRunner>& io_thread)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : io_thread_(io_thread),
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      port_(-1),
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(io_thread_.get());
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)EmbeddedTestServer::~EmbeddedTestServer() {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (Started() && !ShutdownAndWaitUntilComplete()) {
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!PostTaskToIOThreadAndWait(base::Bind(
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          &EmbeddedTestServer::InitializeOnIOThread, base::Unretained(this)))) {
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return Started() && base_url_.is_valid();
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() {
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return PostTaskToIOThreadAndWait(base::Bind(
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this)));
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::InitializeOnIOThread() {
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!Started());
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SocketDescriptor socket_descriptor =
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_);
143424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (socket_descriptor == kInvalidSocket)
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  listen_socket_.reset(new HttpListenSocket(socket_descriptor, this));
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  listen_socket_->Listen();
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  IPEndPoint address;
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int result = listen_socket_->GetLocalAddress(&address);
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (result == OK) {
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base_url_ = GURL(std::string("http://") + address.ToString());
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::ShutdownOnIOThread() {
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  listen_socket_.reset();
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(connections_.begin(),
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       connections_.end());
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.clear();
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               scoped_ptr<HttpRequest> request) {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool request_handled = false;
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < request_handlers_.size(); ++i) {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<HttpResponse> response =
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request_handlers_[i].Run(*request.get());
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response.get()) {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection->SendResponse(response.Pass());
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      request_handled = true;
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!request_handled) {
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(WARNING) << "Request not handled. Returning 404: "
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << request->relative_url;
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    not_found_response->set_code(HTTP_NOT_FOUND);
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    connection->SendResponse(
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        not_found_response.PassAs<HttpResponse>());
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Drop the connection, since we do not support multiple requests per
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // connection.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.erase(connection->socket_.get());
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete connection;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */))
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << relative_url;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base_url_.Resolve(relative_url);
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EmbeddedTestServer::ServeFilesFromDirectory(
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::FilePath& directory) {
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  RegisterRequestHandler(base::Bind(&HandleFileRequest, directory));
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::RegisterRequestHandler(
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const HandleRequestCallback& callback) {
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_handlers_.push_back(callback);
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void EmbeddedTestServer::DidAccept(
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    StreamListenSocket* server,
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<StreamListenSocket> connection) {
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = new HttpConnection(
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      connection.Pass(),
221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&EmbeddedTestServer::HandleRequest,
222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // TODO(szym): Make HttpConnection the StreamListenSocket delegate.
22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  connections_[http_connection->socket_.get()] = http_connection;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
227b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const char* data,
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         int length) {
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (http_connection == NULL) {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Unknown connection.";
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  http_connection->ReceiveData(std::string(data, length));
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (http_connection == NULL) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Unknown connection.";
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete http_connection;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.erase(connection);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)HttpConnection* EmbeddedTestServer::FindConnection(
253b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    StreamListenSocket* socket) {
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::map<StreamListenSocket*, HttpConnection*>::iterator it =
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connections_.find(socket);
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == connections_.end()) {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return it->second;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool EmbeddedTestServer::PostTaskToIOThreadAndWait(
26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const base::Closure& closure) {
26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Note that PostTaskAndReply below requires base::MessageLoopProxy::current()
26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // to return a loop for posting the reply task. However, in order to make
26858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // EmbeddedTestServer universally usable, it needs to cope with the situation
26958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // where it's running on a thread on which a message loop is not (yet)
27058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // available or as has been destroyed already.
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  //
27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // To handle this situation, create temporary message loop to support the
27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // PostTaskAndReply operation if the current thread as no message loop.
27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<base::MessageLoop> temporary_loop;
27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::MessageLoop::current())
27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    temporary_loop.reset(new base::MessageLoop());
27758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::RunLoop run_loop;
27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!io_thread_->PostTaskAndReply(FROM_HERE, closure, run_loop.QuitClosure()))
28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  run_loop.Run();
28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
28358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace test_server
287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace net
288