Sirikata
|
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_