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.
5 #ifndef CHROME_FRAME_TEST_TEST_SERVER_H_
6 #define CHROME_FRAME_TEST_TEST_SERVER_H_
8 // Implementation of an HTTP server for tests.
9 // To instantiate the server, make sure you have a message loop on the
10 // current thread and then create an instance of the SimpleWebServer class.
11 // The server uses two basic concepts, a request and a response.
12 // The Response interface represents an item (e.g. a document) available from
13 // the server. A Request object represents a request from a client (e.g. a
14 // browser). There are several basic Response classes implemented in this file,
15 // all derived from the Response interface.
17 // Here's a simple example that starts a web server that can serve up
18 // a single document (http://<server.host()>:1337/foo).
19 // All other requests will get a 404.
21 // MessageLoopForUI loop;
22 // test_server::SimpleWebServer server(1337);
23 // test_server::SimpleResponse document("/foo", "Hello World!");
24 // test_server.AddResponse(&document);
25 // loop.MessageLoop::Run();
27 // To close the web server, just go to http://<server.host()>:1337/quit.
29 // All Response classes count how many times they have been accessed. Just
30 // call Response::accessed().
32 // To implement a custom response object (e.g. to match against a request
33 // based on some data, serve up dynamic content or take some action on the
34 // server), just inherit from one of the response classes or directly from the
35 // Response interface and add your response object to the server's list of
41 #include "base/basictypes.h"
42 #include "base/files/file_path.h"
43 #include "base/files/memory_mapped_file.h"
44 #include "base/message_loop.h"
45 #include "net/base/stream_listen_socket.h"
47 namespace test_server
{
51 Request() : content_length_(0) {
54 void ParseHeaders(const std::string
& headers
);
56 const std::string
& method() const {
60 const std::string
& path() const {
64 // Returns the argument section of a GET path.
65 // Note: does currently not work for POST request.
66 std::string
arguments() const {
68 std::string::size_type pos
= path_
.find('?');
69 if (pos
!= std::string::npos
)
70 ret
= path_
.substr(pos
+ 1);
74 const std::string
& headers() const {
78 const std::string
& content() const {
82 size_t content_length() const {
83 return content_length_
;
86 bool AllContentReceived() const {
87 return method_
.length() && content_
.size() >= content_length_
;
90 void OnDataReceived(const std::string
& data
);
98 size_t content_length_
;
101 DISALLOW_COPY_AND_ASSIGN(Request
);
104 // Manages request headers for a single request.
105 // For each successful request that's made, the server will keep an instance
106 // of this class so that they can be checked even after the server has been
110 explicit Connection(net::StreamListenSocket
* sock
) : socket_(sock
) {
116 bool IsSame(const net::StreamListenSocket
* socket
) const {
117 return socket_
== socket
;
120 const Request
& request() const {
128 void OnSocketClosed() {
133 scoped_refptr
<net::StreamListenSocket
> socket_
;
137 DISALLOW_COPY_AND_ASSIGN(Connection
);
140 // Abstract interface with default implementations for some of the methods and
141 // a counter for how many times the response object has served requests.
144 Response() : accessed_(0) {
147 virtual ~Response() {
150 // Returns true if this response object should be used for a given request.
151 virtual bool Matches(const Request
& r
) const = 0;
153 // Response objects can optionally supply their own HTTP headers, completely
154 // bypassing the default ones.
155 virtual bool GetCustomHeaders(std::string
* headers
) const {
159 // Optionally provide a content type. Return false if you don't specify
161 virtual bool GetContentType(std::string
* content_type
) const {
165 virtual size_t ContentLength() const {
169 virtual void WriteContents(net::StreamListenSocket
* socket
) const {
172 virtual void IncrementAccessCounter() {
176 size_t accessed() const {
184 DISALLOW_COPY_AND_ASSIGN(Response
);
187 // Partial implementation of Response that matches a request's path.
188 // This is just a convenience implementation for the boilerplate implementation
189 // of Matches(). Don't instantiate directly.
190 class ResponseForPath
: public Response
{
192 explicit ResponseForPath(const char* request_path
)
193 : request_path_(request_path
) {
196 virtual ~ResponseForPath();
198 virtual bool Matches(const Request
& r
) const {
199 std::string path
= r
.path();
200 std::string::size_type pos
= path
.find('?');
201 if (pos
!= std::string::npos
)
202 path
= path
.substr(0, pos
);
203 return path
.compare(request_path_
) == 0;
207 std::string request_path_
;
210 DISALLOW_COPY_AND_ASSIGN(ResponseForPath
);
213 // A very basic implementation of a response.
214 // A simple response matches a single document path on the server
215 // (e.g. "/foo") and returns a document in the form of a string.
216 class SimpleResponse
: public ResponseForPath
{
218 SimpleResponse(const char* request_path
, const std::string
& contents
)
219 : ResponseForPath(request_path
), contents_(contents
) {
222 virtual ~SimpleResponse();
224 virtual void WriteContents(net::StreamListenSocket
* socket
) const {
225 socket
->Send(contents_
.c_str(), contents_
.length(), false);
228 virtual size_t ContentLength() const {
229 return contents_
.length();
233 std::string contents_
;
236 DISALLOW_COPY_AND_ASSIGN(SimpleResponse
);
239 // To serve up files from the web server, create an instance of FileResponse
240 // and add it to the server's list of responses. The content type of the
241 // file will be determined by calling FindMimeFromData which examines the
242 // contents of the file and performs registry lookups.
243 class FileResponse
: public ResponseForPath
{
245 FileResponse(const char* request_path
, const base::FilePath
& file_path
)
246 : ResponseForPath(request_path
), file_path_(file_path
) {
249 virtual bool GetContentType(std::string
* content_type
) const;
250 virtual void WriteContents(net::StreamListenSocket
* socket
) const;
251 virtual size_t ContentLength() const;
254 base::FilePath file_path_
;
255 mutable scoped_ptr
<base::MemoryMappedFile
> file_
;
258 DISALLOW_COPY_AND_ASSIGN(FileResponse
);
261 // Returns a 302 (temporary redirect) to redirect the client from a path
262 // on the test server to a different URL.
263 class RedirectResponse
: public ResponseForPath
{
265 RedirectResponse(const char* request_path
, const std::string
& redirect_url
)
266 : ResponseForPath(request_path
), redirect_url_(redirect_url
) {
269 virtual bool GetCustomHeaders(std::string
* headers
) const;
272 std::string redirect_url_
;
275 DISALLOW_COPY_AND_ASSIGN(RedirectResponse
);
278 // typedef for a list of connections. Used by SimpleWebServer.
279 typedef std::list
<Connection
*> ConnectionList
;
281 // Implementation of a simple http server.
282 // Before creating an instance of the server, make sure the current thread
283 // has a message loop.
284 class SimpleWebServer
: public net::StreamListenSocket::Delegate
{
286 // Constructs a server listening at the given port on a local IPv4 address.
287 // An address on a NIC is preferred over the loopback address.
288 explicit SimpleWebServer(int port
);
290 // Constructs a server listening at the given address:port.
291 SimpleWebServer(const std::string
& address
, int port
);
292 virtual ~SimpleWebServer();
294 void AddResponse(Response
* response
);
296 // Ownership of response objects is by default assumed to be outside
297 // of the SimpleWebServer class.
298 // However, if the caller doesn't wish to maintain a list of response objects
299 // but rather let this class hold the only references to those objects,
300 // the caller can call this method to delete the objects as part of
301 // the cleanup process.
302 void DeleteAllResponses();
304 // StreamListenSocket::Delegate overrides.
305 virtual void DidAccept(net::StreamListenSocket
* server
,
306 net::StreamListenSocket
* connection
);
307 virtual void DidRead(net::StreamListenSocket
* connection
,
310 virtual void DidClose(net::StreamListenSocket
* sock
);
312 // Returns the host on which the server is listening. This is suitable for
313 // use in URLs for resources served by this instance.
314 const std::string
& host() const {
318 const ConnectionList
& connections() const {
323 class QuitResponse
: public SimpleResponse
{
326 : SimpleResponse("/quit", "So long and thanks for all the fish.") {
329 virtual void WriteContents(net::StreamListenSocket
* socket
) const {
330 SimpleResponse::WriteContents(socket
);
331 MessageLoop::current()->Quit();
335 Response
* FindResponse(const Request
& request
) const;
336 Connection
* FindConnection(const net::StreamListenSocket
* socket
) const;
339 scoped_refptr
<net::StreamListenSocket
> server_
;
340 ConnectionList connections_
;
341 std::list
<Response
*> responses_
;
345 void Construct(const std::string
& address
, int port
);
346 DISALLOW_COPY_AND_ASSIGN(SimpleWebServer
);
349 // Simple class holding incoming HTTP request. Can send the HTTP response
350 // at different rate - small chunks, on regular interval.
351 class ConfigurableConnection
: public base::RefCounted
<ConfigurableConnection
> {
354 enum Speed
{ IMMEDIATE
, DELAYED
, IMMEDIATE_HEADERS_DELAYED_CONTENT
};
355 SendOptions() : speed_(IMMEDIATE
), chunk_size_(0), timeout_(0) { }
356 SendOptions(Speed speed
, int chunk_size
, int64 timeout
)
357 : speed_(speed
), chunk_size_(chunk_size
), timeout_(timeout
) {
365 explicit ConfigurableConnection(net::StreamListenSocket
* sock
)
369 // Send HTTP response with provided |headers| and |content|. Appends
370 // "Context-Length:" header if the |content| is not empty.
371 void Send(const std::string
& headers
, const std::string
& content
);
373 // Send HTTP response with provided |headers| and |content|. Appends
374 // "Context-Length:" header if the |content| is not empty.
375 // Use the |options| to tweak the network speed behaviour.
376 void SendWithOptions(const std::string
& headers
, const std::string
& content
,
377 const SendOptions
& options
);
380 friend class HTTPTestServer
;
381 // Sends a chunk of the response and queues itself as a task for sending
382 // next chunk of |data_|.
385 // Closes the connection by releasing this instance's reference on its socket.
388 scoped_refptr
<net::StreamListenSocket
> socket_
;
390 SendOptions options_
;
394 DISALLOW_COPY_AND_ASSIGN(ConfigurableConnection
);
397 // Simple class used as a base class for mock webserver.
398 // Override virtual functions Get and Post and use passed ConfigurableConnection
399 // instance to send the response.
400 class HTTPTestServer
: public net::StreamListenSocket::Delegate
{
402 HTTPTestServer(int port
, const std::wstring
& address
,
403 base::FilePath root_dir
);
404 virtual ~HTTPTestServer();
406 // HTTP GET request is received. Override in derived classes.
407 // |connection| can be used to send the response.
408 virtual void Get(ConfigurableConnection
* connection
,
409 const std::wstring
& path
, const Request
& r
) = 0;
411 // HTTP POST request is received. Override in derived classes.
412 // |connection| can be used to send the response
413 virtual void Post(ConfigurableConnection
* connection
,
414 const std::wstring
& path
, const Request
& r
) = 0;
416 // Return the appropriate url with the specified path for this server.
417 std::wstring
Resolve(const std::wstring
& path
);
419 base::FilePath
root_dir() { return root_dir_
; }
423 std::wstring address_
;
424 base::FilePath root_dir_
;
427 typedef std::list
<scoped_refptr
<ConfigurableConnection
> > ConnectionList
;
428 ConnectionList::iterator
FindConnection(
429 const net::StreamListenSocket
* socket
);
430 scoped_refptr
<ConfigurableConnection
> ConnectionFromSocket(
431 const net::StreamListenSocket
* socket
);
433 // StreamListenSocket::Delegate overrides.
434 virtual void DidAccept(net::StreamListenSocket
* server
,
435 net::StreamListenSocket
* socket
);
436 virtual void DidRead(net::StreamListenSocket
* socket
,
437 const char* data
, int len
);
438 virtual void DidClose(net::StreamListenSocket
* socket
);
440 scoped_refptr
<net::StreamListenSocket
> server_
;
441 ConnectionList connection_list_
;
443 DISALLOW_COPY_AND_ASSIGN(HTTPTestServer
);
446 } // namespace test_server
448 #endif // CHROME_FRAME_TEST_TEST_SERVER_H_