// Copyright (C) 2006 Davis E. King (davis@dlib.net), Steven Van Ingelgem // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_SERVER_HTTp_1_ #define DLIB_SERVER_HTTp_1_ #include "server_http_abstract.h" #include <iostream> #include <sstream> #include <string> #include <cctype> #include <map> #include "../logger.h" #include "../string.h" #include "server_iostream.h" #ifdef __INTEL_COMPILER // ignore the bogus warning about hiding on_connect() #pragma warning (disable: 1125) #endif #if _MSC_VER # pragma warning( disable: 4503 ) #endif // _MSC_VER namespace dlib { // ---------------------------------------------------------------------------------------- class http_parse_error : public error { public: http_parse_error(const std::string& str, int http_error_code_): error(str),http_error_code(http_error_code_) {} const int http_error_code; }; // ---------------------------------------------------------------------------------------- template <typename Key, typename Value, typename Comparer = std::less<Key> > class constmap : public std::map<Key, Value, Comparer> { public: const Value& operator[](const Key& k) const { static const Value dummy = Value(); typename std::map<Key, Value, Comparer>::const_iterator ci = std::map<Key, Value, Comparer>::find(k); if ( ci == this->end() ) return dummy; else return ci->second; } Value& operator[](const Key& k) { return std::map<Key, Value, Comparer>::operator [](k); } }; class less_case_insensitive { public: bool operator()(const std::string& a, const std::string& b) const { unsigned long i = 0; while (i < a.size() && i < b.size()) { const int cha = std::tolower(a[i]); const int chb = std::tolower(b[i]); if (cha < chb) return true; else if (cha > chb) return false; ++i; } if (a.size() < b.size()) return true; else return false; } }; typedef constmap< std::string, std::string, less_case_insensitive > key_value_map_ci; typedef constmap< std::string, std::string > key_value_map; struct incoming_things { incoming_things ( const std::string& foreign_ip_, const std::string& local_ip_, unsigned short foreign_port_, unsigned short local_port_ ): foreign_ip(foreign_ip_), foreign_port(foreign_port_), local_ip(local_ip_), local_port(local_port_) {} std::string path; std::string request_type; std::string content_type; std::string protocol; std::string body; key_value_map queries; key_value_map cookies; key_value_map_ci headers; std::string foreign_ip; unsigned short foreign_port; std::string local_ip; unsigned short local_port; }; struct outgoing_things { outgoing_things() : http_return(200), http_return_status("OK") { } key_value_map cookies; key_value_map_ci headers; unsigned short http_return; std::string http_return_status; }; // ---------------------------------------------------------------------------------------- unsigned long parse_http_request ( std::istream& in, incoming_things& incoming, unsigned long max_content_length ); void read_body ( std::istream& in, incoming_things& incoming ); void write_http_response ( std::ostream& out, outgoing_things outgoing, const std::string& result ); void write_http_response ( std::ostream& out, const http_parse_error& e ); void write_http_response ( std::ostream& out, const std::exception& e ); // ---------------------------------------------------------------------------------------- class server_http : public server_iostream { public: server_http() { max_content_length = 10*1024*1024; // 10MB } unsigned long get_max_content_length ( ) const { auto_mutex lock(http_class_mutex); return max_content_length; } void set_max_content_length ( unsigned long max_length ) { auto_mutex lock(http_class_mutex); max_content_length = max_length; } private: virtual const std::string on_request ( const incoming_things& incoming, outgoing_things& outgoing ) = 0; virtual void on_connect ( std::istream& in, std::ostream& out, const std::string& foreign_ip, const std::string& local_ip, unsigned short foreign_port, unsigned short local_port, uint64 ) { try { incoming_things incoming(foreign_ip, local_ip, foreign_port, local_port); outgoing_things outgoing; parse_http_request(in, incoming, get_max_content_length()); read_body(in, incoming); const std::string& result = on_request(incoming, outgoing); write_http_response(out, outgoing, result); } catch (http_parse_error& e) { dlog << LERROR << "Error processing request from: " << foreign_ip << " - " << e.what(); write_http_response(out, e); } catch (std::exception& e) { dlog << LERROR << "Error processing request from: " << foreign_ip << " - " << e.what(); write_http_response(out, e); } } mutex http_class_mutex; unsigned long max_content_length; const static logger dlog; }; // ---------------------------------------------------------------------------------------- } #ifdef NO_MAKEFILE #include "server_http.cpp" #endif #endif // DLIB_SERVER_HTTp_1_