<html><!-- Created using the cpp_pretty_printer from the dlib C++ library. See http://dlib.net for updates. --><head><title>dlib C++ Library - server_http_abstract.h</title></head><body bgcolor='white'><pre> <font color='#009900'>// Copyright (C) 2006 Davis E. King (davis@dlib.net), Steven Van Ingelgem </font><font color='#009900'>// License: Boost Software License See LICENSE.txt for the full license. </font><font color='#0000FF'>#undef</font> DLIB_SERVER_HTTp_ABSTRACT_ <font color='#0000FF'>#ifdef</font> DLIB_SERVER_HTTp_ABSTRACT_ <font color='#0000FF'>#include</font> "<a style='text-decoration:none' href='server_iostream_abstract.h.html'>server_iostream_abstract.h</a>" <font color='#0000FF'>#include</font> <font color='#5555FF'><</font>iostream<font color='#5555FF'>></font> <font color='#0000FF'>#include</font> <font color='#5555FF'><</font>string<font color='#5555FF'>></font> <font color='#0000FF'>#include</font> <font color='#5555FF'><</font>map<font color='#5555FF'>></font> <font color='#0000FF'>namespace</font> dlib <b>{</b> <font color='#009900'>// ----------------------------------------------------------------------------------------- </font> <font color='#0000FF'>template</font> <font color='#5555FF'><</font> <font color='#0000FF'>typename</font> Key, <font color='#0000FF'>typename</font> Value, <font color='#0000FF'>typename</font> Comparer <font color='#5555FF'>=</font> std::less<font color='#5555FF'><</font>Key<font color='#5555FF'>></font> <font color='#5555FF'>></font> <font color='#0000FF'>class</font> <b><a name='constmap'></a>constmap</b> : <font color='#0000FF'>public</font> std::map<font color='#5555FF'><</font>Key, Value, Comparer<font color='#5555FF'>></font> <b>{</b> <font color='#009900'>/*! WHAT THIS OBJECT REPRESENTS This is simply an extension to the std::map that allows you to use the operator[] accessor with a constant map. !*/</font> <font color='#0000FF'>public</font>: <font color='#0000FF'>const</font> Value<font color='#5555FF'>&</font> <b><a name='operator'></a>operator</b>[]<font face='Lucida Console'>(</font> <font color='#0000FF'>const</font> Key<font color='#5555FF'>&</font> k <font face='Lucida Console'>)</font> <font color='#0000FF'>const</font>; <font color='#009900'>/*! ensures - if (this->find(k) != this->end()) then - This map contains the given key - return the value associated with the given key - else - return a default initialized Value object !*/</font> Value<font color='#5555FF'>&</font> <b><a name='operator'></a>operator</b>[]<font face='Lucida Console'>(</font> <font color='#0000FF'>const</font> Key<font color='#5555FF'>&</font> k <font face='Lucida Console'>)</font> <b>{</b> <font color='#0000FF'>return</font> std::map<font color='#5555FF'><</font>Key, Value<font color='#5555FF'>></font>::<font color='#0000FF'>operator</font> []<font face='Lucida Console'>(</font>k<font face='Lucida Console'>)</font>; <b>}</b> <font color='#009900'>/*! ensures - This function does the same thing as the normal std::map operator[] function. - if (this->find(k) != this->end()) then - This map contains the given key - return the value associated with the given key - else - Adds a new entry into the map that is associated with the given key. The new entry will be default initialized and this function returns a reference to it. !*/</font> <b>}</b>; <font color='#0000FF'>typedef</font> constmap<font color='#5555FF'><</font>std::string, std::string<font color='#5555FF'>></font> key_value_map; <font color='#009900'>// This version of key_value_map treats the key string as being case-insensitive. </font> <font color='#009900'>// For example, a key string of "Content-Type" would access the same element as a key </font> <font color='#009900'>// of "content-type". </font> <font color='#0000FF'>typedef</font> constmap<font color='#5555FF'><</font>std::string, std::string, less_case_insensitive<font color='#5555FF'>></font> key_value_map_ci; <font color='#009900'>// ----------------------------------------------------------------------------------------- </font> <font color='#0000FF'>struct</font> <b><a name='incoming_things'></a>incoming_things</b> <b>{</b> <font color='#009900'>/*! WHAT THIS OBJECT REPRESENTS This object contains all the various bits of information that describe a HTTP request that comes into a web server. For a detailed discussion of the fields of this object, see the server_http::on_request() method defined later in this file. !*/</font> <b><a name='incoming_things'></a>incoming_things</b> <font face='Lucida Console'>(</font> <font color='#0000FF'>const</font> std::string<font color='#5555FF'>&</font> foreign_ip_, <font color='#0000FF'>const</font> std::string<font color='#5555FF'>&</font> local_ip_, <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> foreign_port_, <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> local_port_ <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - #foreign_ip = foreign_ip_ - #foreign_port = foreign_port_ - #local_ip = local_ip_ - #local_port = local_port_ !*/</font> 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; <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> foreign_port; std::string local_ip; <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> local_port; <b>}</b>; <font color='#0000FF'>struct</font> <b><a name='outgoing_things'></a>outgoing_things</b> <b>{</b> <font color='#009900'>/*! WHAT THIS OBJECT REPRESENTS This object contains all the various bits of information that describe a HTTP response from a web server. For a detailed discussion of the fields of this object, see the server_http::on_request() method defined later in this file. !*/</font> <b><a name='outgoing_things'></a>outgoing_things</b><font face='Lucida Console'>(</font> <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - #http_return == 200 - #http_return_status == "OK" !*/</font> key_value_map cookies; key_value_map_ci headers; <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> http_return; std::string http_return_status; <b>}</b>; <font color='#009900'>// ----------------------------------------------------------------------------------------- </font> <font color='#0000FF'>class</font> <b><a name='http_parse_error'></a>http_parse_error</b> : <font color='#0000FF'>public</font> error <b>{</b> <font color='#009900'>/*! WHAT THIS OBJECT REPRESENTS This is an exception thrown by the parse_http_request() routine if there is a problem. !*/</font> <b>}</b>; <font color='#009900'>// ----------------------------------------------------------------------------------------- </font> <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>long</u></font> <b><a name='parse_http_request'></a>parse_http_request</b> <font face='Lucida Console'>(</font> std::istream<font color='#5555FF'>&</font> in, incoming_things<font color='#5555FF'>&</font> incoming, <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>long</u></font> max_content_length <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - Attempts to read a HTTP GET, POST, or PUT request from the given input stream. - Reads all headers of the request and puts them into #incoming. In particular, this function populates the following fields: - #incoming.path - #incoming.request_type - #incoming.content_type - #incoming.protocol - #incoming.queries - #incoming.cookies - #incoming.headers - This function also populates the #incoming.body field if and only if the Content-Type field is equal to "application/x-www-form-urlencoded". Otherwise, the content is not read from the stream. throws - http_parse_error This exception is thrown if the Content-Length coming from the web browser is greater than max_content_length or if any other problem is detected with the request. !*/</font> <font color='#0000FF'><u>void</u></font> <b><a name='read_body'></a>read_body</b> <font face='Lucida Console'>(</font> std::istream<font color='#5555FF'>&</font> in, incoming_things<font color='#5555FF'>&</font> incoming <font face='Lucida Console'>)</font>; <font color='#009900'>/*! requires - parse_http_request(in,incoming,max_content_length) has already been called and therefore populated the fields of incoming. ensures - if (incoming.body has already been populated with the content of an HTTP request) then - this function does nothing - else - reads the body of the HTTP request into #incoming.body. !*/</font> <font color='#0000FF'><u>void</u></font> <b><a name='write_http_response'></a>write_http_response</b> <font face='Lucida Console'>(</font> std::ostream<font color='#5555FF'>&</font> out, outgoing_things outgoing, <font color='#0000FF'>const</font> std::string<font color='#5555FF'>&</font> result <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - Writes an HTTP response, defined by the data in outgoing, to the given output stream. - The result variable is written out as the content of the response. !*/</font> <font color='#0000FF'><u>void</u></font> <b><a name='write_http_response'></a>write_http_response</b> <font face='Lucida Console'>(</font> std::ostream<font color='#5555FF'>&</font> out, <font color='#0000FF'>const</font> http_parse_error<font color='#5555FF'>&</font> e <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - Writes an HTTP error response based on the information in the exception object e. !*/</font> <font color='#0000FF'><u>void</u></font> <b><a name='write_http_response'></a>write_http_response</b> <font face='Lucida Console'>(</font> std::ostream<font color='#5555FF'>&</font> out, <font color='#0000FF'>const</font> std::exception<font color='#5555FF'>&</font> e <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - Writes an HTTP error response based on the information in the exception object e. !*/</font> <font color='#009900'>// ----------------------------------------------------------------------------------------- </font><font color='#009900'>// ----------------------------------------------------------------------------------------- </font> <font color='#0000FF'>class</font> <b><a name='server_http'></a>server_http</b> : <font color='#0000FF'>public</font> server_iostream <b>{</b> <font color='#009900'>/*! WHAT THIS EXTENSION DOES FOR server_iostream This extension turns the server object into a simple HTTP server. It only handles HTTP GET, PUT and POST requests and each incoming request triggers the on_request() callback. COOKIE STRINGS The strings returned in the cookies key_value_map should be of the following form: key: cookie_name value: cookie contents; expires=Fri, 31-Dec-2010 23:59:59 GMT; path=/; domain=.example.net You don't have to supply all the extra cookie arguments. So if you just want to set a cookie that will expire when the client's browser is closed you can just say something like incoming.cookies["cookie_name"] = "cookie contents"; HTTP HEADERS The HTTP headers in the incoming.headers and outgoing.headers are the name/value pairs of HTTP headers. For example, the HTTP header "Content-Type: text/html" would be encoded such that outgoing.headers["Content-Type"] == "text/html". Also note that if you wish to change the content type of your response to the client you may do so by setting the "Content-Type" header to whatever you like. However, setting this field manually is not necessary as it will default to "text/html" if you don't explicitly set it to something. !*/</font> <font color='#0000FF'>public</font>: <b><a name='server_http'></a>server_http</b> <font face='Lucida Console'>(</font> <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - #get_max_content_length() == 10*1024*1024 !*/</font> <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>long</u></font> <b><a name='get_max_content_length'></a>get_max_content_length</b> <font face='Lucida Console'>(</font> <font face='Lucida Console'>)</font> <font color='#0000FF'>const</font>; <font color='#009900'>/*! ensures - returns the max allowable content length, in bytes, of the post back to the web server. If a client attempts to send more data than this then an error number 413 is returned back to the client and the request is not processed by the web server. !*/</font> <font color='#0000FF'><u>void</u></font> <b><a name='set_max_content_length'></a>set_max_content_length</b> <font face='Lucida Console'>(</font> <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>long</u></font> max_length <font face='Lucida Console'>)</font>; <font color='#009900'>/*! ensures - #get_max_content_length() == max_length !*/</font> <font color='#0000FF'>private</font>: <font color='#0000FF'>virtual</font> <font color='#0000FF'>const</font> std::string <b><a name='on_request'></a>on_request</b> <font face='Lucida Console'>(</font> <font color='#0000FF'>const</font> incoming_things<font color='#5555FF'>&</font> incoming, outgoing_things<font color='#5555FF'>&</font> outgoing <font face='Lucida Console'>)</font> <font color='#5555FF'>=</font> <font color='#979000'>0</font>; <font color='#009900'>/*! requires - on_request() is called when there is an HTTP GET or POST request to be serviced - on_request() is run in its own thread - is_running() == true - the number of current on_request() functions running < get_max_connection() - in incoming: - incoming.path == the path being requested by this request - incoming.request_type == the type of request, GET or POST - incoming.content_type == the content type associated with this request - incoming.protocol == The protocol being used by the web browser (e.g. HTTP/1.1) - incoming.body == a string that contains the data that was posted back to the web server by the client (e.g. The string has the length specified by the Content-Length header). - incoming.body.size() < get_max_content_length() - incoming.queries == a map that contains all the key/value pairs in the query string of this request. The key and value strings of the query string will have been decoded back into their original form before being sent to this function (i.e. '+' decoded back to ' ' and "%hh" into its corresponding ascii value. So the URL-encoding is decoded automatically) - incoming.cookies == The set of cookies that came from the client along with this request. The cookies will have been decoded back to normal form from the URL-encoding. - incoming.headers == a map that contains all the incoming HTTP headers from the client web browser. - incoming.foreign_ip == the foreign ip address for this request - incoming.foreign_port == the foreign port number for this request - incoming.local_ip == the IP of the local interface this request is coming in on - incoming.local_port == the local port number this request is coming in on - in outgoing: - outgoing.cookies.size() == 0 - outgoing.headers.size() == 0 - outgoing.http_return == 200 - outgoing.http_return_status == "OK" ensures - This function returns the HTML page to be displayed as the response to this request. - this function will not call clear() - #outgoing.cookies == a set of new cookies to pass back to the client along with the result of this request. (Note that URL-encoding is automatically applied so you don't have to do it yourself) - #outgoing.headers == a set of additional headers you wish to appear in the HTTP response to this request. (This may be empty, the minimum needed headers will be added automatically if you don't set them) - outgoing.http_return and outgoing.http_return_status may be set to override the default HTTP return code of 200 OK throws - throws only exceptions derived from std::exception. If an exception is thrown then the error string from the exception is returned to the web browser. !*/</font> <font color='#009900'>// ----------------------------------------------------------------------- </font> <font color='#009900'>// Implementation Notes </font> <font color='#009900'>// ----------------------------------------------------------------------- </font> <font color='#0000FF'>virtual</font> <font color='#0000FF'><u>void</u></font> <b><a name='on_connect'></a>on_connect</b> <font face='Lucida Console'>(</font> std::istream<font color='#5555FF'>&</font> in, std::ostream<font color='#5555FF'>&</font> out, <font color='#0000FF'>const</font> std::string<font color='#5555FF'>&</font> foreign_ip, <font color='#0000FF'>const</font> std::string<font color='#5555FF'>&</font> local_ip, <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> foreign_port, <font color='#0000FF'><u>unsigned</u></font> <font color='#0000FF'><u>short</u></font> local_port, uint64 <font face='Lucida Console'>)</font> <font color='#009900'>/*! on_connect() is the function defined by server_iostream which is overloaded by server_http. In particular, the server_http's implementation is shown below. In it you can see how the server_http parses the incoming http request, gets a response by calling on_request(), and sends it back using the helper routines defined at the top of this file. Therefore, if you want to modify the behavior of the HTTP server, for example, to do some more complex data streaming requiring direct access to the iostreams, then you can do so by defining your own on_connect() routine. In particular, the default implementation shown below is a good starting point. !*/</font> <b>{</b> <font color='#0000FF'>try</font> <b>{</b> incoming_things <font color='#BB00BB'>incoming</font><font face='Lucida Console'>(</font>foreign_ip, local_ip, foreign_port, local_port<font face='Lucida Console'>)</font>; outgoing_things outgoing; <font color='#BB00BB'>parse_http_request</font><font face='Lucida Console'>(</font>in, incoming, <font color='#BB00BB'>get_max_content_length</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font><font face='Lucida Console'>)</font>; <font color='#BB00BB'>read_body</font><font face='Lucida Console'>(</font>in, incoming<font face='Lucida Console'>)</font>; <font color='#0000FF'>const</font> std::string<font color='#5555FF'>&</font> result <font color='#5555FF'>=</font> <font color='#BB00BB'>on_request</font><font face='Lucida Console'>(</font>incoming, outgoing<font face='Lucida Console'>)</font>; <font color='#BB00BB'>write_http_response</font><font face='Lucida Console'>(</font>out, outgoing, result<font face='Lucida Console'>)</font>; <b>}</b> <font color='#0000FF'>catch</font> <font face='Lucida Console'>(</font>http_parse_error<font color='#5555FF'>&</font> e<font face='Lucida Console'>)</font> <b>{</b> <font color='#BB00BB'>write_http_response</font><font face='Lucida Console'>(</font>out, e<font face='Lucida Console'>)</font>; <b>}</b> <font color='#0000FF'>catch</font> <font face='Lucida Console'>(</font>std::exception<font color='#5555FF'>&</font> e<font face='Lucida Console'>)</font> <b>{</b> <font color='#BB00BB'>write_http_response</font><font face='Lucida Console'>(</font>out, e<font face='Lucida Console'>)</font>; <b>}</b> <b>}</b> <b>}</b>; <b>}</b> <font color='#0000FF'>#endif</font> <font color='#009900'>// DLIB_SERVER_HTTp_ABSTRACT_ </font> </pre></body></html>