00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef __PION_HTTP_SERVER_HEADER__
00011 #define __PION_HTTP_SERVER_HEADER__
00012
00013 #include <map>
00014 #include <string>
00015 #include <boost/asio.hpp>
00016 #include <boost/function.hpp>
00017 #include <boost/function/function2.hpp>
00018 #include <boost/function/function3.hpp>
00019 #include <boost/shared_ptr.hpp>
00020 #include <boost/thread/mutex.hpp>
00021 #include <pion/config.hpp>
00022 #include <pion/tcp/server.hpp>
00023 #include <pion/tcp/connection.hpp>
00024 #include <pion/http/request.hpp>
00025 #include <pion/http/auth.hpp>
00026 #include <pion/http/parser.hpp>
00027
00028
00029 namespace pion {
00030 namespace http {
00031
00032
00036 class PION_API server :
00037 public tcp::server
00038 {
00039
00040 public:
00041
00043 typedef boost::function2<void, http::request_ptr&, tcp::connection_ptr&> request_handler_t;
00044
00046 typedef boost::function3<void, http::request_ptr&, tcp::connection_ptr&,
00047 const std::string&> error_handler_t;
00048
00049
00051 virtual ~server() { if (is_listening()) stop(); }
00052
00058 explicit server(const unsigned int tcp_port = 0)
00059 : tcp::server(tcp_port),
00060 m_bad_request_handler(server::handle_bad_request),
00061 m_not_found_handler(server::handle_not_found_request),
00062 m_server_error_handler(server::handle_server_error),
00063 m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
00064 {
00065 set_logger(PION_GET_LOGGER("pion.http.server"));
00066 }
00067
00073 explicit server(const boost::asio::ip::tcp::endpoint& endpoint)
00074 : tcp::server(endpoint),
00075 m_bad_request_handler(server::handle_bad_request),
00076 m_not_found_handler(server::handle_not_found_request),
00077 m_server_error_handler(server::handle_server_error),
00078 m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
00079 {
00080 set_logger(PION_GET_LOGGER("pion.http.server"));
00081 }
00082
00089 explicit server(scheduler& sched, const unsigned int tcp_port = 0)
00090 : tcp::server(sched, tcp_port),
00091 m_bad_request_handler(server::handle_bad_request),
00092 m_not_found_handler(server::handle_not_found_request),
00093 m_server_error_handler(server::handle_server_error),
00094 m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
00095 {
00096 set_logger(PION_GET_LOGGER("pion.http.server"));
00097 }
00098
00105 server(scheduler& sched, const boost::asio::ip::tcp::endpoint& endpoint)
00106 : tcp::server(sched, endpoint),
00107 m_bad_request_handler(server::handle_bad_request),
00108 m_not_found_handler(server::handle_not_found_request),
00109 m_server_error_handler(server::handle_server_error),
00110 m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
00111 {
00112 set_logger(PION_GET_LOGGER("pion.http.server"));
00113 }
00114
00121 void add_resource(const std::string& resource, request_handler_t request_handler);
00122
00128 void remove_resource(const std::string& resource);
00129
00136 void add_redirect(const std::string& requested_resource, const std::string& new_resource);
00137
00139 inline void set_bad_request_handler(request_handler_t h) { m_bad_request_handler = h; }
00140
00142 inline void set_not_found_handler(request_handler_t h) { m_not_found_handler = h; }
00143
00145 inline void set_error_handler(error_handler_t h) { m_server_error_handler = h; }
00146
00148 virtual void clear(void) {
00149 if (is_listening()) stop();
00150 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
00151 m_resources.clear();
00152 }
00153
00160 static inline std::string strip_trailing_slash(const std::string& str) {
00161 std::string result(str);
00162 if (!result.empty() && result[result.size()-1]=='/')
00163 result.resize(result.size() - 1);
00164 return result;
00165 }
00166
00173 static void handle_bad_request(http::request_ptr& http_request_ptr,
00174 tcp::connection_ptr& tcp_conn);
00175
00182 static void handle_not_found_request(http::request_ptr& http_request_ptr,
00183 tcp::connection_ptr& tcp_conn);
00184
00192 static void handle_server_error(http::request_ptr& http_request_ptr,
00193 tcp::connection_ptr& tcp_conn,
00194 const std::string& error_msg);
00195
00203 static void handle_forbidden_request(http::request_ptr& http_request_ptr,
00204 tcp::connection_ptr& tcp_conn,
00205 const std::string& error_msg);
00206
00214 static void handle_method_not_allowed(http::request_ptr& http_request_ptr,
00215 tcp::connection_ptr& tcp_conn,
00216 const std::string& allowed_methods = "");
00217
00221 inline void set_authentication(http::auth_ptr auth) { m_auth_ptr = auth; }
00222
00224 inline void set_max_content_length(std::size_t n) { m_max_content_length = n; }
00225
00226 protected:
00227
00233 virtual void handle_connection(tcp::connection_ptr& tcp_conn);
00234
00242 virtual void handle_request(http::request_ptr& http_request_ptr,
00243 tcp::connection_ptr& tcp_conn, const boost::system::error_code& ec);
00244
00251 virtual bool find_request_handler(const std::string& resource,
00252 request_handler_t& request_handler) const;
00253
00254
00255 private:
00256
00258 static const unsigned int MAX_REDIRECTS;
00259
00261 typedef std::map<std::string, request_handler_t> resource_map_t;
00262
00264 typedef std::map<std::string, std::string> redirect_map_t;
00265
00266
00268 resource_map_t m_resources;
00269
00271 redirect_map_t m_redirects;
00272
00274 request_handler_t m_bad_request_handler;
00275
00277 request_handler_t m_not_found_handler;
00278
00280 error_handler_t m_server_error_handler;
00281
00283 mutable boost::mutex m_resource_mutex;
00284
00286 http::auth_ptr m_auth_ptr;
00287
00289 std::size_t m_max_content_length;
00290 };
00291
00292
00294 typedef boost::shared_ptr<server> server_ptr;
00295
00296
00297 }
00298 }
00299
00300 #endif