1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_ 6 #define NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_ 7 8 #include <map> 9 #include <string> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/callback.h" 14 #include "base/compiler_specific.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/threading/thread.h" 18 #include "base/threading/thread_checker.h" 19 #include "net/socket/tcp_listen_socket.h" 20 #include "url/gurl.h" 21 22 namespace base { 23 class FilePath; 24 } 25 26 namespace net { 27 namespace test_server { 28 29 class HttpConnection; 30 class HttpResponse; 31 struct HttpRequest; 32 33 // This class is required to be able to have composition instead of inheritance, 34 class HttpListenSocket : public TCPListenSocket { 35 public: 36 HttpListenSocket(const SocketDescriptor socket_descriptor, 37 StreamListenSocket::Delegate* delegate); 38 virtual ~HttpListenSocket(); 39 virtual void Listen(); 40 41 private: 42 friend class EmbeddedTestServer; 43 44 // Detaches the current from |thread_checker_|. 45 void DetachFromThread(); 46 47 base::ThreadChecker thread_checker_; 48 }; 49 50 // Class providing an HTTP server for testing purpose. This is a basic server 51 // providing only an essential subset of HTTP/1.1 protocol. Especially, 52 // it assumes that the request syntax is correct. It *does not* support 53 // a Chunked Transfer Encoding. 54 // 55 // The common use case for unit tests is below: 56 // 57 // void SetUp() { 58 // test_server_.reset(new EmbeddedTestServer()); 59 // ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady()); 60 // test_server_->RegisterRequestHandler( 61 // base::Bind(&FooTest::HandleRequest, base::Unretained(this))); 62 // } 63 // 64 // scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { 65 // GURL absolute_url = test_server_->GetURL(request.relative_url); 66 // if (absolute_url.path() != "/test") 67 // return scoped_ptr<HttpResponse>(); 68 // 69 // scoped_ptr<HttpResponse> http_response(new HttpResponse()); 70 // http_response->set_code(test_server::SUCCESS); 71 // http_response->set_content("hello"); 72 // http_response->set_content_type("text/plain"); 73 // return http_response.Pass(); 74 // } 75 // 76 // For a test that spawns another process such as browser_tests, it is 77 // suggested to call InitializeAndWaitUntilReady in SetUpOnMainThread after 78 // the process is spawned. If you have to do it before the process spawns, 79 // you need to stop the server's thread so that there is no no other 80 // threads running while spawning the process. To do so, please follow 81 // the following example: 82 // 83 // void SetUp() { 84 // ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 85 // // EmbeddedTestServer spawns a thread to initialize socket. 86 // // Stop the thread in preparation for fork and exec. 87 // embedded_test_server()->StopThread(); 88 // ... 89 // InProcessBrowserTest::SetUp(); 90 // } 91 // 92 // void SetUpOnMainThread() { 93 // embedded_test_server()->RestartThreadAndListen(); 94 // } 95 // 96 class EmbeddedTestServer : public StreamListenSocket::Delegate { 97 public: 98 typedef base::Callback<scoped_ptr<HttpResponse>( 99 const HttpRequest& request)> HandleRequestCallback; 100 101 // Creates a http test server. InitializeAndWaitUntilReady() must be called 102 // to start the server. 103 EmbeddedTestServer(); 104 virtual ~EmbeddedTestServer(); 105 106 // Initializes and waits until the server is ready to accept requests. 107 bool InitializeAndWaitUntilReady() WARN_UNUSED_RESULT; 108 109 // Shuts down the http server and waits until the shutdown is complete. 110 bool ShutdownAndWaitUntilComplete() WARN_UNUSED_RESULT; 111 112 // Checks if the server is started. 113 bool Started() const { 114 return listen_socket_.get() != NULL; 115 } 116 117 // Returns the base URL to the server, which looks like 118 // http://127.0.0.1:<port>/, where <port> is the actual port number used by 119 // the server. 120 const GURL& base_url() const { return base_url_; } 121 122 // Returns a URL to the server based on the given relative URL, which 123 // should start with '/'. For example: GetURL("/path?query=foo") => 124 // http://127.0.0.1:<port>/path?query=foo. 125 GURL GetURL(const std::string& relative_url) const; 126 127 // Returns the port number used by the server. 128 int port() const { return port_; } 129 130 // Registers request handler which serves files from |directory|. 131 // For instance, a request to "/foo.html" is served by "foo.html" under 132 // |directory|. Files under sub directories are also handled in the same way 133 // (i.e. "/foo/bar.html" is served by "foo/bar.html" under |directory|). 134 void ServeFilesFromDirectory(const base::FilePath& directory); 135 136 // The most general purpose method. Any request processing can be added using 137 // this method. Takes ownership of the object. The |callback| is called 138 // on UI thread. 139 void RegisterRequestHandler(const HandleRequestCallback& callback); 140 141 // Stops IO thread that handles http requests. 142 void StopThread(); 143 144 // Restarts IO thread and listen on the socket. 145 void RestartThreadAndListen(); 146 147 private: 148 void StartThread(); 149 150 // Initializes and starts the server. If initialization succeeds, Starts() 151 // will return true. 152 void InitializeOnIOThread(); 153 void ListenOnIOThread(); 154 155 // Shuts down the server. 156 void ShutdownOnIOThread(); 157 158 // Handles a request when it is parsed. It passes the request to registed 159 // request handlers and sends a http response. 160 void HandleRequest(HttpConnection* connection, 161 scoped_ptr<HttpRequest> request); 162 163 // StreamListenSocket::Delegate overrides: 164 virtual void DidAccept(StreamListenSocket* server, 165 scoped_ptr<StreamListenSocket> connection) OVERRIDE; 166 virtual void DidRead(StreamListenSocket* connection, 167 const char* data, 168 int length) OVERRIDE; 169 virtual void DidClose(StreamListenSocket* connection) OVERRIDE; 170 171 HttpConnection* FindConnection(StreamListenSocket* socket); 172 173 // Posts a task to the |io_thread_| and waits for a reply. 174 bool PostTaskToIOThreadAndWait( 175 const base::Closure& closure) WARN_UNUSED_RESULT; 176 177 scoped_ptr<base::Thread> io_thread_; 178 179 scoped_ptr<HttpListenSocket> listen_socket_; 180 int port_; 181 GURL base_url_; 182 183 // Owns the HttpConnection objects. 184 std::map<StreamListenSocket*, HttpConnection*> connections_; 185 186 // Vector of registered request handlers. 187 std::vector<HandleRequestCallback> request_handlers_; 188 189 // Note: This should remain the last member so it'll be destroyed and 190 // invalidate its weak pointers before any other members are destroyed. 191 base::WeakPtrFactory<EmbeddedTestServer> weak_factory_; 192 193 base::ThreadChecker thread_checker_; 194 195 DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServer); 196 }; 197 198 } // namespace test_servers 199 } // namespace net 200 201 #endif // NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_ 202