Sirikata
libcore/plugins/http/HttpServer.hpp
Go to the documentation of this file.
00001 // Copyright (c) 2012 Sirikata Authors. All rights reserved.
00002 // Use of this source code is governed by a BSD-style license that can
00003 // be found in the LICENSE file.
00004 
00005 #ifndef _SIRIKATA_LIBCORE_HTTP_SERVER_HPP_
00006 #define _SIRIKATA_LIBCORE_HTTP_SERVER_HPP_
00007 
00008 #include <sirikata/core/command/Commander.hpp>
00009 #include <sirikata/core/util/ListenerProvider.hpp>
00010 #include <sirikata/core/network/Asio.hpp>
00011 
00012 namespace Sirikata {
00013 namespace Command {
00014 
00015 typedef std::map<std::string, std::string> StringDictionary;
00016 // StringDictionary that uses case-insensitive keys, as required for
00017 // http headers by RFC 2616
00018 struct CaseInsensitiveStringLess {
00019     bool operator()(const std::string& lhs, const std::string& rhs) const {
00020         std::size_t lsize = lhs.size(), rsize = rhs.size();
00021         if (lsize != rsize) return (lsize < rsize);
00022         for(std::size_t i = 0; i < lsize; i++) {
00023             char li = std::tolower(lhs[i]), ri = std::tolower(rhs[i]);
00024             if (li != ri) return (li < ri);
00025         }
00026         return false;
00027     }
00028 };
00029 typedef std::map<std::string, std::string, CaseInsensitiveStringLess> CaseInsensitiveStringDictionary;
00030 
00031 typedef CaseInsensitiveStringDictionary Headers;
00032 typedef StringDictionary QueryParameters;
00033 
00034 typedef uint16 HttpStatus;
00035 
00036 // Unique identifer for requests coming into the HttpServer.
00037 typedef uint32 HttpRequestID;
00038 
00039 class HttpServer;
00040 
00041 class HttpRequestListener {
00042 public:
00043     virtual ~HttpRequestListener() {}
00044 
00059     virtual void onHttpRequest(HttpServer* server, HttpRequestID id, String& path, String& query, String& fragment, Headers& headers, String& body) = 0;
00060 };
00061 
00062 
00063 typedef std::tr1::shared_ptr<Network::TCPListener> TCPListenerPtr;
00064 typedef std::tr1::shared_ptr<Network::TCPSocket> TCPSocketPtr;
00065 
00066 class HttpRequest;
00067 typedef std::tr1::shared_ptr<HttpRequest> HttpRequestPtr;
00068 
00069 class HttpServer : public Provider<HttpRequestListener*> {
00070 public:
00071     HttpServer(Context* ctx, const String& host, uint16 port);
00072     ~HttpServer();
00073 
00074     void response(HttpRequestID id, HttpStatus status, const Headers& headers, const String& body);
00075 private:
00076 
00077     void acceptConnection();
00078     void handleConnection(TCPSocketPtr socket);
00079 
00080     void readRequestData(HttpRequestPtr req);
00081     void handleReadRequestData(HttpRequestPtr req, const boost::system::error_code& ec, std::size_t bytes_transferred);
00082 
00083     void handleRequest(HttpRequestPtr req);
00084 
00085     void writeResponseData(HttpRequestPtr req, uint32 offset);
00086     void handleWriteResponseData(HttpRequestPtr req, uint32 offset, const boost::system::error_code& ec, std::size_t bytes_transferred);
00087 
00088 
00089 
00090     Context* mContext;
00091     String mHost;
00092     uint16 mPort;
00093 
00094     TCPListenerPtr mAcceptor;
00095 
00096     // Much of the common steps work on data independently, and only one
00097     // callback can be active at a time for any given request. This just
00098     // protects the shared state (set of requests);
00099     typedef boost::recursive_mutex Mutex;
00100     typedef boost::lock_guard<Mutex> Lock;
00101     Mutex mMutex;
00102 
00103     typedef std::set<HttpRequestPtr> RequestSet;
00104     RequestSet mRequests;
00105 
00106     // Source of request IDs
00107     HttpRequestID mRequestIDSource;
00108 
00109     // Requests we've assigned IDs and sent out events for, but which we're
00110     // waiting for response() calls for.
00111     typedef std::map<HttpRequestID, HttpRequestPtr> RequestMap;
00112     RequestMap mProcessingRequests;
00113 }; // class HttpServer
00114 
00115 } // namespace Command
00116 } // namespace Sirikata
00117 
00118 
00119 #endif //_SIRIKATA_LIBCORE_HTTP_SERVER_HPP_