embedded_test_server.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
15870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent// Use of this source code is governed by a BSD-style license that can be 35870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent// found in the LICENSE file. 45870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 55870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "net/test/embedded_test_server/embedded_test_server.h" 65870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 75870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "base/bind.h" 85870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "base/run_loop.h" 95870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "base/stl_util.h" 105870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "base/string_util.h" 115870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "base/stringprintf.h" 125870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "net/test/embedded_test_server/http_connection.h" 135870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "net/test/embedded_test_server/http_request.h" 145870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "net/test/embedded_test_server/http_response.h" 155870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent#include "net/tools/fetch/http_listen_socket.h" 165870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 175870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentnamespace net { 185870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentnamespace test_server { 195870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 205870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentnamespace { 215870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 225870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentconst int kPort = 8040; 235870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentconst char kIp[] = "127.0.0.1"; 245870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentconst int kRetries = 10; 255870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 265870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent// Callback to handle requests with default predefined response for requests 275870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent// matching the address |url|. 285870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentscoped_ptr<HttpResponse> HandleDefaultRequest(const GURL& url, 295870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent const HttpResponse& response, 305870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent const HttpRequest& request) { 315870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent const GURL request_url = url.Resolve(request.relative_url); 325870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent if (url.path() != request_url.path()) 335870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent return scoped_ptr<HttpResponse>(NULL); 345870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent return scoped_ptr<HttpResponse>(new HttpResponse(response)); 355870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 365870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 375870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} // namespace 385870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 395870e071aabfbde0d570142acf440ab4dca97e04Eric LaurentHttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor, 405870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent StreamListenSocket::Delegate* delegate) 415870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent : TCPListenSocket(socket_descriptor, delegate) { 425870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 435870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 445870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 455870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentvoid HttpListenSocket::Listen() { 465870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 475870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent TCPListenSocket::Listen(); 485870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 495870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 505870e071aabfbde0d570142acf440ab4dca97e04Eric LaurentHttpListenSocket::~HttpListenSocket() { 515870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 525870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 535870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 545870e071aabfbde0d570142acf440ab4dca97e04Eric LaurentEmbeddedTestServer::EmbeddedTestServer( 555870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent const scoped_refptr<base::SingleThreadTaskRunner>& io_thread) 565870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent : io_thread_(io_thread), 575870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent port_(-1), 585870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent weak_factory_(this) { 595870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(io_thread_); 605870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 615870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 625870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 635870e071aabfbde0d570142acf440ab4dca97e04Eric LaurentEmbeddedTestServer::~EmbeddedTestServer() { 645870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 655870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 665870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 675870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentbool EmbeddedTestServer::InitializeAndWaitUntilReady() { 685870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 695870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 705870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent base::RunLoop run_loop; 715870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent if (!io_thread_->PostTaskAndReply( 725870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent FROM_HERE, 735870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent base::Bind(&EmbeddedTestServer::InitializeOnIOThread, 745870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent base::Unretained(this)), 755870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent run_loop.QuitClosure())) { 765870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent return false; 775870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent } 785870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent run_loop.Run(); 795870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 805870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent return Started(); 815870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent} 825870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 835870e071aabfbde0d570142acf440ab4dca97e04Eric Laurentbool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { 845870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent DCHECK(thread_checker_.CalledOnValidThread()); 855870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent 865870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent base::RunLoop run_loop; 875870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent if (!io_thread_->PostTaskAndReply( 885870e071aabfbde0d570142acf440ab4dca97e04Eric Laurent FROM_HERE, 89 base::Bind(&EmbeddedTestServer::ShutdownOnIOThread, 90 base::Unretained(this)), 91 run_loop.QuitClosure())) { 92 return false; 93 } 94 run_loop.Run(); 95 96 return true; 97} 98 99void EmbeddedTestServer::InitializeOnIOThread() { 100 DCHECK(io_thread_->BelongsToCurrentThread()); 101 DCHECK(!Started()); 102 103 int retries_left = kRetries + 1; 104 int try_port = kPort; 105 106 while (retries_left > 0) { 107 SocketDescriptor socket_descriptor = TCPListenSocket::CreateAndBind( 108 kIp, 109 try_port); 110 if (socket_descriptor != TCPListenSocket::kInvalidSocket) { 111 listen_socket_ = new HttpListenSocket(socket_descriptor, this); 112 listen_socket_->Listen(); 113 base_url_ = GURL(base::StringPrintf("http://%s:%d", kIp, try_port)); 114 port_ = try_port; 115 break; 116 } 117 retries_left--; 118 try_port++; 119 } 120} 121 122void EmbeddedTestServer::ShutdownOnIOThread() { 123 DCHECK(io_thread_->BelongsToCurrentThread()); 124 125 listen_socket_ = NULL; // Release the listen socket. 126 STLDeleteContainerPairSecondPointers(connections_.begin(), 127 connections_.end()); 128 connections_.clear(); 129} 130 131void EmbeddedTestServer::HandleRequest(HttpConnection* connection, 132 scoped_ptr<HttpRequest> request) { 133 DCHECK(io_thread_->BelongsToCurrentThread()); 134 135 for (size_t i = 0; i < request_handlers_.size(); ++i) { 136 scoped_ptr<HttpResponse> response = 137 request_handlers_[i].Run(*request.get()); 138 if (response.get()) { 139 connection->SendResponse(response.Pass()); 140 return; 141 } 142 } 143 144 LOG(WARNING) << "Request not handled. Returning 404: " 145 << request->relative_url; 146 scoped_ptr<HttpResponse> not_found_response(new HttpResponse()); 147 not_found_response->set_code(NOT_FOUND); 148 connection->SendResponse(not_found_response.Pass()); 149 150 // Drop the connection, since we do not support multiple requests per 151 // connection. 152 connections_.erase(connection->socket_.get()); 153 delete connection; 154} 155 156GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const { 157 DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */)) 158 << relative_url; 159 return base_url_.Resolve(relative_url); 160} 161 162void EmbeddedTestServer::RegisterRequestHandler( 163 const HandleRequestCallback& callback) { 164 request_handlers_.push_back(callback); 165} 166 167void EmbeddedTestServer::DidAccept(StreamListenSocket* server, 168 StreamListenSocket* connection) { 169 DCHECK(io_thread_->BelongsToCurrentThread()); 170 171 HttpConnection* http_connection = new HttpConnection( 172 connection, 173 base::Bind(&EmbeddedTestServer::HandleRequest, 174 weak_factory_.GetWeakPtr())); 175 connections_[connection] = http_connection; 176} 177 178void EmbeddedTestServer::DidRead(StreamListenSocket* connection, 179 const char* data, 180 int length) { 181 DCHECK(io_thread_->BelongsToCurrentThread()); 182 183 HttpConnection* http_connection = FindConnection(connection); 184 if (http_connection == NULL) { 185 LOG(WARNING) << "Unknown connection."; 186 return; 187 } 188 http_connection->ReceiveData(std::string(data, length)); 189} 190 191void EmbeddedTestServer::DidClose(StreamListenSocket* connection) { 192 DCHECK(io_thread_->BelongsToCurrentThread()); 193 194 HttpConnection* http_connection = FindConnection(connection); 195 if (http_connection == NULL) { 196 LOG(WARNING) << "Unknown connection."; 197 return; 198 } 199 delete http_connection; 200 connections_.erase(connection); 201} 202 203HttpConnection* EmbeddedTestServer::FindConnection( 204 StreamListenSocket* socket) { 205 DCHECK(io_thread_->BelongsToCurrentThread()); 206 207 std::map<StreamListenSocket*, HttpConnection*>::iterator it = 208 connections_.find(socket); 209 if (it == connections_.end()) { 210 return NULL; 211 } 212 return it->second; 213} 214 215} // namespace test_server 216} // namespace net 217