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" 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/files/file_path.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/message_loop/message_loop.h" 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/path_service.h" 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/process/process_metrics.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/run_loop.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/ip_endpoint.h" 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/net_errors.h" 20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_connection.h" 21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_request.h" 22b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_response.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) 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HttpListenSocket::ListenOnIOThread() { 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(thread_checker_.CalledOnValidThread()); 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if !defined(OS_POSIX) 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // This method may be called after the IO thread is changed, thus we need to 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // call |WatchSocket| again to make sure it listens on the current IO thread. 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Only needed for non POSIX platforms, since on POSIX platforms 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // StreamListenSocket::Listen already calls WatchSocket inside the function. 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci WatchSocket(WAITING_ACCEPT); 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Listen(); 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpListenSocket::~HttpListenSocket() { 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void HttpListenSocket::DetachFromThread() { 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) thread_checker_.DetachFromThread(); 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)EmbeddedTestServer::EmbeddedTestServer() 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : port_(-1), 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_factory_(this) { 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)EmbeddedTestServer::~EmbeddedTestServer() { 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (Started() && !ShutdownAndWaitUntilComplete()) { 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LOG(ERROR) << "EmbeddedTestServer failed to shut down."; 12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::InitializeAndWaitUntilReady() { 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StartThread(); 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!PostTaskToIOThreadAndWait(base::Bind( 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &EmbeddedTestServer::InitializeOnIOThread, base::Unretained(this)))) { 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return Started() && base_url_.is_valid(); 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void EmbeddedTestServer::StopThread() { 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(io_thread_ && io_thread_->IsRunning()); 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(OS_LINUX) 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const int thread_count = 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::GetNumberOfThreads(base::GetCurrentProcessHandle()); 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) io_thread_->Stop(); 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) io_thread_.reset(); 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) thread_checker_.DetachFromThread(); 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) listen_socket_->DetachFromThread(); 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(OS_LINUX) 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Busy loop to wait for thread count to decrease. This is needed because 157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // pthread_join does not guarantee that kernel stat is updated when it 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // returns. Thus, GetNumberOfThreads does not immediately reflect the stopped 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // thread and hits the thread number DCHECK in render_sandbox_host_linux.cc 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // in browser_tests. 161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) while (thread_count == 162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::GetNumberOfThreads(base::GetCurrentProcessHandle())) { 163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::PlatformThread::YieldCurrentThread(); 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void EmbeddedTestServer::RestartThreadAndListen() { 169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StartThread(); 170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CHECK(PostTaskToIOThreadAndWait(base::Bind( 171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) &EmbeddedTestServer::ListenOnIOThread, base::Unretained(this)))); 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 174b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return PostTaskToIOThreadAndWait(base::Bind( 17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this))); 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void EmbeddedTestServer::StartThread() { 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(!io_thread_.get()); 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Thread::Options thread_options; 184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) thread_options.message_loop_type = base::MessageLoop::TYPE_IO; 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) io_thread_.reset(new base::Thread("EmbeddedTestServer io thread")); 186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CHECK(io_thread_->StartWithOptions(thread_options)); 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::InitializeOnIOThread() { 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!Started()); 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SocketDescriptor socket_descriptor = 19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_); 195424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (socket_descriptor == kInvalidSocket) 19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 19858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) listen_socket_.reset(new HttpListenSocket(socket_descriptor, this)); 19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) listen_socket_->Listen(); 20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) IPEndPoint address; 20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int result = listen_socket_->GetLocalAddress(&address); 20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result == OK) { 20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base_url_ = GURL(std::string("http://") + address.ToString()); 20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } else { 20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void EmbeddedTestServer::ListenOnIOThread() { 211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(Started()); 2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci listen_socket_->ListenOnIOThread(); 214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::ShutdownOnIOThread() { 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) listen_socket_.reset(); 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STLDeleteContainerPairSecondPointers(connections_.begin(), 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connections_.end()); 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connections_.clear(); 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::HandleRequest(HttpConnection* connection, 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<HttpRequest> request) { 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool request_handled = false; 23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < request_handlers_.size(); ++i) { 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<HttpResponse> response = 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_handlers_[i].Run(*request.get()); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (response.get()) { 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connection->SendResponse(response.Pass()); 23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) request_handled = true; 23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) break; 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!request_handled) { 24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LOG(WARNING) << "Request not handled. Returning 404: " 24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) << request->relative_url; 24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse); 245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch not_found_response->set_code(HTTP_NOT_FOUND); 24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) connection->SendResponse( 24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) not_found_response.PassAs<HttpResponse>()); 24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Drop the connection, since we do not support multiple requests per 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // connection. 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connections_.erase(connection->socket_.get()); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete connection; 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const { 2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(Started()) << "You must start the server first."; 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */)) 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << relative_url; 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base_url_.Resolve(relative_url); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EmbeddedTestServer::ServeFilesFromDirectory( 26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const base::FilePath& directory) { 26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) RegisterRequestHandler(base::Bind(&HandleFileRequest, directory)); 26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::RegisterRequestHandler( 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const HandleRequestCallback& callback) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_handlers_.push_back(callback); 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void EmbeddedTestServer::DidAccept( 27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) StreamListenSocket* server, 27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scoped_ptr<StreamListenSocket> connection) { 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HttpConnection* http_connection = new HttpConnection( 27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) connection.Pass(), 280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Bind(&EmbeddedTestServer::HandleRequest, 281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) weak_factory_.GetWeakPtr())); 28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // TODO(szym): Make HttpConnection the StreamListenSocket delegate. 28358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) connections_[http_connection->socket_.get()] = http_connection; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidRead(StreamListenSocket* connection, 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char* data, 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int length) { 289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HttpConnection* http_connection = FindConnection(connection); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (http_connection == NULL) { 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(WARNING) << "Unknown connection."; 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) http_connection->ReceiveData(std::string(data, length)); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void EmbeddedTestServer::DidClose(StreamListenSocket* connection) { 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HttpConnection* http_connection = FindConnection(connection); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (http_connection == NULL) { 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(WARNING) << "Unknown connection."; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete http_connection; 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connections_.erase(connection); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)HttpConnection* EmbeddedTestServer::FindConnection( 312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) StreamListenSocket* socket) { 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) std::map<StreamListenSocket*, HttpConnection*>::iterator it = 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connections_.find(socket); 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (it == connections_.end()) { 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return it->second; 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 32358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool EmbeddedTestServer::PostTaskToIOThreadAndWait( 32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::Closure& closure) { 32558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Note that PostTaskAndReply below requires base::MessageLoopProxy::current() 32658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // to return a loop for posting the reply task. However, in order to make 32758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // EmbeddedTestServer universally usable, it needs to cope with the situation 32858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // where it's running on a thread on which a message loop is not (yet) 32958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // available or as has been destroyed already. 33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // 33158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // To handle this situation, create temporary message loop to support the 33258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // PostTaskAndReply operation if the current thread as no message loop. 33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scoped_ptr<base::MessageLoop> temporary_loop; 33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!base::MessageLoop::current()) 33558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) temporary_loop.reset(new base::MessageLoop()); 33658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 33758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::RunLoop run_loop; 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!io_thread_->message_loop_proxy()->PostTaskAndReply( 3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) FROM_HERE, closure, run_loop.QuitClosure())) { 34058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return false; 3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) run_loop.Run(); 34358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return true; 34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 34658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace test_server 348b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} // namespace net 349