embedded_test_server.h revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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/compiler_specific.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/weak_ptr.h"
16#include "base/threading/thread_checker.h"
17#include "googleurl/src/gurl.h"
18#include "net/socket/tcp_listen_socket.h"
19
20namespace net {
21namespace test_server {
22
23class HttpConnection;
24class HttpResponse;
25struct HttpRequest;
26
27// This class is required to be able to have composition instead of inheritance,
28class HttpListenSocket : public TCPListenSocket {
29 public:
30  HttpListenSocket(const SocketDescriptor socket_descriptor,
31                   StreamListenSocket::Delegate* delegate);
32  virtual void Listen();
33
34 private:
35  virtual ~HttpListenSocket();
36
37  base::ThreadChecker thread_checker_;
38};
39
40// Class providing an HTTP server for testing purpose. This is a basic server
41// providing only an essential subset of HTTP/1.1 protocol. Especially,
42// it assumes that the request syntax is correct. It *does not* support
43// a Chunked Transfer Encoding.
44//
45// The common use case is below:
46//
47// base::Thread io_thread_;
48// scoped_ptr<EmbeddedTestServer> test_server_;
49//
50// void SetUp() {
51//   base::Thread::Options thread_options;
52//   thread_options.message_loop_type = MessageLoop::TYPE_IO;
53//   ASSERT_TRUE(io_thread_.StartWithOptions(thread_options));
54//
55//   test_server_.reset(
56//       new EmbeddedTestServer(io_thread_.message_loop_proxy()));
57//   ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady());
58//   test_server_->RegisterRequestHandler(
59//       base::Bind(&FooTest::HandleRequest, base::Unretained(this)));
60// }
61//
62// scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
63//   GURL absolute_url = test_server_->GetURL(request.relative_url);
64//   if (absolute_url.path() != "/test")
65//     return scoped_ptr<HttpResponse>();
66//
67//   scoped_ptr<HttpResponse> http_response(new HttpResponse());
68//   http_response->set_code(test_server::SUCCESS);
69//   http_response->set_content("hello");
70//   http_response->set_content_type("text/plain");
71//   return http_response.Pass();
72// }
73//
74class EmbeddedTestServer : public StreamListenSocket::Delegate {
75 public:
76  typedef base::Callback<scoped_ptr<HttpResponse>(const HttpRequest& request)>
77      HandleRequestCallback;
78
79  // Creates a http test server. |io_thread| is a task runner
80  // with IO message loop, used as a backend thread.
81  // InitializeAndWaitUntilReady() must be called to start the server.
82  explicit EmbeddedTestServer(
83      const scoped_refptr<base::SingleThreadTaskRunner>& io_thread);
84  virtual ~EmbeddedTestServer();
85
86  // Initializes and waits until the server is ready to accept requests.
87  bool InitializeAndWaitUntilReady() WARN_UNUSED_RESULT;
88
89  // Shuts down the http server and waits until the shutdown is complete.
90  bool ShutdownAndWaitUntilComplete() WARN_UNUSED_RESULT;
91
92  // Checks if the server is started.
93  bool Started() const {
94    return listen_socket_.get() != NULL;
95  }
96
97  // Returns the base URL to the server, which looks like
98  // http://127.0.0.1:<port>/, where <port> is the actual port number used by
99  // the server.
100  const GURL& base_url() const { return base_url_; }
101
102  // Returns a URL to the server based on the given relative URL, which
103  // should start with '/'. For example: GetURL("/path?query=foo") =>
104  // http://127.0.0.1:<port>/path?query=foo.
105  GURL GetURL(const std::string& relative_url) const;
106
107  // Returns the port number used by the server.
108  int port() const { return port_; }
109
110  // The most general purpose method. Any request processing can be added using
111  // this method. Takes ownership of the object. The |callback| is called
112  // on UI thread.
113  void RegisterRequestHandler(const HandleRequestCallback& callback);
114
115 private:
116  // Initializes and starts the server. If initialization succeeds, Starts()
117  // will return true.
118  void InitializeOnIOThread();
119
120  // Shuts down the server.
121  void ShutdownOnIOThread();
122
123  // Handles a request when it is parsed. It passes the request to registed
124  // request handlers and sends a http response.
125  void HandleRequest(HttpConnection* connection,
126                     scoped_ptr<HttpRequest> request);
127
128  // StreamListenSocket::Delegate overrides:
129  virtual void DidAccept(StreamListenSocket* server,
130                         StreamListenSocket* connection) OVERRIDE;
131  virtual void DidRead(StreamListenSocket* connection,
132                       const char* data,
133                       int length) OVERRIDE;
134  virtual void DidClose(StreamListenSocket* connection) OVERRIDE;
135
136  HttpConnection* FindConnection(StreamListenSocket* socket);
137
138  scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
139
140  scoped_refptr<HttpListenSocket> listen_socket_;
141  int port_;
142  GURL base_url_;
143
144  // Owns the HttpConnection objects.
145  std::map<StreamListenSocket*, HttpConnection*> connections_;
146
147  // Vector of registered request handlers.
148  std::vector<HandleRequestCallback> request_handlers_;
149
150  // Note: This should remain the last member so it'll be destroyed and
151  // invalidate its weak pointers before any other members are destroyed.
152  base::WeakPtrFactory<EmbeddedTestServer> weak_factory_;
153
154  base::ThreadChecker thread_checker_;
155
156  DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServer);
157};
158
159}  // namespace test_servers
160}  // namespace net
161
162#endif  // NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_
163