diff options
author | slightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 05:11:58 +0000 |
---|---|---|
committer | slightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 05:11:58 +0000 |
commit | f781782dd67077478e117c61dca4ea5eefce3544 (patch) | |
tree | 4801f724123cfdcbb69c4e7fe40a565b331723ae /chrome_frame/test/test_server.h | |
parent | 63cf4759efa2373e33436fb5df6849f930081226 (diff) | |
download | chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.zip chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.gz chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.bz2 |
Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming in a separate CL.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/218019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27042 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/test/test_server.h')
-rw-r--r-- | chrome_frame/test/test_server.h | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/chrome_frame/test/test_server.h b/chrome_frame/test/test_server.h new file mode 100644 index 0000000..896b2b3 --- /dev/null +++ b/chrome_frame/test/test_server.h @@ -0,0 +1,296 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_FRAME_TEST_TEST_SERVER_H_ +#define CHROME_FRAME_TEST_TEST_SERVER_H_ + +// Implementation of an HTTP server for tests. +// To instantiate the server, make sure you have a message loop on the +// current thread and then create an instance of the SimpleWebServer class. +// The server uses two basic concepts, a request and a response. +// The Response interface represents an item (e.g. a document) available from +// the server. A Request object represents a request from a client (e.g. a +// browser). There are several basic Response classes implemented in this file, +// all derived from the Response interface. +// +// Here's a simple example that starts a web server that can serve up +// a single document (http://localhost:1337/foo). +// All other requests will get a 404. +// +// MessageLoopForUI loop; +// test_server::SimpleWebServer server(1337); +// test_server::SimpleResponse document("/foo", "Hello World!"); +// test_server.AddResponse(&document); +// loop.MessageLoop::Run(); +// +// To close the web server, just go to http://localhost:1337/quit. +// +// All Response classes count how many times they have been accessed. Just +// call Response::accessed(). +// +// To implement a custom response object (e.g. to match against a request +// based on some data, serve up dynamic content or take some action on the +// server), just inherit from one of the response classes or directly from the +// Response interface and add your response object to the server's list of +// response objects. + +#include <list> +#include <string> + +#include "base/basictypes.h" +#include "base/file_util.h" +#include "net/base/listen_socket.h" + +namespace test_server { + +class Request { + public: + Request() : content_length_(0) { + } + + void ParseHeaders(const std::string& headers); + + const std::string& method() const { + return method_; + } + + const std::string& path() const { + return path_; + } + + const std::string& headers() const { + return headers_; + } + + size_t content_length() const { + return content_length_; + } + + protected: + std::string method_; + std::string path_; + std::string version_; + std::string headers_; + size_t content_length_; + + private: + DISALLOW_COPY_AND_ASSIGN(Request); +}; + +// Manages request headers for a single request. +// For each successful request that's made, the server will keep an instance +// of this class so that they can be checked even after the server has been +// shut down. +class Connection { + public: + explicit Connection(ListenSocket* sock) : socket_(sock) { + } + + ~Connection() { + } + + bool IsSame(const ListenSocket* socket) const { + return socket_ == socket; + } + + void AddData(const std::string& data) { + data_ += data; + } + + bool CheckRequestReceived(); + + const Request& request() const { + return request_; + } + + protected: + scoped_refptr<ListenSocket> socket_; + std::string data_; + Request request_; + + private: + DISALLOW_COPY_AND_ASSIGN(Connection); +}; + +// Abstract interface with default implementations for some of the methods and +// a counter for how many times the response object has served requests. +class Response { + public: + Response() : accessed_(0) { + } + + virtual ~Response() { + } + + // Returns true if this response object should be used for a given request. + virtual bool Matches(const Request& r) const = 0; + + // Response objects can optionally supply their own HTTP headers, completely + // bypassing the default ones. + virtual bool GetCustomHeaders(std::string* headers) const { + return false; + } + + // Optionally provide a content type. Return false if you don't specify + // a content type. + virtual bool GetContentType(std::string* content_type) const { + return false; + } + + virtual size_t ContentLength() const { + return 0; + } + + virtual void WriteContents(ListenSocket* socket) const { + } + + void IncrementAccessCounter() { + accessed_++; + } + + size_t accessed() const { + return accessed_; + } + + protected: + size_t accessed_; + + private: + DISALLOW_COPY_AND_ASSIGN(Response); +}; + +// Partial implementation of Response that matches a request's path. +// This is just a convenience implementation for the boilerplate implementation +// of Matches(). Don't instantiate directly. +class ResponseForPath : public Response { + public: + explicit ResponseForPath(const char* request_path) + : request_path_(request_path) { + } + + virtual bool Matches(const Request& r) const { + return r.path().compare(request_path_) == 0; + } + + protected: + std::string request_path_; + + private: + DISALLOW_COPY_AND_ASSIGN(ResponseForPath); +}; + +// A very basic implementation of a response. +// A simple response matches a single document path on the server +// (e.g. "/foo") and returns a document in the form of a string. +class SimpleResponse : public ResponseForPath { + public: + SimpleResponse(const char* request_path, const std::string& contents) + : ResponseForPath(request_path), contents_(contents) { + } + + virtual void WriteContents(ListenSocket* socket) const { + socket->Send(contents_.c_str(), contents_.length(), false); + } + + virtual size_t ContentLength() const { + return contents_.length(); + } + + protected: + std::string contents_; + + private: + DISALLOW_COPY_AND_ASSIGN(SimpleResponse); +}; + +// To serve up files from the web server, create an instance of FileResponse +// and add it to the server's list of responses. The content type of the +// file will be determined by calling FindMimeFromData which examines the +// contents of the file and performs registry lookups. +class FileResponse : public ResponseForPath { + public: + FileResponse(const char* request_path, const FilePath& file_path) + : ResponseForPath(request_path), file_path_(file_path) { + } + + virtual bool GetContentType(std::string* content_type) const; + virtual void WriteContents(ListenSocket* socket) const; + virtual size_t ContentLength() const; + + protected: + FilePath file_path_; + mutable scoped_ptr<file_util::MemoryMappedFile> file_; + + private: + DISALLOW_COPY_AND_ASSIGN(FileResponse); +}; + +// Returns a 302 (temporary redirect) to redirect the client from a path +// on the test server to a different URL. +class RedirectResponse : public ResponseForPath { + public: + RedirectResponse(const char* request_path, const std::string& redirect_url) + : ResponseForPath(request_path), redirect_url_(redirect_url) { + } + + virtual bool GetCustomHeaders(std::string* headers) const; + + protected: + std::string redirect_url_; + + private: + DISALLOW_COPY_AND_ASSIGN(RedirectResponse); +}; + +// typedef for a list of connections. Used by SimpleWebServer. +typedef std::list<Connection*> ConnectionList; + +// Implementation of a simple http server. +// Before creating an instance of the server, make sure the current thread +// has a message loop. +class SimpleWebServer : public ListenSocket::ListenSocketDelegate { + public: + explicit SimpleWebServer(int port); + virtual ~SimpleWebServer(); + + void AddResponse(Response* response); + + // ListenSocketDelegate overrides. + virtual void DidAccept(ListenSocket* server, ListenSocket* connection); + virtual void DidRead(ListenSocket* connection, const std::string& data); + virtual void DidClose(ListenSocket* sock); + + const ConnectionList& connections() { + return connections_; + } + + protected: + class QuitResponse : public SimpleResponse { + public: + QuitResponse() + : SimpleResponse("/quit", "So long and thanks for all the fish.") { + } + + virtual void QuitResponse::WriteContents(ListenSocket* socket) const { + SimpleResponse::WriteContents(socket); + MessageLoop::current()->Quit(); + } + }; + + Response* FindResponse(const Request& request) const; + Connection* FindConnection(const ListenSocket* socket) const; + + protected: + scoped_refptr<ListenSocket> server_; + ConnectionList connections_; + std::list<Response*> responses_; + QuitResponse quit_; + + private: + DISALLOW_COPY_AND_ASSIGN(SimpleWebServer); +}; + +} // namespace test_server + +#endif // CHROME_FRAME_TEST_TEST_SERVER_H_ |