| OLD | NEW |
| (Empty) |
| 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 CHROME_FRAME_TEST_TEST_SERVER_H_ | |
| 6 #define CHROME_FRAME_TEST_TEST_SERVER_H_ | |
| 7 | |
| 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. | |
| 16 // | |
| 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. | |
| 20 // | |
| 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(); | |
| 26 // | |
| 27 // To close the web server, just go to http://<server.host()>:1337/quit. | |
| 28 // | |
| 29 // All Response classes count how many times they have been accessed. Just | |
| 30 // call Response::accessed(). | |
| 31 // | |
| 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 | |
| 36 // response objects. | |
| 37 | |
| 38 #include <list> | |
| 39 #include <string> | |
| 40 | |
| 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/message_loop.h" | |
| 45 #include "net/socket/stream_listen_socket.h" | |
| 46 | |
| 47 namespace test_server { | |
| 48 | |
| 49 class Request { | |
| 50 public: | |
| 51 Request() : content_length_(0) { | |
| 52 } | |
| 53 | |
| 54 void ParseHeaders(const std::string& headers); | |
| 55 | |
| 56 const std::string& method() const { | |
| 57 return method_; | |
| 58 } | |
| 59 | |
| 60 const std::string& path() const { | |
| 61 return path_; | |
| 62 } | |
| 63 | |
| 64 // Returns the argument section of a GET path. | |
| 65 // Note: does currently not work for POST request. | |
| 66 std::string arguments() const { | |
| 67 std::string ret; | |
| 68 std::string::size_type pos = path_.find('?'); | |
| 69 if (pos != std::string::npos) | |
| 70 ret = path_.substr(pos + 1); | |
| 71 return ret; | |
| 72 } | |
| 73 | |
| 74 const std::string& headers() const { | |
| 75 return headers_; | |
| 76 } | |
| 77 | |
| 78 const std::string& content() const { | |
| 79 return content_; | |
| 80 } | |
| 81 | |
| 82 size_t content_length() const { | |
| 83 return content_length_; | |
| 84 } | |
| 85 | |
| 86 bool AllContentReceived() const { | |
| 87 return method_.length() && content_.size() >= content_length_; | |
| 88 } | |
| 89 | |
| 90 void OnDataReceived(const std::string& data); | |
| 91 | |
| 92 protected: | |
| 93 std::string method_; | |
| 94 std::string path_; | |
| 95 std::string version_; | |
| 96 std::string headers_; | |
| 97 std::string content_; | |
| 98 size_t content_length_; | |
| 99 | |
| 100 private: | |
| 101 DISALLOW_COPY_AND_ASSIGN(Request); | |
| 102 }; | |
| 103 | |
| 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 | |
| 107 // shut down. | |
| 108 class Connection { | |
| 109 public: | |
| 110 explicit Connection(scoped_ptr<net::StreamListenSocket> sock) | |
| 111 : socket_(sock.Pass()) { | |
| 112 } | |
| 113 | |
| 114 ~Connection() { | |
| 115 } | |
| 116 | |
| 117 bool IsSame(const net::StreamListenSocket* socket) const { | |
| 118 return socket_ == socket; | |
| 119 } | |
| 120 | |
| 121 const Request& request() const { | |
| 122 return request_; | |
| 123 } | |
| 124 | |
| 125 Request& request() { | |
| 126 return request_; | |
| 127 } | |
| 128 | |
| 129 void OnSocketClosed() { | |
| 130 socket_.reset(); | |
| 131 } | |
| 132 | |
| 133 protected: | |
| 134 scoped_ptr<net::StreamListenSocket> socket_; | |
| 135 Request request_; | |
| 136 | |
| 137 private: | |
| 138 DISALLOW_COPY_AND_ASSIGN(Connection); | |
| 139 }; | |
| 140 | |
| 141 // Abstract interface with default implementations for some of the methods and | |
| 142 // a counter for how many times the response object has served requests. | |
| 143 class Response { | |
| 144 public: | |
| 145 Response() : accessed_(0) { | |
| 146 } | |
| 147 | |
| 148 virtual ~Response() { | |
| 149 } | |
| 150 | |
| 151 // Returns true if this response object should be used for a given request. | |
| 152 virtual bool Matches(const Request& r) const = 0; | |
| 153 | |
| 154 // Response objects can optionally supply their own HTTP headers, completely | |
| 155 // bypassing the default ones. | |
| 156 virtual bool GetCustomHeaders(std::string* headers) const { | |
| 157 return false; | |
| 158 } | |
| 159 | |
| 160 // Optionally provide a content type. Return false if you don't specify | |
| 161 // a content type. | |
| 162 virtual bool GetContentType(std::string* content_type) const { | |
| 163 return false; | |
| 164 } | |
| 165 | |
| 166 virtual size_t ContentLength() const { | |
| 167 return 0; | |
| 168 } | |
| 169 | |
| 170 virtual void WriteContents(net::StreamListenSocket* socket) const { | |
| 171 } | |
| 172 | |
| 173 virtual void IncrementAccessCounter() { | |
| 174 accessed_++; | |
| 175 } | |
| 176 | |
| 177 size_t accessed() const { | |
| 178 return accessed_; | |
| 179 } | |
| 180 | |
| 181 protected: | |
| 182 size_t accessed_; | |
| 183 | |
| 184 private: | |
| 185 DISALLOW_COPY_AND_ASSIGN(Response); | |
| 186 }; | |
| 187 | |
| 188 // Partial implementation of Response that matches a request's path. | |
| 189 // This is just a convenience implementation for the boilerplate implementation | |
| 190 // of Matches(). Don't instantiate directly. | |
| 191 class ResponseForPath : public Response { | |
| 192 public: | |
| 193 explicit ResponseForPath(const char* request_path) | |
| 194 : request_path_(request_path) { | |
| 195 } | |
| 196 | |
| 197 virtual ~ResponseForPath(); | |
| 198 | |
| 199 virtual bool Matches(const Request& r) const { | |
| 200 std::string path = r.path(); | |
| 201 std::string::size_type pos = path.find('?'); | |
| 202 if (pos != std::string::npos) | |
| 203 path = path.substr(0, pos); | |
| 204 return path.compare(request_path_) == 0; | |
| 205 } | |
| 206 | |
| 207 protected: | |
| 208 std::string request_path_; | |
| 209 | |
| 210 private: | |
| 211 DISALLOW_COPY_AND_ASSIGN(ResponseForPath); | |
| 212 }; | |
| 213 | |
| 214 // A very basic implementation of a response. | |
| 215 // A simple response matches a single document path on the server | |
| 216 // (e.g. "/foo") and returns a document in the form of a string. | |
| 217 class SimpleResponse : public ResponseForPath { | |
| 218 public: | |
| 219 SimpleResponse(const char* request_path, const std::string& contents) | |
| 220 : ResponseForPath(request_path), contents_(contents) { | |
| 221 } | |
| 222 | |
| 223 virtual ~SimpleResponse(); | |
| 224 | |
| 225 virtual void WriteContents(net::StreamListenSocket* socket) const { | |
| 226 socket->Send(contents_.c_str(), contents_.length(), false); | |
| 227 } | |
| 228 | |
| 229 virtual size_t ContentLength() const { | |
| 230 return contents_.length(); | |
| 231 } | |
| 232 | |
| 233 protected: | |
| 234 std::string contents_; | |
| 235 | |
| 236 private: | |
| 237 DISALLOW_COPY_AND_ASSIGN(SimpleResponse); | |
| 238 }; | |
| 239 | |
| 240 // To serve up files from the web server, create an instance of FileResponse | |
| 241 // and add it to the server's list of responses. The content type of the | |
| 242 // file will be determined by calling FindMimeFromData which examines the | |
| 243 // contents of the file and performs registry lookups. | |
| 244 class FileResponse : public ResponseForPath { | |
| 245 public: | |
| 246 FileResponse(const char* request_path, const base::FilePath& file_path) | |
| 247 : ResponseForPath(request_path), file_path_(file_path) { | |
| 248 } | |
| 249 | |
| 250 virtual bool GetContentType(std::string* content_type) const; | |
| 251 virtual void WriteContents(net::StreamListenSocket* socket) const; | |
| 252 virtual size_t ContentLength() const; | |
| 253 | |
| 254 protected: | |
| 255 base::FilePath file_path_; | |
| 256 mutable scoped_ptr<base::MemoryMappedFile> file_; | |
| 257 | |
| 258 private: | |
| 259 DISALLOW_COPY_AND_ASSIGN(FileResponse); | |
| 260 }; | |
| 261 | |
| 262 // Returns a 302 (temporary redirect) to redirect the client from a path | |
| 263 // on the test server to a different URL. | |
| 264 class RedirectResponse : public ResponseForPath { | |
| 265 public: | |
| 266 RedirectResponse(const char* request_path, const std::string& redirect_url) | |
| 267 : ResponseForPath(request_path), redirect_url_(redirect_url) { | |
| 268 } | |
| 269 | |
| 270 virtual bool GetCustomHeaders(std::string* headers) const; | |
| 271 | |
| 272 protected: | |
| 273 std::string redirect_url_; | |
| 274 | |
| 275 private: | |
| 276 DISALLOW_COPY_AND_ASSIGN(RedirectResponse); | |
| 277 }; | |
| 278 | |
| 279 // typedef for a list of connections. Used by SimpleWebServer. | |
| 280 typedef std::list<Connection*> ConnectionList; | |
| 281 | |
| 282 // Implementation of a simple http server. | |
| 283 // Before creating an instance of the server, make sure the current thread | |
| 284 // has a message loop. | |
| 285 class SimpleWebServer : public net::StreamListenSocket::Delegate { | |
| 286 public: | |
| 287 // Constructs a server listening at the given port on a local IPv4 address. | |
| 288 // An address on a NIC is preferred over the loopback address. | |
| 289 explicit SimpleWebServer(int port); | |
| 290 | |
| 291 // Constructs a server listening at the given address:port. | |
| 292 SimpleWebServer(const std::string& address, int port); | |
| 293 virtual ~SimpleWebServer(); | |
| 294 | |
| 295 void AddResponse(Response* response); | |
| 296 | |
| 297 // Ownership of response objects is by default assumed to be outside | |
| 298 // of the SimpleWebServer class. | |
| 299 // However, if the caller doesn't wish to maintain a list of response objects | |
| 300 // but rather let this class hold the only references to those objects, | |
| 301 // the caller can call this method to delete the objects as part of | |
| 302 // the cleanup process. | |
| 303 void DeleteAllResponses(); | |
| 304 | |
| 305 // StreamListenSocket::Delegate overrides. | |
| 306 virtual void DidAccept(net::StreamListenSocket* server, | |
| 307 scoped_ptr<net::StreamListenSocket> connection); | |
| 308 virtual void DidRead(net::StreamListenSocket* connection, | |
| 309 const char* data, | |
| 310 int len); | |
| 311 virtual void DidClose(net::StreamListenSocket* sock); | |
| 312 | |
| 313 // Returns the host on which the server is listening. This is suitable for | |
| 314 // use in URLs for resources served by this instance. | |
| 315 const std::string& host() const { | |
| 316 return host_; | |
| 317 } | |
| 318 | |
| 319 const ConnectionList& connections() const { | |
| 320 return connections_; | |
| 321 } | |
| 322 | |
| 323 protected: | |
| 324 class QuitResponse : public SimpleResponse { | |
| 325 public: | |
| 326 QuitResponse() | |
| 327 : SimpleResponse("/quit", "So long and thanks for all the fish.") { | |
| 328 } | |
| 329 | |
| 330 virtual void WriteContents(net::StreamListenSocket* socket) const { | |
| 331 SimpleResponse::WriteContents(socket); | |
| 332 base::MessageLoop::current()->Quit(); | |
| 333 } | |
| 334 }; | |
| 335 | |
| 336 Response* FindResponse(const Request& request) const; | |
| 337 Connection* FindConnection(const net::StreamListenSocket* socket) const; | |
| 338 | |
| 339 std::string host_; | |
| 340 scoped_ptr<net::StreamListenSocket> server_; | |
| 341 ConnectionList connections_; | |
| 342 std::list<Response*> responses_; | |
| 343 QuitResponse quit_; | |
| 344 | |
| 345 private: | |
| 346 void Construct(const std::string& address, int port); | |
| 347 DISALLOW_COPY_AND_ASSIGN(SimpleWebServer); | |
| 348 }; | |
| 349 | |
| 350 // Simple class holding incoming HTTP request. Can send the HTTP response | |
| 351 // at different rate - small chunks, on regular interval. | |
| 352 class ConfigurableConnection : public base::RefCounted<ConfigurableConnection> { | |
| 353 public: | |
| 354 struct SendOptions { | |
| 355 enum Speed { IMMEDIATE, DELAYED, IMMEDIATE_HEADERS_DELAYED_CONTENT }; | |
| 356 SendOptions() : speed_(IMMEDIATE), chunk_size_(0), timeout_(0) { } | |
| 357 SendOptions(Speed speed, int chunk_size, int64 timeout) | |
| 358 : speed_(speed), chunk_size_(chunk_size), timeout_(timeout) { | |
| 359 } | |
| 360 | |
| 361 Speed speed_; | |
| 362 int chunk_size_; | |
| 363 int64 timeout_; | |
| 364 }; | |
| 365 | |
| 366 explicit ConfigurableConnection(scoped_ptr<net::StreamListenSocket> sock) | |
| 367 : socket_(sock.Pass()), | |
| 368 cur_pos_(0) {} | |
| 369 | |
| 370 // Send HTTP response with provided |headers| and |content|. Appends | |
| 371 // "Context-Length:" header if the |content| is not empty. | |
| 372 void Send(const std::string& headers, const std::string& content); | |
| 373 | |
| 374 // Send HTTP response with provided |headers| and |content|. Appends | |
| 375 // "Context-Length:" header if the |content| is not empty. | |
| 376 // Use the |options| to tweak the network speed behaviour. | |
| 377 void SendWithOptions(const std::string& headers, const std::string& content, | |
| 378 const SendOptions& options); | |
| 379 | |
| 380 private: | |
| 381 friend class HTTPTestServer; | |
| 382 // Sends a chunk of the response and queues itself as a task for sending | |
| 383 // next chunk of |data_|. | |
| 384 void SendChunk(); | |
| 385 | |
| 386 // Closes the connection by releasing this instance's reference on its socket. | |
| 387 void Close(); | |
| 388 | |
| 389 scoped_ptr<net::StreamListenSocket> socket_; | |
| 390 Request r_; | |
| 391 SendOptions options_; | |
| 392 std::string data_; | |
| 393 int cur_pos_; | |
| 394 | |
| 395 DISALLOW_COPY_AND_ASSIGN(ConfigurableConnection); | |
| 396 }; | |
| 397 | |
| 398 // Simple class used as a base class for mock webserver. | |
| 399 // Override virtual functions Get and Post and use passed ConfigurableConnection | |
| 400 // instance to send the response. | |
| 401 class HTTPTestServer : public net::StreamListenSocket::Delegate { | |
| 402 public: | |
| 403 HTTPTestServer(int port, const std::wstring& address, | |
| 404 base::FilePath root_dir); | |
| 405 virtual ~HTTPTestServer(); | |
| 406 | |
| 407 // HTTP GET request is received. Override in derived classes. | |
| 408 // |connection| can be used to send the response. | |
| 409 virtual void Get(ConfigurableConnection* connection, | |
| 410 const std::wstring& path, const Request& r) = 0; | |
| 411 | |
| 412 // HTTP POST request is received. Override in derived classes. | |
| 413 // |connection| can be used to send the response | |
| 414 virtual void Post(ConfigurableConnection* connection, | |
| 415 const std::wstring& path, const Request& r) = 0; | |
| 416 | |
| 417 // Return the appropriate url with the specified path for this server. | |
| 418 std::wstring Resolve(const std::wstring& path); | |
| 419 | |
| 420 base::FilePath root_dir() { return root_dir_; } | |
| 421 | |
| 422 protected: | |
| 423 int port_; | |
| 424 std::wstring address_; | |
| 425 base::FilePath root_dir_; | |
| 426 | |
| 427 private: | |
| 428 typedef std::list<scoped_refptr<ConfigurableConnection> > ConnectionList; | |
| 429 ConnectionList::iterator FindConnection( | |
| 430 const net::StreamListenSocket* socket); | |
| 431 scoped_refptr<ConfigurableConnection> ConnectionFromSocket( | |
| 432 const net::StreamListenSocket* socket); | |
| 433 | |
| 434 // StreamListenSocket::Delegate overrides. | |
| 435 virtual void DidAccept(net::StreamListenSocket* server, | |
| 436 scoped_ptr<net::StreamListenSocket> socket); | |
| 437 virtual void DidRead(net::StreamListenSocket* socket, | |
| 438 const char* data, int len); | |
| 439 virtual void DidClose(net::StreamListenSocket* socket); | |
| 440 | |
| 441 scoped_ptr<net::StreamListenSocket> server_; | |
| 442 ConnectionList connection_list_; | |
| 443 | |
| 444 DISALLOW_COPY_AND_ASSIGN(HTTPTestServer); | |
| 445 }; | |
| 446 | |
| 447 } // namespace test_server | |
| 448 | |
| 449 #endif // CHROME_FRAME_TEST_TEST_SERVER_H_ | |
| OLD | NEW |