text: // ---------------------------------------------------------------------
  // pion:  a Boost C++ framework for building lightweight HTTP interfaces
  // ---------------------------------------------------------------------
  // Copyright (C) 2007-2014 Splunk Inc.  (https://github.com/splunk/pion)
  //
  // Distributed under the Boost Software License, Version 1.0.
  // See http://www.boost.org/LICENSE_1_0.txt
  //
  
  #ifndef __PION_HTTP_SERVER_HEADER__
  #define __PION_HTTP_SERVER_HEADER__
  
  #include <pion/config.hpp>
  #include <map>
  #include <string>
  #include <asio.hpp>
  #include <functional>
  #include <memory>
  #include <mutex>
  #include <pion/tcp/server.hpp>
  #include <pion/tcp/connection.hpp>
  #include <pion/http/request.hpp>
  #include <pion/http/auth.hpp>
  #include <pion/http/parser.hpp>
  
  #ifdef PION_WIN32
  #  pragma warning( push )
  #  pragma warning( disable: 4251 )
  #endif
  
  namespace pion {    // begin namespace pion
  namespace http {    // begin namespace http
  
  ///
  /// server: a server that handles HTTP connections
  ///
  class PION_API server :
      public tcp::server
  {
  
  public:
  
      /// type of function that is used to handle requests
      typedef std::function<void (const http::request_ptr&, const tcp::connection_ptr&)>  request_handler_t;
  
      /// handler for requests that result in "500 Server Error"
      typedef std::function<void (const http::request_ptr&, const tcp::connection_ptr&,
          const std::string&)> error_handler_t;
  
  
      /// default destructor
      virtual ~server() { if (is_listening()) stop(); }
  
      /**
       * creates a new server object
       *
       * @param tcp_port port number used to listen for new connections (IPv4)
       */
      explicit server(const unsigned int tcp_port = 0)
          : tcp::server(tcp_port),
          m_bad_request_handler(server::handle_bad_request),
          m_not_found_handler(server::handle_not_found_request),
          m_server_error_handler(server::handle_server_error),
          m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
      {
          set_logger(PION_GET_LOGGER("pion.http.server"));
      }
  
      /**
       * creates a new server object
       *
       * @param endpoint TCP endpoint used to listen for new connections (see ASIO docs)
       */
      explicit server(const asio::ip::tcp::endpoint& endpoint)
          : tcp::server(endpoint),
          m_bad_request_handler(server::handle_bad_request),
          m_not_found_handler(server::handle_not_found_request),
          m_server_error_handler(server::handle_server_error),
          m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
      {
          set_logger(PION_GET_LOGGER("pion.http.server"));
      }
  
      /**
       * creates a new server object
       *
       * @param sched the scheduler that will be used to manage worker threads
       * @param tcp_port port number used to listen for new connections (IPv4)
       */
      explicit server(scheduler& sched, const unsigned int tcp_port = 0)
          : tcp::server(sched, tcp_port),
          m_bad_request_handler(server::handle_bad_request),
          m_not_found_handler(server::handle_not_found_request),
          m_server_error_handler(server::handle_server_error),
          m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
      {
          set_logger(PION_GET_LOGGER("pion.http.server"));
      }
  
      /**
       * creates a new server object
       *
       * @param sched the scheduler that will be used to manage worker threads
       * @param endpoint TCP endpoint used to listen for new connections (see ASIO docs)
       */
      server(scheduler& sched, const asio::ip::tcp::endpoint& endpoint)
          : tcp::server(sched, endpoint),
          m_bad_request_handler(server::handle_bad_request),
          m_not_found_handler(server::handle_not_found_request),
          m_server_error_handler(server::handle_server_error),
          m_max_content_length(http::parser::DEFAULT_CONTENT_MAX)
      {
          set_logger(PION_GET_LOGGER("pion.http.server"));
      }
  
      /**
       * adds a new web service to the HTTP server
       *
       * @param resource the resource name or uri-stem to bind to the handler
       * @param request_handler function used to handle requests to the resource
       */
      void add_resource(const std::string& resource, request_handler_t request_handler);
  
      /**
       * removes a web service from the HTTP server
       *
       * @param resource the resource name or uri-stem to remove
       */
      void remove_resource(const std::string& resource);
  
      /**
       * adds a new resource redirection to the HTTP server
       *
       * @param requested_resource the resource name or uri-stem that will be redirected
       * @param new_resource the resource that requested_resource will be redirected to
       */
      void add_redirect(const std::string& requested_resource, const std::string& new_resource);
  
      /// sets the function that handles bad HTTP requests
      inline void set_bad_request_handler(request_handler_t h) { m_bad_request_handler = h; }
  
      /// sets the function that handles requests which match no other web services
      inline void set_not_found_handler(request_handler_t h) { m_not_found_handler = h; }
  
      /// sets the function that handles requests which match no other web services
      inline void set_error_handler(error_handler_t h) { m_server_error_handler = h; }
  
      /// clears the collection of resources recognized by the HTTP server
      virtual void clear() {
          if (is_listening()) stop();
          std::unique_lock<std::mutex> resource_lock(m_resource_mutex);
          m_resources.clear();
      }
  
      /**
       * strips trailing slash from a string, if one exists
       *
       * @param str the original string
       * @return the resulting string, after any trailing slash is removed
       */
      static inline std::string strip_trailing_slash(const std::string& str) {
          std::string result(str);
          if (!result.empty() && result[result.size()-1]=='/')
              result.resize(result.size() - 1);
          return result;
      }
  
      /**
       * used to send responses when a bad HTTP request is made
       *
       * @param http_request_ptr the new HTTP request to handle
       * @param tcp_conn the TCP connection that has the new request
       */
      static void handle_bad_request(const http::request_ptr& http_request_ptr,
                                   const tcp::connection_ptr& tcp_conn);
  
      /**
       * used to send responses when no web services can handle the request
       *
       * @param http_request_ptr the new HTTP request to handle
       * @param tcp_conn the TCP connection that has the new request
       */
      static void handle_not_found_request(const http::request_ptr& http_request_ptr,
                                        const tcp::connection_ptr& tcp_conn);
  
      /**
       * used to send responses when a server error occurs
       *
       * @param http_request_ptr the new HTTP request to handle
       * @param tcp_conn the TCP connection that has the new request
       * @param error_msg message that explains what went wrong
       */
      static void handle_server_error(const http::request_ptr& http_request_ptr,
                                    const tcp::connection_ptr& tcp_conn,
                                    const std::string& error_msg);
  
      /**
       * used to send responses when a request is forbidden
       *
       * @param http_request_ptr the new HTTP request to handle
       * @param tcp_conn the TCP connection that has the new request
       * @param error_msg message that explains what went wrong
       */
      static void handle_forbidden_request(const http::request_ptr& http_request_ptr,
                                         const tcp::connection_ptr& tcp_conn,
                                         const std::string& error_msg);
  
      /**
       * used to send responses when a method is not allowed
       *
       * @param http_request_ptr the new HTTP request to handle
       * @param tcp_conn the TCP connection that has the new request
       * @param allowed_methods optional comma separated list of allowed methods
       */
      static void handle_method_not_allowed(const http::request_ptr& http_request_ptr,
                                         const tcp::connection_ptr& tcp_conn,
                                         const std::string& allowed_methods = "");
  
      /**
       * sets the handler object for authentication verification processing
       */
      inline void set_authentication(http::auth_ptr auth) { m_auth_ptr = auth; }
  
      /// sets the maximum length for HTTP request payload content
      inline void set_max_content_length(std::size_t n) { m_max_content_length = n; }
  
  protected:
  
      /**
       * handles a new TCP connection
       *
       * @param tcp_conn the new TCP connection to handle
       */
      virtual void handle_connection(const tcp::connection_ptr& tcp_conn);
  
      /**
       * handles a new HTTP request
       *
       * @param http_request_ptr the HTTP request to handle
       * @param tcp_conn TCP connection containing a new request
       * @param ec error_code contains additional information for parsing errors
       */
      virtual void handle_request(const http::request_ptr& http_request_ptr,
                                  const tcp::connection_ptr& tcp_conn, const std::error_code& ec);
  
      /**
       * searches for the appropriate request handler to use for a given resource
       *
       * @param resource the name of the resource to search for
       * @param request_handler function that can handle requests for this resource
       */
      virtual bool find_request_handler(const std::string& resource,
                                        request_handler_t& request_handler) const;
  
  
  private:
  
      /// maximum number of redirections
      static const unsigned int   MAX_REDIRECTS;
  
      /// data type for a map of resources to request handlers
      typedef std::map<std::string, request_handler_t>    resource_map_t;
  
      /// data type for a map of requested resources to other resources
      typedef std::map<std::string, std::string>          redirect_map_t;
  
  
      /// collection of resources that are recognized by this HTTP server
      resource_map_t              m_resources;
  
      /// collection of redirections from a requested resource to another resource
      redirect_map_t              m_redirects;
  
      /// points to a function that handles bad HTTP requests
      request_handler_t           m_bad_request_handler;
  
      /// points to a function that handles requests which match no web services
      request_handler_t           m_not_found_handler;
  
      /// points to the function that handles server errors
      error_handler_t             m_server_error_handler;
  
      /// mutex used to protect access to the resources
      mutable std::mutex        m_resource_mutex;
  
      /// pointer to authentication handler object
      http::auth_ptr              m_auth_ptr;
  
      /// maximum length for HTTP request payload content
      std::size_t                 m_max_content_length;
  };
  
  
  /// data type for a HTTP server pointer
  typedef std::shared_ptr<server>	server_ptr;
  
  }   // end namespace http
  }   // end namespace pion
  
  #ifdef PION_WIN32
  #  pragma warning( pop )
  #endif
  
  #endif
  