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