embedded_test_server.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/files/file_path.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/file_util.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/path_service.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/run_loop.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/ip_endpoint.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/net_errors.h"
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_connection.h"
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_request.h"
20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_response.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/tools/fetch/http_listen_socket.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace net {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace test_server {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass CustomHttpResponse : public HttpResponse {
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CustomHttpResponse(const std::string& headers, const std::string& contents)
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : headers_(headers), contents_(contents) {
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual std::string ToResponseString() const OVERRIDE {
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return headers_ + "\r\n" + contents_;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string headers_;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string contents_;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DISALLOW_COPY_AND_ASSIGN(CustomHttpResponse);
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Handles |request| by serving a file from under |server_root|.
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)scoped_ptr<HttpResponse> HandleFileRequest(
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::FilePath& server_root,
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const HttpRequest& request) {
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This is a test-only server. Ignore I/O thread restrictions.
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::ThreadRestrictions::ScopedAllowIO allow_io;
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Trim the first byte ('/').
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string request_path(request.relative_url.substr(1));
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Remove the query string if present.
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t query_pos = request_path.find('?');
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (query_pos != std::string::npos)
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    request_path = request_path.substr(0, query_pos);
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath file_path(server_root.AppendASCII(request_path));
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string file_contents;
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!file_util::ReadFileToString(file_path, &file_contents))
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return scoped_ptr<HttpResponse>();
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath headers_path(
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (base::PathExists(headers_path)) {
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::string headers_contents;
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!file_util::ReadFileToString(headers_path, &headers_contents))
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return scoped_ptr<HttpResponse>();
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_ptr<CustomHttpResponse> http_response(
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        new CustomHttpResponse(headers_contents, file_contents));
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return http_response.PassAs<HttpResponse>();
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  http_response->set_code(HTTP_OK);
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  http_response->set_content(file_contents);
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return http_response.PassAs<HttpResponse>();
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor,
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                   StreamListenSocket::Delegate* delegate)
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    : TCPListenSocket(socket_descriptor, delegate) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HttpListenSocket::Listen() {
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  TCPListenSocket::Listen();
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpListenSocket::~HttpListenSocket() {
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)EmbeddedTestServer::EmbeddedTestServer(
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const scoped_refptr<base::SingleThreadTaskRunner>& io_thread)
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : io_thread_(io_thread),
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      port_(-1),
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(io_thread_.get());
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)EmbeddedTestServer::~EmbeddedTestServer() {
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (Started() && !ShutdownAndWaitUntilComplete()) {
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::RunLoop run_loop;
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!io_thread_->PostTaskAndReply(
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          FROM_HERE,
124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          base::Bind(&EmbeddedTestServer::InitializeOnIOThread,
125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                     base::Unretained(this)),
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          run_loop.QuitClosure())) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  run_loop.Run();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return Started() && base_url_.is_valid();
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() {
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::RunLoop run_loop;
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!io_thread_->PostTaskAndReply(
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          FROM_HERE,
140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          base::Bind(&EmbeddedTestServer::ShutdownOnIOThread,
141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                     base::Unretained(this)),
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          run_loop.QuitClosure())) {
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  run_loop.Run();
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::InitializeOnIOThread() {
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!Started());
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SocketDescriptor socket_descriptor =
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_);
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (socket_descriptor == TCPListenSocket::kInvalidSocket)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  listen_socket_ = new HttpListenSocket(socket_descriptor, this);
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  listen_socket_->Listen();
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  IPEndPoint address;
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int result = listen_socket_->GetLocalAddress(&address);
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (result == OK) {
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base_url_ = GURL(std::string("http://") + address.ToString());
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::ShutdownOnIOThread() {
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listen_socket_ = NULL;  // Release the listen socket.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(connections_.begin(),
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       connections_.end());
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.clear();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               scoped_ptr<HttpRequest> request) {
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool request_handled = false;
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < request_handlers_.size(); ++i) {
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<HttpResponse> response =
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request_handlers_[i].Run(*request.get());
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response.get()) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection->SendResponse(response.Pass());
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      request_handled = true;
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!request_handled) {
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(WARNING) << "Request not handled. Returning 404: "
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << request->relative_url;
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    not_found_response->set_code(HTTP_NOT_FOUND);
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    connection->SendResponse(
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        not_found_response.PassAs<HttpResponse>());
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Drop the connection, since we do not support multiple requests per
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // connection.
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.erase(connection->socket_.get());
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete connection;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */))
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << relative_url;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base_url_.Resolve(relative_url);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EmbeddedTestServer::ServeFilesFromDirectory(
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::FilePath& directory) {
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  RegisterRequestHandler(base::Bind(&HandleFileRequest, directory));
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::RegisterRequestHandler(
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const HandleRequestCallback& callback) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_handlers_.push_back(callback);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
227b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidAccept(StreamListenSocket* server,
228b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           StreamListenSocket* connection) {
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = new HttpConnection(
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection,
233b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&EmbeddedTestServer::HandleRequest,
234b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_[connection] = http_connection;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
238b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const char* data,
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         int length) {
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)  http_connection->ReceiveData(std::string(data, length));
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
251b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HttpConnection* http_connection = FindConnection(connection);
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (http_connection == NULL) {
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Unknown connection.";
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete http_connection;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connections_.erase(connection);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)HttpConnection* EmbeddedTestServer::FindConnection(
264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    StreamListenSocket* socket) {
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_thread_->BelongsToCurrentThread());
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::map<StreamListenSocket*, HttpConnection*>::iterator it =
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connections_.find(socket);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == connections_.end()) {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return it->second;
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace test_server
276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace net
277