From 20ab9032a0fba8f4f3b1ba331486762718c32e9c Mon Sep 17 00:00:00 2001 From: Dean Berris Date: Tue, 29 Mar 2016 21:46:38 +1100 Subject: [PATCH 001/112] Update the README to cover new developments --- README.rst | 68 ++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/README.rst b/README.rst index b349ff629..5b8185fb2 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,21 @@ Join us on Slack: http://slack.cpp-netlib.org/ Subscribe to the mailing list: https://groups.google.com/forum/#!forum/cpp-netlib +Downloading cpp-netlib +---------------------- + +You can find official release packages of the library at:: + + http://github.com/cpp-netlib/cpp-netlib/downloads + +If you want the latest code from the master branch of the project, you can +follow these instructions for cloning the project repository:: + + $ git clone https://github.com/cpp-netlib/cpp-netlib + $ cd cpp-netlib + $ git submodule init + $ git submodule update + Introduction ------------ @@ -35,41 +50,31 @@ This library is released under the Boost Software License (please see http://boost.org/LICENSE_1_0.txt or the accompanying LICENSE_1_0.txt file for the full text. -Downloading cpp-netlib ----------------------- - -You can find official release packages of the library at:: - - http://github.com/cpp-netlib/cpp-netlib/downloads - Building and Installing ----------------------- -Building with CMake -~~~~~~~~~~~~~~~~~~~ - -To build the libraries and run the tests with CMake, you will need to -have CMake version 2.8 or higher installed appropriately in your -system. +To build the libraries you will need to have CMake version 2.8 or higher +installed appropriately in your system. :: $ cmake --version cmake version 2.8.1 -Inside the cpp-netlib directory, you can issue the following statements to -configure and generate the Makefiles, and build the tests:: +It is recommended that you build cpp-netlib outside of the source directory, to +avoid having issues with CMake generated files polluting the source directory:: - $ cd ~/cpp-netlib # we're assuming it's where cpp-netlib is + $ mkdir ~/cpp-netlib-build + $ cd ~/cpp-netlib-build $ cmake -DCMAKE_BUILD_TYPE=Debug \ > -DCMAKE_C_COMPILER=clang \ > -DCMAKE_CXX_COMPILER=clang++ \ - > . + > $HOME/cpp-netlib # we're assuming this is where cpp-netlib is. Once CMake is done with generating the Makefiles and configuring the project, you can now build the tests and run them:: - $ cd ~/cpp-netlib + $ cd ~/cpp-netlib-build $ make $ make test @@ -85,8 +90,8 @@ Running Tests If you want to run the tests that come with cpp-netlib, there are a few things you will need. These are: - * A compiler (GCC 4.x, Clang 2.8, MSVC 2008) - * A build tool (CMake_ recommended, Boost.Build also an option) + * A compiler (GCC 4.x, Clang 3.6, MSVC 2008) + * A build tool (CMake_ is required) * OpenSSL headers (optional) .. note:: This assumes that you have cpp-netlib at the top-level of @@ -96,11 +101,13 @@ you will need. These are: Hacking on cpp-netlib --------------------- -cpp-netlib is being developed with the git_ distributed SCM system. +cpp-netlib uses git_ for tracking work, and is hosted on GitHub_. cpp-netlib is hosted on GitHub_ following the GitHub recommended practice of forking the repository and submitting pull requests to the source repository. You can read more about the forking_ process and submitting `pull requests`_ if -you're not familiar with either process yet. +you're not familiar with either process yet. cpp-netib follows the GitHub pull +request model for accepting patches. You can read more about the process at +http://cpp-netlib.org/process.html#pull-requests. .. _git: http://git-scm.com/ .. _GitHub: http://github.com/ @@ -114,19 +121,10 @@ copyright notices are at the top of each file in the project. .. _`Boost Software License`: http://www.boost.org/LICENSE_1_0.txt -At the time of writing, there are no coding conventions being followed but if -you write in the general style that is already existing in the project that -would be greatly appreciated. Copious amounts of comments will be called out, -but code that is not self-explanatory typically at least requires a rationale -documentation in comments explaining "why" the code is written that way. - -The main "upstream" repository is the one hosted by the original maintainer of -the project (Dean Michael Berris) at http://github.com/deanberris/cpp-netlib. -The "official" release repository is maintained at -http://github.com/cpp-netlib/cpp-netlib -- which is a fork of the upstream -repository. It is recommended that forks be made against the upstream repostory -and pull requests be submitted against the upstream repository so that patches -and other implementations can be curated by the original maintainer. +You can read about the cpp-netlib style guide at +http://cpp-netlib.org/style-guide.html. + +The main "upstream" repository is at http://github.com/cpp-netlib/cpp-netlib. Contact and Support ------------------- From 65b155115e442a7ae28636399e708ddf91833084 Mon Sep 17 00:00:00 2001 From: Dean Berris Date: Tue, 29 Mar 2016 23:55:01 +1100 Subject: [PATCH 002/112] Update inline docs and remove stale docs --- boost/network/protocol/http/server.hpp | 42 ++-- .../http/server/.async_connection.hpp.swo | Bin 0 -> 57344 bytes .../protocol/http/server/async_connection.hpp | 215 ++++++++++------ .../protocol/http/server/async_server.hpp | 44 +++- .../network/protocol/http/server/options.hpp | 166 ++++++++----- .../protocol/http/server/sync_connection.hpp | 233 ------------------ .../protocol/http/server/sync_server.hpp | 133 ---------- libs/network/doc/contents.rst | 3 - libs/network/doc/history.rst | 54 ---- libs/network/doc/in_depth.rst | 15 -- libs/network/doc/in_depth/http.rst | 180 -------------- .../network/doc/in_depth/http_client_tags.rst | 42 ---- libs/network/doc/in_depth/message.rst | 233 ------------------ libs/network/doc/in_depth/uri.rst | 151 ------------ libs/network/doc/index.rst | 1 - libs/network/doc/techniques.rst | 12 - libs/network/doc/techniques/directives.rst | 92 ------- libs/network/doc/techniques/polymorphism.rst | 92 ------- .../doc/techniques/tag_metafunctions.rst | 172 ------------- 19 files changed, 308 insertions(+), 1572 deletions(-) create mode 100644 boost/network/protocol/http/server/.async_connection.hpp.swo delete mode 100644 boost/network/protocol/http/server/sync_connection.hpp delete mode 100644 boost/network/protocol/http/server/sync_server.hpp delete mode 100644 libs/network/doc/history.rst delete mode 100644 libs/network/doc/in_depth.rst delete mode 100644 libs/network/doc/in_depth/http.rst delete mode 100644 libs/network/doc/in_depth/http_client_tags.rst delete mode 100644 libs/network/doc/in_depth/message.rst delete mode 100644 libs/network/doc/in_depth/uri.rst delete mode 100644 libs/network/doc/techniques.rst delete mode 100644 libs/network/doc/techniques/directives.rst delete mode 100644 libs/network/doc/techniques/polymorphism.rst delete mode 100644 libs/network/doc/techniques/tag_metafunctions.rst diff --git a/boost/network/protocol/http/server.hpp b/boost/network/protocol/http/server.hpp index 386901c13..b70381fa6 100644 --- a/boost/network/protocol/http/server.hpp +++ b/boost/network/protocol/http/server.hpp @@ -12,37 +12,35 @@ #include #include -#include #include namespace boost { namespace network { namespace http { -template -struct server_base { - typedef unsupported_tag type; -}; - -template -struct server_base >::type> { - typedef async_server_base type; -}; - -template -struct server_base >::type> { - typedef sync_server_base type; -}; - -template -struct basic_server : server_base::type {}; - +/** + * The main HTTP Server template implementing an asynchronous HTTP service. + * + * Usage Example: + * \code{.cpp} + * handler_type handler; + * http_server::options options(handler); + * options.thread_pool( + * std::make_shared()); + * http_server server(options.address("localhost").port("8000")); + * \endcode + * + */ template -struct server : server_base::type { - typedef typename server_base::type server_base; +struct server : async_server_base { + /// A convenience typedef for the base of this type, implementing most of + /// the internal details. + typedef async_server_base server_base; + + /// The options supported by the server. typedef server_options options; - explicit server(options const &options) : server_base(options) {} + using server_base::server_base; }; } // namespace http diff --git a/boost/network/protocol/http/server/.async_connection.hpp.swo b/boost/network/protocol/http/server/.async_connection.hpp.swo new file mode 100644 index 0000000000000000000000000000000000000000..fc24467541d9e242c89989e3f075a1bde946afd0 GIT binary patch literal 57344 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 literal 0 HcmV?d00001 diff --git a/boost/network/protocol/http/server/async_connection.hpp b/boost/network/protocol/http/server/async_connection.hpp index 0c259f9cc..f6aa15cf6 100644 --- a/boost/network/protocol/http/server/async_connection.hpp +++ b/boost/network/protocol/http/server/async_connection.hpp @@ -35,16 +35,17 @@ #include #ifndef BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE -/** Here we define a page's worth of header connection buffer data. - * This can be tuned to reduce the memory cost of connections, but this - * default size is set to be friendly to typical service applications. - * This is the maximum size though and Boost.Asio's internal representation - * of a streambuf would make appropriate decisions on how big a buffer - * is to begin with. +/** + * Here we define a page's worth of header connection buffer data. + * This can be tuned to reduce the memory cost of connections, but this + * default size is set to be friendly to typical service applications. + * This is the maximum size though and Boost.Asio's internal representation + * of a streambuf would make appropriate decisions on how big a buffer + * is to begin with. * - * This kinda assumes that a page is by default 4096. Since we're using - * the default allocator with the static buffers, it's not guaranteed that - * the static buffers will be page-aligned when they are allocated. + * This kinda assumes that a page is by default 4096. Since we're using + * the default allocator with the static buffers, it's not guaranteed that + * the static buffers will be page-aligned when they are allocated. */ #define BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE 4096 #endif /* BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE */ @@ -61,17 +62,15 @@ namespace boost { namespace network { namespace http { -#ifndef BOOST_NETWORK_NO_LIB extern void parse_version(std::string const& partial_parsed, std::tuple& version_pair); extern void parse_headers(std::string const& input, std::vector& container); -#endif template struct async_connection : std::enable_shared_from_this > { - + /// The set of known status codes for HTTP server responses. enum status_t { ok = 200, created = 201, @@ -100,6 +99,8 @@ struct async_connection typedef typename string::type string_type; typedef basic_request request; + + /// The connection pointer type. typedef std::shared_ptr connection_ptr; private: @@ -180,10 +181,10 @@ struct async_connection } public: - async_connection(asio::io_service& io_service, Handler& handler, - utils::thread_pool& thread_pool, - std::shared_ptr ctx = - std::shared_ptr()) + async_connection( + asio::io_service& io_service, Handler& handler, + utils::thread_pool& thread_pool, + std::shared_ptr ctx = std::shared_ptr()) : strand(io_service), handler(handler), thread_pool_(thread_pool), @@ -207,17 +208,16 @@ struct async_connection socket_.shutdown(asio::ip::tcp::socket::shutdown_receive, ignored); } - /** Function: template set_headers(Range headers) - * Precondition: headers have not been sent yet - * Postcondition: headers have been linearized to a buffer, - * and assumed to have been sent already when the - *function exits - * Throws: std::logic_error in case the headers have already been sent. + /** + * A call to set_headers takes a Range where each element models the Header + * concept. This Range will be linearized onto a buffer, which is then sent + * as soon as the first call to `write` or `flush` commences. * - * A call to set_headers takes a Range where each element models the - * Header concept. This Range will be linearized onto a buffer, which - *is - * then sent as soon as the first call to `write` or `flush` commences. + * @param[in] headers A range of Header objects to write out. + * @pre Headers have not been sent yet. + * @post Headers have been linearized to a buffer, and assumed to have been + * sent already when the function exits. + * @throw std::logic_error when the precondition is violated. */ template void set_headers(Range headers) { @@ -249,6 +249,14 @@ struct async_connection write_headers_only([self] {}); } + /** + * Sets the status of the response. + * + * @param[in] new_status The new status for this response. + * @pre Headers have not been sent. + * @post Status is set on the response. + * @throw std::logic_error when the precondition is violated. + */ void set_status(status_t new_status) { lock_guard lock(headers_mutex); if (headers_already_sent) @@ -260,33 +268,78 @@ struct async_connection status = new_status; } + /** + * Writes a given range of bytes out in order. + * + * Even though this function looks synchronous, all it does is schedules + * asynchronous writes to the connection as soon as the range is serialised + * into appropriately sized buffers. + * + * To use in your handler, it would look like: + * + * Example: + * \code{.cpp} + * connection->write("Hello, world!\n"); + * std::string sample = "I have a string!"; + * connection->write(sample); + * \endcode + * + * Note that if you want to send custom status and headers, you MUST call + * set_status and/or set_headers before any calls to write. + * + * @param[in] range A Boost.Range ``Single Pass Range`` of char's for writing. + * @throw std::system_error The encountered underlying error in previous + * operations. + * @post Status and headers have been sent, contents in the range have been + * serialized. + */ template void write(Range const& range) { lock_guard lock(headers_mutex); if (error_encountered) boost::throw_exception(std::system_error(*error_encountered)); auto self = this->shared_from_this(); - auto f = [this, self](std::error_code ec) { - this->default_error(ec); - }; + auto f = [this, self](std::error_code ec) { this->default_error(ec); }; write_impl(boost::make_iterator_range(range), f); } + /** + * Writes a given range out and schedules a completion callback to be invoked + * when the writes are done. This works similarly to write above. + * + * This overload is useful for writing streaming applications that send out + * chunks of data at a time, or for writing data that may not all fit in + * memory at once. + * + * @param[in] range A Boost.Range ``Single Pass Range`` of char's for writing. + * @param[in] callback A function of type `void(std::error_code)`. + * @throw std::system_error The encountered underlying error in previous + * operations. + * @post Status and headers have been sent, contents in the range have been + * serialized and scheduled for writing through the socket. + */ template typename disable_if< is_base_of, void>::type - write(Range const& range, Callback const& callback) { + write(Range const& range, Callback const& callback) { lock_guard lock(headers_mutex); if (error_encountered) boost::throw_exception(std::system_error(*error_encountered)); write_impl(boost::make_iterator_range(range), callback); } + /** + * Writes a given set of `asio::const_buffer`s out using a more efficient + * implementation. + * + * @param[in] seq A sequence of `asio::const_buffer` objects. + * @param[in] callback A function of type `void(std::error_code)`. + */ template typename enable_if< is_base_of, void>::type - write(ConstBufferSeq const& seq, Callback const& callback) { + write(ConstBufferSeq const& seq, Callback const& callback) { write_vec_impl(seq, callback, shared_array_list(), shared_buffers()); } @@ -295,11 +348,30 @@ struct async_connection buffer_type; public: + /// The input range taken by ``read`` callbacks. Typically a range of + /// ``char``s. typedef iterator_range input_range; - typedef std::function< - void(input_range, std::error_code, std::size_t, connection_ptr)> - read_callback_function; + /// Type required for ``read`` callbacks. Takes an input range, an error + /// code, the number of bytes read, and a connection pointer. + typedef std::function read_callback_function; + + /** + * Schedules an asynchronous read from the connection. This is generally + * useful for handling POST/PUT or other requests that may have data coming + * in through the HTTP request's body in a streaming manner. + * + * To use this function, the caller needs to provide a callback that handles + * a chunk of data at a time. The signature of the function (lambda or actual + * function pointer) should be of the following form: + * + * void(input_range, error_code, size_t, connection_ptr) + * + * @param[in] callback Invoked when the read has data ready for processing. + * @throw std::system_error The underlying error encountered in previous + * operations. + */ void read(read_callback_function callback) { if (error_encountered) boost::throw_exception(std::system_error(*error_encountered)); @@ -316,17 +388,24 @@ struct async_connection } auto self = this->shared_from_this(); - socket().async_read_some( - asio::buffer(read_buffer_), - strand.wrap([this, self, callback](std::error_code ec, - size_t bytes_transferred) { - callback(ec, bytes_transferred); - })); + socket().async_read_some(asio::buffer(read_buffer_), + strand.wrap([this, self, callback]( + std::error_code ec, size_t bytes_transferred) { + callback(ec, bytes_transferred); + })); } + /// Returns a reference to the underlying socket. boost::network::stream_handler& socket() { return socket_; } + + /// Returns a reference to the thread_pool running this handler. utils::thread_pool& thread_pool() { return thread_pool_; } + + /// Returns whether or not there were errors encountered in previous + /// operations. bool has_error() { return (!!error_encountered); } + + /// Returns the most recent error encountered. optional error() { return error_encountered; } private: @@ -378,12 +457,7 @@ struct async_connection template friend struct async_server_base; - enum state_t { - method, - uri, - version, - headers - }; + enum state_t { method, uri, version, headers }; void start() { typename ostringstream::type ip_stream; @@ -397,11 +471,10 @@ struct async_connection auto self = this->shared_from_this(); #ifdef BOOST_NETWORK_ENABLE_HTTPS if (socket_.is_ssl_enabled() && !handshake_done) { - socket_.async_handshake( - asio::ssl::stream_base::server, - [this, self, state](std::error_code ec) { - handle_handshake(ec, state); - }); + socket_.async_handshake(asio::ssl::stream_base::server, + [this, self, state](std::error_code ec) { + handle_handshake(ec, state); + }); } else { #endif socket_.async_read_some( @@ -530,11 +603,11 @@ struct async_connection "text/plain\r\nContent-Length: 12\r\n\r\nBad Request."; auto self = this->shared_from_this(); - asio::async_write(socket(), asio::buffer(bad_request, strlen(bad_request)), - strand.wrap([this, self](std::error_code ec, - size_t bytes_transferred) { - client_error_sent(ec, bytes_transferred); - })); + asio::async_write( + socket(), asio::buffer(bad_request, strlen(bad_request)), + strand.wrap([this, self](std::error_code ec, size_t bytes_transferred) { + client_error_sent(ec, bytes_transferred); + })); } void client_error_sent(std::error_code const& ec, std::size_t) { @@ -551,11 +624,11 @@ struct async_connection if (headers_in_progress) return; headers_in_progress = true; auto self = this->shared_from_this(); - asio::async_write( - socket(), headers_buffer, - strand.wrap([this, self, callback] (std::error_code ec, size_t bytes_transferred) { - handle_write_headers(callback, ec, bytes_transferred); - })); + asio::async_write(socket(), headers_buffer, + strand.wrap([this, self, callback]( + std::error_code ec, size_t bytes_transferred) { + handle_write_headers(callback, ec, bytes_transferred); + })); } void handle_write_headers(std::function callback, @@ -575,17 +648,15 @@ struct async_connection } } - void handle_write( - std::function callback, - shared_array_list, shared_buffers, std::error_code const& ec, - std::size_t) { + void handle_write(std::function callback, + shared_array_list, shared_buffers, + std::error_code const& ec, std::size_t) { // we want to forget the temporaries and buffers thread_pool().post([callback, ec] { callback(ec); }); } template - void write_impl(Range range, - std::function callback) { + void write_impl(Range range, std::function callback) { // linearize the whole range into a vector // of fixed-sized buffers, then schedule an asynchronous // write of these buffers -- make sure they are live @@ -645,11 +716,11 @@ struct async_connection pending_actions.push_back(continuation); return; } - asio::async_write(socket_, seq, [this, self, callback, temporaries, - buffers](std::error_code ec, - size_t bytes_transferred) { - handle_write(callback, temporaries, buffers, ec, bytes_transferred); - }); + asio::async_write( + socket_, seq, [this, self, callback, temporaries, buffers]( + std::error_code ec, size_t bytes_transferred) { + handle_write(callback, temporaries, buffers, ec, bytes_transferred); + }); } void handle_handshake(const std::error_code& ec, state_t state) { diff --git a/boost/network/protocol/http/server/async_server.hpp b/boost/network/protocol/http/server/async_server.hpp index f3d665d51..954e0a5c3 100644 --- a/boost/network/protocol/http/server/async_server.hpp +++ b/boost/network/protocol/http/server/async_server.hpp @@ -21,15 +21,21 @@ namespace http { template struct async_server_base : server_storage_base, socket_options_base { + /// The request type for this server. typedef basic_request request; - typedef basic_response response; typedef typename string::type string_type; - typedef typename boost::network::http::response_header::type - response_header; + + /// The header type for this server. + typedef + typename boost::network::http::response_header::type response_header; + + /// The connection type for this server. typedef async_connection connection; + + /// Defines the type for the connection pointer. typedef std::shared_ptr connection_ptr; - typedef std::unique_lock scoped_mutex_lock; + /// Constructs and initializes the asynchronous server core. explicit async_server_base(server_options const &options) : server_storage_base(options), socket_options_base(options), @@ -47,11 +53,31 @@ struct async_server_base : server_storage_base, socket_options_base { listening(false), ctx_(options.context()) {} + /** + * Listens to the correct port and runs the server's event loop. This can be + * run on multiple threads, as in the example below: + * + * Example: + * handler_type handler; + * http_server::options options(handler); + * options.thread_pool( + * std::make_shared()); + * http_server server(options.address("localhost").port("8000")); + * + * // Run in three threads including the current thread. + * std::thread t1([&server] { server.run() }); + * std::thread t2([&server] { server.run() }); + * server.run(); + * t1.join(); + * t2.join(); + */ void run() { listen(); service_.run(); }; + /// Stops the HTTP server acceptor and waits for all pending request handlers + /// to finish. void stop() { // stop accepting new requests and let all the existing // handlers finish. @@ -63,10 +89,12 @@ struct async_server_base : server_storage_base, socket_options_base { std::error_code ignored; acceptor.close(ignored); listening = false; - service_.post([this] () { this->handle_stop(); }); + service_.post([this]() { this->handle_stop(); }); } } + /// Explicitly listens on the configured host and port. May be called + /// multiple times but only takes effect once. void listen() { scoped_mutex_lock listening_lock(listening_mutex_); BOOST_NETWORK_MESSAGE("Listening on " << address_ << ':' << port_); @@ -81,6 +109,8 @@ struct async_server_base : server_storage_base, socket_options_base { } private: + typedef std::unique_lock scoped_mutex_lock; + Handler &handler; string_type address_, port_; std::shared_ptr thread_pool; @@ -126,7 +156,7 @@ struct async_server_base : server_storage_base, socket_options_base { #else new_connection->socket(), #endif - [this] (std::error_code const &ec) { this->handle_accept(ec); }); + [this](std::error_code const &ec) { this->handle_accept(ec); }); } void start_listening() { @@ -168,7 +198,7 @@ struct async_server_base : server_storage_base, socket_options_base { #else new_connection->socket(), #endif - [this] (std::error_code const &ec) { this->handle_accept(ec); }); + [this](std::error_code const &ec) { this->handle_accept(ec); }); listening = true; scoped_mutex_lock stopping_lock(stopping_mutex_); stopping = false; // if we were in the process of stopping, we revoke diff --git a/boost/network/protocol/http/server/options.hpp b/boost/network/protocol/http/server/options.hpp index a9db0e23c..d3d9f03a1 100644 --- a/boost/network/protocol/http/server/options.hpp +++ b/boost/network/protocol/http/server/options.hpp @@ -20,10 +20,15 @@ namespace boost { namespace network { namespace http { +/** + * The options supported by an HTTP Server's constructor. + */ template struct server_options { typedef typename string::type string_type; + /// A single-argument constructor that takes a Handler, and sets all options + /// to defaults. explicit server_options(Handler &handler) : io_service_(), handler_(handler), @@ -41,139 +46,186 @@ struct server_options { thread_pool_(), context_() {} - server_options(const server_options &other) - : io_service_(other.io_service()), - handler_(other.handler_), - address_(other.address_), - port_(other.port_), - reuse_address_(other.reuse_address_), - report_aborted_(other.report_aborted_), - non_blocking_io_(other.non_blocking_io_), - linger_(other.linger_), - linger_timeout_(0), - receive_buffer_size_(other.receive_buffer_size_), - send_buffer_size_(other.send_buffer_size_), - receive_low_watermark_(other.receive_low_watermark_), - send_low_watermark_(other.send_low_watermark_), - thread_pool_(other.thread_pool_), - context_(other.context_) {} - - server_options &operator=(server_options other) { - other.swap(*this); - return *this; - } + /// Disabled default constructor for the options class. + server_options() = delete; - void swap(server_options &other) { - using std::swap; - swap(io_service_, other.io_service_); - swap(address_, other.address_); - swap(port_, other.port_); - swap(reuse_address_, other.reuse_address_); - swap(report_aborted_, other.report_aborted_); - swap(non_blocking_io_, other.non_blocking_io_); - swap(linger_, other.linger_); - swap(linger_timeout_, other.linger_timeout_); - swap(receive_buffer_size_, other.receive_buffer_size_); - swap(send_buffer_size_, other.send_buffer_size_); - swap(receive_low_watermark_, other.receive_low_watermark_); - swap(send_low_watermark_, other.send_low_watermark_); - swap(thread_pool_, other.thread_pool_); - swap(context_, other.context_); - } + /// Copy constructor for the options class. + server_options(const server_options &) = default; + + /// Copy assignment for the options class. + server_options &operator=(const server_options &) = default; + + /// Move constructor for the options class. + server_options(server_options &&) = default; + + /// Move assignment for the options class. + server_options &operator=(server_options &&) = default; + /// Destructor for the options class. + ~server_options() = default; + + /// Sets the SSL context for the server. Default is nullptr. server_options &context(std::shared_ptr v) { context_ = v; return *this; } + + /// Provides an Asio io_service for the server. Default is nullptr. server_options &io_service(std::shared_ptr v) { io_service_ = v; return *this; } - server_options &address(string_type const &v) { - address_ = v; + + /// Sets the address to listen to for the server. Default is localhost. + server_options &address(string_type v) { + address_ = std::move(v); return *this; } + + /// Set the port to listen to for the server. Default is 80. server_options &port(string_type const &v) { port_ = v; return *this; } + + /// Set whether to reuse the address (SO_REUSE_ADDR). Default is false. server_options &reuse_address(bool v) { reuse_address_ = v; return *this; } + + /// Set whether to report aborted connections. Default is false. server_options &report_aborted(bool v) { report_aborted_ = v; return *this; } + + /// Set whether to use non-blocking IO. Default is true. server_options &non_blocking_io(bool v) { non_blocking_io_ = v; return *this; } + + /// Set whether sockets linger (SO_LINGER). Default is true. server_options &linger(bool v) { linger_ = v; return *this; } + + /// Set the linger timeout. Default is 0. server_options &linger_timeout(size_t v) { linger_timeout_ = v; return *this; } + + /// Set the socket receive buffer size. Unset by default. server_options &receive_buffer_size( asio::socket_base::receive_buffer_size v) { receive_buffer_size_ = v; return *this; } - server_options &send_buffer_size( - asio::socket_base::send_buffer_size v) { + + /// Set the send buffer size. Unset by default. + server_options &send_buffer_size(asio::socket_base::send_buffer_size v) { send_buffer_size_ = v; return *this; } + + /// Set the socket receive low watermark. Unset by default. server_options &receive_low_watermark( asio::socket_base::receive_low_watermark v) { receive_low_watermark_ = v; return *this; } - server_options &send_low_watermark( - asio::socket_base::send_low_watermark v) { + + /// Set the socket send low watermark. Unset by default. + server_options &send_low_watermark(asio::socket_base::send_low_watermark v) { send_low_watermark_ = v; return *this; } + + /// Set the thread-pool to use. Default is nullptr. server_options &thread_pool(std::shared_ptr v) { thread_pool_ = v; return *this; } - std::shared_ptr io_service() const { - return io_service_; - } + /// Returns the provided Asio io_service. + std::shared_ptr io_service() const { return io_service_; } + + /// Returns the address to listen on. string_type address() const { return address_; } + + /// Returns the port to listen on. string_type port() const { return port_; } + + /// Returns a reference to the provided handler. Handler &handler() const { return handler_; } + + /// Returns whether to reuse the address. bool reuse_address() const { return reuse_address_; } + + /// Returns whether to report aborted connections. bool report_aborted() const { return report_aborted_; } + + /// Returns whether to perform non-blocking IO. bool non_blocking_io() const { return non_blocking_io_; } + + /// Returns whether to linger. bool linger() const { return linger_; } + + /// Returns the linger timeout. size_t linger_timeout() const { return linger_timeout_; } - boost::optional - receive_buffer_size() const { + + /// Returns the optional receive buffer size. + boost::optional receive_buffer_size() + const { return receive_buffer_size_; } + + /// Returns the optional send buffer size. boost::optional send_buffer_size() const { return send_buffer_size_; } + + /// Returns the optional receive low watermark. boost::optional - receive_low_watermark() const { + receive_low_watermark() const { return receive_low_watermark_; } - boost::optional - send_low_watermark() const { + + /// Returns the optional send low watermark. + boost::optional send_low_watermark() + const { return send_low_watermark_; } + + /// Returns a pointer to the provided thread pool. std::shared_ptr thread_pool() const { return thread_pool_; } - std::shared_ptr context() const { - return context_; + + /// Returns a pointer to the provided context. + std::shared_ptr context() const { return context_; } + + /// Swap implementation for the server options. + void swap(server_options &other) { + using std::swap; + swap(io_service_, other.io_service_); + swap(address_, other.address_); + swap(port_, other.port_); + swap(reuse_address_, other.reuse_address_); + swap(report_aborted_, other.report_aborted_); + swap(non_blocking_io_, other.non_blocking_io_); + swap(linger_, other.linger_); + swap(linger_timeout_, other.linger_timeout_); + swap(receive_buffer_size_, other.receive_buffer_size_); + swap(send_buffer_size_, other.send_buffer_size_); + swap(receive_low_watermark_, other.receive_low_watermark_); + swap(send_low_watermark_, other.send_low_watermark_); + swap(thread_pool_, other.thread_pool_); + swap(context_, other.context_); } private: @@ -186,13 +238,11 @@ struct server_options { bool non_blocking_io_; bool linger_; size_t linger_timeout_; - boost::optional - receive_buffer_size_; + boost::optional receive_buffer_size_; boost::optional send_buffer_size_; boost::optional receive_low_watermark_; - boost::optional - send_low_watermark_; + boost::optional send_low_watermark_; std::shared_ptr thread_pool_; std::shared_ptr context_; }; diff --git a/boost/network/protocol/http/server/sync_connection.hpp b/boost/network/protocol/http/server/sync_connection.hpp deleted file mode 100644 index 969ce6bba..000000000 --- a/boost/network/protocol/http/server/sync_connection.hpp +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2009 (c) Dean Michael Berris -// Copyright 2009 (c) Tarroo, Inc. -// Adapted from Christopher Kholhoff's Boost.Asio Example, released under -// the Boost Software License, Version 1.0. (See acccompanying file -// LICENSE_1_0.txt -// or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_NETWORK_HTTP_SERVER_SYNC_CONNECTION_HPP_ -#define BOOST_NETWORK_HTTP_SERVER_SYNC_CONNECTION_HPP_ - -#ifndef BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE -#define BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE 1024uL -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace network { -namespace http { - -template -struct sync_connection - : std::enable_shared_from_this > { - - sync_connection(asio::io_service &service, Handler &handler) - : service_(service), - handler_(handler), - socket_(service_), - wrapper_(service_) {} - - asio::ip::tcp::socket &socket() { return socket_; } - - void start() { - // This is HTTP so we really want to just - // read and parse a request that's incoming - // and then pass that request object to the - // handler_ instance. - // - using asio::ip::tcp; - std::error_code option_error; - socket_.set_option(tcp::no_delay(true), option_error); - if (option_error) - handler_.log(std::system_error(option_error).what()); - auto self = this->shared_from_this(); - socket_.async_read_some( - asio::buffer(buffer_), - wrapper_.wrap([=] (std::error_code const &ec, - std::size_t bytes_transferred) { - self->handle_read_headers(ec, bytes_transferred); - })); - } - - private: - struct is_content_length { - template - bool operator()(Header const &header) { - return boost::to_lower_copy(header.name) == "content-length"; - } - }; - - void handle_read_headers(std::error_code const &ec, - size_t bytes_transferred) { - if (!ec) { - request_.source = socket_.remote_endpoint().address().to_string(); - request_.source_port = socket_.remote_endpoint().port(); - boost::tribool done; - buffer_type::iterator new_start; - tie(done, new_start) = parser_.parse_headers( - request_, buffer_.data(), buffer_.data() + bytes_transferred); - if (done) { - if (request_.method[0] == 'P') { - // look for the content-length header - auto - it = std::find_if(request_.headers.begin(), - request_.headers.end(), is_content_length()); - if (it == request_.headers.end()) { - response_ = basic_response::stock_reply( - basic_response::bad_request); - auto self = this->shared_from_this(); - asio::async_write( - socket_, response_.to_buffers(), - wrapper_.wrap([=] (std::error_code const &ec) { - self->handle_write(ec); - })); - return; - } - - size_t content_length = 0; - - try { - content_length = std::stoul(it->value); - } - catch (...) { - response_ = basic_response::stock_reply( - basic_response::bad_request); - auto self = this->shared_from_this(); - asio::async_write( - socket_, response_.to_buffers(), - wrapper_.wrap([=] (std::error_code const &ec) { - self->handle_write(ec); - })); - return; - } - - if (content_length != 0) { - if (new_start != (buffer_.begin() + bytes_transferred)) { - request_.body.append(new_start, - buffer_.begin() + bytes_transferred); - content_length -= - std::distance(new_start, buffer_.begin() + bytes_transferred); - } - if (content_length > 0) { - auto self = this->shared_from_this(); - socket_.async_read_some( - asio::buffer(buffer_), - wrapper_.wrap([=] (std::error_code const &ec, - std::size_t bytes_transferred) { - self->handle_read_body_contents(ec, content_length, - bytes_transferred); - })); - return; - } - } - - handler_(request_, response_); - auto self = this->shared_from_this(); - asio::async_write( - socket_, response_.to_buffers(), - wrapper_.wrap([=] (std::error_code const &ec) { - self->handle_write(ec); - })); - } else { - handler_(request_, response_); - auto self = this->shared_from_this(); - asio::async_write( - socket_, response_.to_buffers(), - wrapper_.wrap([=] (std::error_code const &ec) { - self->handle_write(ec); - })); - } - } else if (!done) { - response_ = - basic_response::stock_reply(basic_response::bad_request); - auto self = this->shared_from_this(); - asio::async_write( - socket_, response_.to_buffers(), - wrapper_.wrap([=] (std::error_code const &ec) { - self->handle_write(ec); - })); - } else { - auto self = this->shared_from_this(); - socket_.async_read_some( - asio::buffer(buffer_), - wrapper_.wrap([=] (std::error_code const &ec, - std::size_t bytes_transferred) { - self->handle_read_headers(ec, bytes_transferred); - })); - } - } - // TODO Log the error? - } - - void handle_read_body_contents(std::error_code const &ec, - size_t bytes_to_read, - size_t bytes_transferred) { - if (!ec) { - size_t difference = bytes_to_read - bytes_transferred; - buffer_type::iterator start = buffer_.begin(), past_end = start; - std::advance(past_end, (std::min)(bytes_to_read, bytes_transferred)); - request_.body.append(buffer_.begin(), past_end); - if (difference == 0) { - handler_(request_, response_); - auto self = this->shared_from_this(); - asio::async_write( - socket_, response_.to_buffers(), - wrapper_.wrap([=] (std::error_code const &ec) { - self->handle_write(ec); - })); - } else { - auto self = this->shared_from_this(); - socket_.async_read_some( - asio::buffer(buffer_), - wrapper_.wrap([=] (std::error_code const &ec, - std::size_t bytes_transferred) { - self->handle_read_body_contents(ec, difference, bytes_transferred); - })); - } - } - // TODO Log the error? - } - - void handle_write(std::error_code const &ec) { - if (!ec) { - using asio::ip::tcp; - std::error_code ignored_ec; - socket_.shutdown(tcp::socket::shutdown_receive, ignored_ec); - } - } - - asio::io_service &service_; - Handler &handler_; - asio::ip::tcp::socket socket_; - asio::io_service::strand wrapper_; - - typedef std::array - buffer_type; - buffer_type buffer_; - typedef basic_request_parser request_parser; - request_parser parser_; - basic_request request_; - basic_response response_; -}; - -} // namespace http - -} // namespace network - -} // namespace boost - -#endif // BOOST_NETWORK_HTTP_SERVER_SYNC_CONNECTION_HPP_ diff --git a/boost/network/protocol/http/server/sync_server.hpp b/boost/network/protocol/http/server/sync_server.hpp deleted file mode 100644 index 2b4b976da..000000000 --- a/boost/network/protocol/http/server/sync_server.hpp +++ /dev/null @@ -1,133 +0,0 @@ - -// Copyright 2010 Dean Michael Berris. -// Copyright 2010 Glyn Matthews. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SYNC_SERVER_HPP_20101025 -#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SYNC_SERVER_HPP_20101025 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace network { -namespace http { - -template -struct sync_server_base : server_storage_base, socket_options_base { - typedef typename string::type string_type; - typedef basic_request request; - typedef basic_response response; - typedef typename boost::network::http::response_header::type - response_header; - - sync_server_base(server_options const& options) - : server_storage_base(options), - socket_options_base(options), - handler_(options.handler()), - address_(options.address()), - port_(options.port()), - acceptor_(server_storage_base::service_), - new_connection(), - listening_mutex_(), - listening_(false) {} - - void run() { - listen(); - service_.run(); - } - - void stop() { - // stop accepting new connections and let all the existing handlers - // finish. - std::error_code ignored; - acceptor_.close(ignored); - service_.stop(); - } - - void listen() { - std::unique_lock listening_lock(listening_mutex_); - if (!listening_) start_listening(); - } - - private: - Handler& handler_; - string_type address_, port_; - asio::ip::tcp::acceptor acceptor_; - std::shared_ptr > new_connection; - std::mutex listening_mutex_; - bool listening_; - - void handle_accept(std::error_code const& ec) { - if (ec) { - } - socket_options_base::socket_options(new_connection->socket()); - new_connection->start(); - new_connection.reset(new sync_connection(service_, handler_)); - auto self = this->shared_from_this(); - acceptor_.async_accept( - new_connection->socket(), - [=] (std::error_code const &ec) { self->handle_accept(); }); - } - - void start_listening() { - using asio::ip::tcp; - std::error_code error; - tcp::resolver resolver(service_); - tcp::resolver::query query(address_, port_); - tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, error); - if (error) { - BOOST_NETWORK_MESSAGE("Error resolving address: " << address_ << ':' - << port_); - boost::throw_exception(std::runtime_error("Error resolving address.")); - } - tcp::endpoint endpoint = *endpoint_iterator; - acceptor_.open(endpoint.protocol(), error); - if (error) { - BOOST_NETWORK_MESSAGE("Error opening socket: " << address_ << ':' << port_ - << " -- reason: '" << error - << '\''); - boost::throw_exception(std::runtime_error("Error opening socket.")); - } - socket_options_base::acceptor_options(acceptor_); - acceptor_.bind(endpoint, error); - if (error) { - BOOST_NETWORK_MESSAGE("Error binding to socket: " - << address_ << ':' << port_ << " -- reason: '" - << error << '\''); - boost::throw_exception(std::runtime_error("Error binding to socket.")); - } - acceptor_.listen(tcp::socket::max_connections, error); - if (error) { - BOOST_NETWORK_MESSAGE("Error listening on socket: " - << address_ << ':' << port_ << " -- reason: '" - << error << '\''); - boost::throw_exception(std::runtime_error("Error listening on socket.")); - } - new_connection.reset(new sync_connection(service_, handler_)); - auto self = this->shared_from_this(); - acceptor_.async_accept( - new_connection->socket(), - [=] (std::error_code const &ec) { self->handle_accept(ec); }); - listening_ = true; - } -}; - -} /* http */ - -} /* network */ - -} /* boost */ - -#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SYNC_SERVER_HPP_20101025 */ diff --git a/libs/network/doc/contents.rst b/libs/network/doc/contents.rst index b014eab03..0c41b80a7 100644 --- a/libs/network/doc/contents.rst +++ b/libs/network/doc/contents.rst @@ -10,8 +10,5 @@ Contents whats_new.rst getting_started.rst examples.rst - in_depth.rst - techniques.rst - history.rst reference.rst references.rst diff --git a/libs/network/doc/history.rst b/libs/network/doc/history.rst deleted file mode 100644 index 24f503f0a..000000000 --- a/libs/network/doc/history.rst +++ /dev/null @@ -1,54 +0,0 @@ -Project history -=============== - -The :mod:`cpp-netlib` was founded by Dean Michael Berris in 2007. -Initially it consisted of a message template and an HTTP client. It -found a home on Sourceforge_ but was migrated at the end of 2009 to -Github_ where development is actively continued by a committed -community. - -Motivation -~~~~~~~~~~ - -We're a group of C++ developers and we kept becoming annoyed that we -had to repeatedly write the same code when building applications that -needed to be network-aware. - -We found that there was a lack of accessible networking libraries, -either standard or open source, that fulfilled our needs. Such -libraries exist for every other major language. So, building on top -of `Boost.Asio`_, we decided to get together and build our own. - -Objectives -~~~~~~~~~~ - -The objectives of the :mod:`cpp-netlib` are to: - -* develop a high quality, portable, easy to use C++ networking library -* enable developers to easily extend the library -* lower the barrier to entry for cross-platform network-aware C++ - applications - -The goal the of :mod:`cpp-netlib` has never been to build a -fully-featured web server - there are plenty of excellent options -already available. The niche that this library targets is for -light-weight networking functionality for C++ applications that have -demanding performance requirements or memory constraints, but that -also need to be portable. This type of application is becoming -increasingly common as software becomes more distributed, and -applications need to communicate with services. - -While many languages provide direct library support for high level -network programming, this feature is missing in C++. Therefore, this -library has been developed with the intention of eventually being -submitted to Boost_, a collection of general, high quality -libraries for C++ developers. - -Eventually, the :mod:`cpp-netlib` will be extended to support many of -the application layer protocols such as SMTP, FTP, SOAP, XMPP etc. - - -.. _Sourceforge: http://sourceforge.net/projects/cpp-netlib/ -.. _Github: http://github.com/cpp-netlib/cpp-netlib -.. _Boost: http://www.boost.org/ -.. _`Boost.Asio`: http://www.boost.org/libs/asio/ diff --git a/libs/network/doc/in_depth.rst b/libs/network/doc/in_depth.rst deleted file mode 100644 index 39af9a4f4..000000000 --- a/libs/network/doc/in_depth.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _in_depth: - -An in-depth look at the :mod:`cpp-netlib` -========================================= - -The :mod:`cpp-netlib` is composed of three different sets of -functionality: a **message** template, a **URI** template and -different **protocol** implementations. - -.. toctree:: - :maxdepth: 2 - - in_depth/message - in_depth/uri - in_depth/http diff --git a/libs/network/doc/in_depth/http.rst b/libs/network/doc/in_depth/http.rst deleted file mode 100644 index 711bf6b3e..000000000 --- a/libs/network/doc/in_depth/http.rst +++ /dev/null @@ -1,180 +0,0 @@ -HTTP implementation -=================== - -HTTP client -``````````` - -At the heart of the HTTP client implementation is a single class aptly named -``basic_client``, which is also a template. The template ``basic_client`` takes -three template parameters: - -.. code-block:: c++ - - namespace boost { namespace http { - - template - struct basic_client; - - } // namespace http - - } // namespace boost - -The ``Tag`` template parameter follows the same tag-dispatch mechanism to -determine the behavior of the ``basic_client``. The interface of -``basic_client`` may change depending on certain properties defined for the tag -you provide. Below is a table of predefined supported tags you can use in your -overload of the ``basic_client``: - ------------- - -.. include:: http_client_tags.rst - -.. _Boost.Thread: http://www.boost.org/libs/thread - - -The default typedef for the HTTP client that is provided uses the -``http_async_8bit_udp_resolve`` tag, and implements HTTP 1.1. The exact -typedef is in the ``boost::network::http`` namespace as the following: - -.. code-block:: c++ - - namespace boost { namespace network { namespace http { - - typedef basic_client - client; - - }}} - - -This type has nested typedefs for the correct types for the ``basic_request`` -and ``basic_response`` templates. To use the correct types for ``basic_request`` -or ``basic_response`` you can use these nested typedefs like so: - - -.. code-block:: c++ - - boost::network::http::client::request request; - boost::network::http::client::response response; - - // or... - using namespace boost::network; - http::client::request request; - http::client::response response; - - -Typical use cases for the HTTP client would look something like the following: - - -.. code-block:: c++ - - using namespace boost::network; - http::request request("http://www.boost.org/"); - request << header("Connection", "close"); - - -The ``basic_client`` implements all HTTP methods as member functions -(HEAD, GET, POST, PUT, DELETE). Therefore, the code to make an HTTP -request looks trivially simple: - - -.. code-block:: c++ - - using namespace boost::network; - http::client client; - http::client::request request("http://www.boost.org/"); - http::client::response response = client.get(request); - - -Accessing data from ``http::response`` is done using wrappers. -To get the response headers, we use the ``headers`` wrapper which -returns, in the default case, a multimap of strings to strings: - - -.. code-block:: c++ - - using namespace boost::network; - typedef headers_range::type response_headers; - boost::range_iterator::type iterator; - - response_headers headers_ = headers(response); - for (iterator it = headers_.begin(); it != headers_.end(); ++it) { - std::cout << it->first << ": " << it->second << std::endl; - } - std::cout << std::endl; - - -HTTP server -``````````` - -As with the HTTP client, the HTTP server that is provided with -cpp-netlib is extensible through the tag mechanism and is embeddable. -The template class declaration of ``basic_server`` is given below: - - -.. code-block:: c++ - - namespace boost { namespace network { namespace http { - - template basic_server; - - }}} - - -The second template argument is used to specify the request handler -type. The request handler type is a functor type which should overload -the function call operator (``RequestHandler::operator()`` should be -overloaded) that takes two parameters: the first one being a reference -to a ``const basic_request`` and the second being a reference to -a ``basic_response`` instance. - -All the logic for parsing the HTTP request and building the ``const -basic_request`` object resides internally in the ``basic_server`` -template. Processing the request is delegated to the -``RequestHandler`` type, and the assumption of which would be that the -response is formed inside the ``RequestHandler`` function call -operator overload. - -The ``basic_server`` template however is only an underlying -implementation while the user-visible implementation is the -``http::server`` template. This simply specializes the -``basic_server`` template to use the ``default_`` tag and forwards the -``RequestHandler`` parameter: - -.. code-block:: c++ - - namespace boost { namespace network { namespace http { - - template - class server : - public basic_server {}; - - }}} - -To use the forwarding server type you just supply the request handler -implementation as the parameter. For example, an "echo" server example -might look something like this: - - -.. code-block:: c++ - - using namespace boost::network; - struct echo; - typedef http::server echo_server; - - struct echo { - void operator () (const echo_server::request &request, - echo_server::response &response) const { - std::string ip = source(request); - response = echo_server::response::stock_reply( - echo_server::response::ok, - body(request)); - std::cerr << "[" << ip << "]: " << request.uri << - " status = " << echo_server::response::ok << '\n'; - } - }; - - -Here, all we're doing is returning the original request body with an -HTTP OK response (200). We are also printing the IP address from where the -request came from. Notice that we are using a wrapper to access the source of -the request. diff --git a/libs/network/doc/in_depth/http_client_tags.rst b/libs/network/doc/in_depth/http_client_tags.rst deleted file mode 100644 index 5d79ed1ea..000000000 --- a/libs/network/doc/in_depth/http_client_tags.rst +++ /dev/null @@ -1,42 +0,0 @@ -+---------------------------------+---------------------------------------------+ -| Tag | Description | -+=================================+=============================================+ -| http_default_8bit_tcp_resolve | This is the default HTTP implementation tag | -| | that resolves addresses with a TCP resolver | -| | and provides a synchronous/blocking HTTP | -| | client interface. | -+---------------------------------+---------------------------------------------+ -| http_default_8bit_udp_resolve | This is similar to the above tag except that| -| | it specifies the HTTP client to use a UDP | -| | resolver. It also provides a synchronous/ | -| | blocking HTTP client interface. | -+---------------------------------+---------------------------------------------+ -| http_keepalive_8bit_tcp_resolve | This tag specifies that the HTTP client by | -| | default will keep connections to the server | -| | alive. It only makes sense if the | -| | ``version_major`` and ``version_minor`` are | -| | both ``1``, to indicate HTTP 1.1. This tag | -| | causes the HTTP client to resolve using a | -| | TCP resolver and provides a synchronous/ | -| | blocking HTTP client interface. | -+---------------------------------+---------------------------------------------+ -| http_keepalive_8bit_udp_resolve | This is similar to the above tag except that| -| | it specifies the HTTP client to use a UDP | -| | resolver. It also provides a synchronous/ | -| | blocking HTTP client interface. | -+---------------------------------+---------------------------------------------+ -| http_async_8bit_tcp_resolve | This tag provides an active HTTP client | -| | object implementation that uses a TCP | -| | resolver. Response objects returned will | -| | encapsulate a number of Boost.Thread_ | -| | shared futures to hold values. Users don't | -| | have to see this as they are implementation | -| | details. | -+---------------------------------+---------------------------------------------+ -| http_async_8bit_udp_resolve | This is similar to the above tag except that| -| | specifies the HTTP client to use a UDP | -| | resolver. | -+---------------------------------+---------------------------------------------+ - -.. _Boost.Thread: http://www.boost.org/libs/thread - diff --git a/libs/network/doc/in_depth/message.rst b/libs/network/doc/in_depth/message.rst deleted file mode 100644 index 51512314b..000000000 --- a/libs/network/doc/in_depth/message.rst +++ /dev/null @@ -1,233 +0,0 @@ -The message template -==================== - -One of the core components in the library is the concept and the -implementation of a common message type. In most (not all) network -protocols, the concept of a message is central to the definition of -the protocol. In HTTP, SMTP, XMPP, and even other protocols like SNMP -and ICMP, there is a common notion of a "packet" or a message. In -cpp-netlib we chose to implement the concept of a message that has the -following common parts: - - * **Source** - every message has a source identifier which varies - from protocol to protocol. - - * **Destination** - every message has a destination identifier which - varies from protocol to protocol. - - * **Headers** - each message is assumed to contain headers, which - may be empty in cases where the protocol does not support it, but - is nonetheless supported by cpp-netlib messages. - - * **Body** - the content area of a message which varies from - protocol to protocol (also sometimes referred to as payload). - -This division is purely logical -- in the underlying implementation, -the message type can choose to have different means of storing the -data, depending on the type used to tag the message. This section -covers the `Message Concept`_ as well as the `basic_message`_ -implementation. - -Message Concept -``````````````` - -.. warning:: The Message framework is deprecated in the 0.11 release, and will - be removed in future versions of the library. - -The Message Concept specifies what the valid operations on a message -are as well as what messages look like semantically. The following -table summarize the operations and syntactic as well as semantic -properties of messages. - -**Legend** - -:M: The message type. -:H: A headers container type. -:m,n: An instance of **M**. -:S: A string type. -:s,k,v: An instance of **S**. -:O: The source type. -:D: The destination type. -:B: The body type. -:T: The Tag type. - -+----------------------------+----------------------+-----------------------------------------+ -| Construct | Result | Description | -+============================+======================+=========================================+ -| ``typename M::tag`` | T | The nested tag type. | -+----------------------------+----------------------+-----------------------------------------+ -| ``M()`` | Instance of M | Default constructible. | -+----------------------------+----------------------+-----------------------------------------+ -| ``M(m)`` | Instance of M | Copy constructible. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m = n;`` | Reference to m | Assignable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``swap(m, n);`` | ``void`` | Swappable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``source(m);`` | Convertible to O | Retrieve the source of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``destination(m);`` | Convertible to D | Retrieve the destination of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``headers(m);`` | Convertible to H | Retrieve the headers of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``body(m);`` | Convertible to B | Retrieve the body of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << source(s);`` | ``M &`` | Set the source of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << destination(s);`` | ``M &`` | Set the destination of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << header(k, v);`` | ``M &`` | Add a header to ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << remove_header(k);`` | ``M &`` | Remove a header from ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << body(s);`` | ``M &`` | Set the body of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``source(m,s);`` | ``void`` | Set the source of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``destination(m,s);`` | ``void`` | Set the destination of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``add_header(m, k, v);`` | ``void`` | Add a header to ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``remove_header(m, k);`` | ``void`` | Remove a header from ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``clear_headers(m);`` | ``void`` | Clear the headers of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``body(m,s);`` | ``M &`` | Set the body of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ - -Types that model the Message Concept are meant to encapsulate data -that has a source, a destination, one or more named headers, and a -body/payload. Because the accessors and the directives are not -required to be part of the message type that models the Message -Concept, a message can be implemented as a POD type and have all -manipulations performed in the directive implementations, as well as -value transformations done in the accessors. - -Directives, Modifiers, and Wrappers -``````````````````````````````````` - -In the Message Concept definition there are three basic constructs that follow a -certain pattern. These patterns are Directives_, Modifiers_, and Wrappers_. - -Directives -~~~~~~~~~~ - -A directive is a function object that is applied to a Message. Directives -encapsulate a set of operations that apply to messages. The general requirement -for a Directive is that it should apply these operations on a message. - -A directive may dispatch on the type of the message passed to it at the point of -the function call. Typically, directives are generated using a factory function -that returns the correct directive type. - -For a given directive ``foo_directive`` a generator function called ``foo`` is -typically implemented: - -.. code-block:: c++ - - struct foo_directive { - template - Message & operator()(Message & m) const { - // do something to m - return m; - } - }; - - foo_directive const foo() { - return foo_directive(); - } - - // to apply a directive, we use the << operator - message m; - m << foo(); - -Modifiers -~~~~~~~~~ - -A modifier is generally defined as a free function that takes a reference to a -non-const lvalue message as the first parameter, and any number of parameters. -In the concept definition of the Message Concept, a modifier follows the form: - -.. code-block:: c++ - - modifier(message, ...) - -Modifiers are meant to imply modifications on a message, which also allows for -easier dispatch based on Argument Dependent Lookup (ADL_) on the type of the -message. Note that Directives_ can be implemented in terms of Modifiers and -vice versa, although that is not required nor specified. - -.. _ADL: http://en.wikipedia.org/wiki/Argument-dependent_name_lookup - -Wrappers -~~~~~~~~ - -A Wrapper is basically an implementation detail that ensures that a given -message, when wrapped, can be converted to the associated part of the message. A -wrapper has a type that encapsulates the conversion logic from a message to a -given type. - -An example of a Wrapper would be ``source_wrapper`` which would be returned by a -call to the wrapper generator function ``source``. An example implementation of -the ``source_wrapper`` would look like: - -.. code-block:: c++ - - template class Message> - struct source_wrapper { - Message const & m; - explicit source_wrapper(Message const & m) - : m(m) {} - typedef typename source::type source_type; - operator source_type const & () { - return m.source; - } - operator source_type const () { - return m.source; - } - operator source_type () { - return m.source; - } - }; - - template class Message> - source_wrapper const - source(Message const & message) { - return source_wrapper(message); - } - -This pattern is similar to an adapter, but the specific notion of wrapping a -data type (in this case, an object of a type that models the Message Concept) -using an intermediary wrapper is what is pertained to by the Wrapper pattern. -In this case, the Wrapper is ``source_wrapper`` while ``source`` is merely a -wrapper generator function. - -``basic_message`` -````````````````` - -The default implementation of a simple type that models the Message -Concept is available in cpp-netlib. This default implementation is -named ``basic_message`` which supports a ``Tag`` template -parameter. The definition of ``basic_message`` looks like this: - -.. code-block:: c++ - - template - class basic_message; - -The ``basic_message`` template requires that the following -tag-dispatched metafunctions are defined for the type ``Tag``: - -.. code-block:: c++ - - template - struct string; - - template - struct headers_container; - -All the operations defined by the message concept are implemented by -this basic message type. Other message implementations can either use -this common message type or specialize it according to whether they -want to use different containers or whether it's going to be just a -POD type. diff --git a/libs/network/doc/in_depth/uri.rst b/libs/network/doc/in_depth/uri.rst deleted file mode 100644 index 84eca62e2..000000000 --- a/libs/network/doc/in_depth/uri.rst +++ /dev/null @@ -1,151 +0,0 @@ -The URI class -============= - -In addition to protocol implementations, the :mod:`cpp-netlib` -provides a powerful URI class. The class implements a parser based -on `RFC 3986`_ and `RFC 2732`_. - -Generic URI syntax overview -``````````````````````````` - -A generic URI will take the form:: - - [scheme:]scheme-specific-part[#fragment] - -A URI is known as `absolute` if it specifies the scheme. Otherwise, -it is known as a relative URI. Currently, ``uri`` supports only -absolute URIs. - -URIs can be further classified according to whether they're -hierarchical or opaque (non-hierarchical). - -Some examples of non-hierarchical URIs include:: - - mailto:john.doe@example.com - news:comp.infosystems.www.servers.unix - tel:+1-816-555-1212 - -The data following the first ``":"`` is said to be opaque to the URI -parser and requires no further parsing. By way of example, the -following shows how a non-hierarchical URI is processed by the parser -by defining everything after the ``":"`` to be a part of the path: - -.. image:: ../_static/mailto_uri.png - -A hierarchical URI is identified by a double slash (``"//"``) after -the scheme and a scheme-specific component, which `RFC 3986`_ defines -to be:: - - [scheme:][//authority][path][?query][#fragment] - -The authority component can be further broken down to:: - - [user_info@]host[:port] - -Examples of hierarchical URIs include:: - - http://www.boost.org/ - file:///bin/bash - -The following example, describing a complex URI using FTP, shows how -a URI is broken down by the parser: - -.. image:: ../_static/ftp_uri.png - -Note that the ``authority`` is further subdivided into different -elements. Another example, using HTTP is given below: - -.. image:: ../_static/http_uri.png - -The difference here between the path in a hierarchical URI and that in -the example above for the non-hierarchical URI. - -The ``uri`` class -````````````````` - -As of version 0.9.3, ``uri`` supplies a URI parser and builder. -To use the parser, it's as simple as supplying a string to the -constructor: - -.. code-block:: c++ - - using namespace boost::network; - uri::uri instance("http://cpp-netlib.github.com/"); - assert(instance.is_valid()); - std::cout << "scheme: " << instance.scheme() << std::endl - << "host: " << instance.host() << std::endl; - -The command-line output of this program will be:: - - scheme: http - host: cpp-netlib.github.com - -The ``uri`` builder -``````````````````` - -``uri`` support a stream style syntax to create a URI from it's -elements. For example the program: - -.. code-block:: c++ - - #include - #include - #include - using namespace boost::network; - - int main() { - uri::uri url; - url << uri::scheme("http") - << uri::host("www.github.com") - << uri::path("/cpp-netlib"); - std::cout << url << std::endl; - return 0; - } - -will output:: - - http://www.github.com/cpp-netlib - -``URI Concept`` -``````````````` - -**Legend** - -:U: The URI type. -:u,u_: An instance of **M**. -:S: A string type. -:s,v: An instance of **S**. -:T: The Tag type. - -+----------------------------+----------------------+-----------------------------------------+ -| Construct | Result | Description | -+============================+======================+=========================================+ -| ``U(u)`` | Instance of U | Copy constructible. | -+----------------------------+----------------------+-----------------------------------------+ -| ``U(s)`` | Instance of U | Constructible from string. | -+----------------------------+----------------------+-----------------------------------------+ -| ``u = u_;`` | Reference to u | Assignable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``u = s;`` | Reference to u | Assignable from string. | -+----------------------------+----------------------+-----------------------------------------+ -| ``swap(u, u_);`` | ``void`` | Swappable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``scheme(u);`` | Convertible to S | Retrieve the URI scheme of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``user_info(u);`` | Convertible to S | Retrieve the user info of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``host(u);`` | Convertible to S | Retrieve the host of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``port(u);`` | Convertible to H | Retrieve the port of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``path(u);`` | Convertible to S | Retrieve the path of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``query(u);`` | Convertible to S | Retrieve the query string of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``fragment(u);`` | Convertible to S | Retrieve the fragment of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ - -.. _`RFC 3986`: http://tools.ietf.org/html/rfc3986 -.. _`RFC 2368`: http://tools.ietf.org/html/rfc2368 -.. _`RFC 3513`: http://tools.ietf.org/html/rfc3513 -.. _`RFC 2732`: http://tools.ietf.org/html/rfc2732 diff --git a/libs/network/doc/index.rst b/libs/network/doc/index.rst index fc9e65405..3329b8a30 100644 --- a/libs/network/doc/index.rst +++ b/libs/network/doc/index.rst @@ -108,7 +108,6 @@ Want to learn more? * :ref:`Take a look at the getting started guide ` * :ref:`Learn from some simple examples ` * :ref:`Find out what's new ` - * :ref:`Study the library in more depth ` * :ref:`Discover more through the full reference ` * :ref:`Full table of contents ` diff --git a/libs/network/doc/techniques.rst b/libs/network/doc/techniques.rst deleted file mode 100644 index b52bf7e36..000000000 --- a/libs/network/doc/techniques.rst +++ /dev/null @@ -1,12 +0,0 @@ -Techniques -========== - -The :mod:`cpp-netlib` uses several advanced techniques to achieve it's -aims. This chapter describes some of those techniques. - -.. toctree:: - :maxdepth: 1 - - techniques/tag_metafunctions - techniques/directives - techniques/polymorphism diff --git a/libs/network/doc/techniques/directives.rst b/libs/network/doc/techniques/directives.rst deleted file mode 100644 index e40882d95..000000000 --- a/libs/network/doc/techniques/directives.rst +++ /dev/null @@ -1,92 +0,0 @@ -Directives -========== - -The :mod:`cpp-netlib` uses a technique for allowing message-passing -semantics in a chainable fashion in the form of directives. The basic -concept for directives is, in a general sense, an encapsulated -transformation that can be applied to objects that abide by the -directive protocol. - -Using the object-oriented notion of message passing, where an object -accepts a message (usually a function call) we define a simple DSEL in -order for the protocol to be supported by certain object types. In the -:mod:`cpp-netlib` the protocol implemented is similar to that of the -standard iostream formatting system: - -.. code-block:: c++ - - object << directive1(...) - << directive2(...) - ... - << directiveN(...); - -In :mod:`cpp-netlib` the directives are simple function objects that -take a target object as reference and returns a reference to the same -object as a result. In code the directive pattern looks like the -following: - -.. code-block:: c++ - - struct directive_type { - template - Input & operator()(Input & input) const { - // do something to input - return input; - } - }; - -To simplify directive creation, usually factory or generator functions -are defined to return concrete objects of the directive's type. - -.. code-block:: c++ - - inline - directive_type directive(...) { - return directive_type(); - } - -The trivial implementation of the directive protocol then boils down -to the specialization of the shift-left operator on the target type. - -.. code-block:: c++ - - template - inline target_type & operator<< - (target_type & x, Directive const & f) { - return f(x); - } - -.. todo:: - - An example using a directive. - -The rationale for implementing directives include the following: - - * **Encapsulation** - by moving logic into the directive types the - target object's interface can remain rudimentary and even hidden - to the user's immediate attention. Adding this layer of - indirection also allows for changing the underlying - implementations while maintaining the same syntactic and semantic - properties. - * **Flexibility** - by allowing the creation of directives that are - independent from the target object's type, generic operations can - be applied based on the concept being modeled by the target - type. The flexibility also afforded comes in the directive's - generator function, which can also generate different concrete - directive specializations based on parameters to the function. - * **Extensibility** - because the directives are independent of the - target object's type, new directives can be added and supported - without having to change the target object at all. - * **Reuse** - truly generic directives can then be used for a broad - set of target object types that model the same concepts supported - by the directive. Because the directives are self-contained - objects, the state and other object references it keeps are only - accessible to it and can be re-used in different contexts as well. - -Extending a system that uses directives is trivial in header-only -systems because new directives are simply additive. The protocol is -simple and can be applied to a broad class of situations. - -In a header-only library, the static nature of the wiring and chaining -of the operations lends itself to compiler abuse. A deep enough -nesting of the directives can lead to prolonged compilation times. diff --git a/libs/network/doc/techniques/polymorphism.rst b/libs/network/doc/techniques/polymorphism.rst deleted file mode 100644 index d5e42f8c9..000000000 --- a/libs/network/doc/techniques/polymorphism.rst +++ /dev/null @@ -1,92 +0,0 @@ -Static and dynamic polymorphism -=============================== - - -With a header only library, you can only do so much with static -polymorphism alone. There are some situations where you have to handle -dynamic polymorphism because of unavoidable runtime-based decision -making. Although you can deal with the base types that remain static, -behavior can vary greatly which derived type should be handling the -situation based on runtime values. - -This situation comes up in the :mod:`cpp-netlib` when we decide what -kind of connection handler to use for a given HTTP URI -- whether it's -plain HTTP or HTTPS. Although the HTTP semantics are the same for -HTTP and HTTPS the implementation of the connection handler greatly -varies on whether to use a plain TCP connection or an SSL-wrapped TCP -connection. - -The general pattern or technique is to combine tag-based dispatch with -a strategy factory, all while not requiring any externally built -libraries. Doing it in a header-only library requires a little -creativity and additional layers of indirection that you otherwise -will not need for a library with externally built static/dynamic -libraries. - -First we define the base type which we want to support dynamic -behavior with. There's nothing special with the base type, except -that it supports the tag dispatch earlier defined and has a virtual -destructor. In code it looks like this: - -.. code-block:: c++ - - template - struct base { - virtual void foo() = 0; // make this an abstract base - virtual ~base() { - // do the base destructor thing here. - } - }; - -We then define a set of derived types that specialize the -implementation of the ``foo`` member function. To facilitate the -dispatch of the correct type based on an input, we create a strategy -factory function: - -.. code-block:: c++ - - template - unique_ptr > strategy(int input, Tag) { - unique_ptr > ptr; - switch(input) { - case 0: ptr.reset(new derived0()); break; - case 1: ptr.reset(new derived1()); break; - // ... - default: ptr.reset(0); break; - } - return ptr; - } - - unique_ptr > ptr = - strategy(input, default_()); // input is a runtime value - -The strategy factory can be a standalone function, or a static member -of a factory class that is specialized by tag dispatch. This can be -done like the following: - -.. code-block:: c++ - - template - struct strategy; - - template <> - struct strategy { - static unique_ptr > create(int input) { - unique_ptr > ptr; - switch(input) { - case 0: ptr.reset(new derived0()); break; - case 1: ptr.reset(new derived1()); break; - //... - default: ptr.reset(0); break; - } - return ptr; - } - }; - -This approach allows the header-only libraries to define new dynamic -types in subsequent versions of the library while keeping the -static-dynamic bridge fluid. The only down-side to this is the -possibility of derived type explosion in case there are a lot of -different strategies or specializations available -- this though is -not unique to static-dynamic bridging, but is also a problem with pure -object oriented programming with dynamic polymorphism. diff --git a/libs/network/doc/techniques/tag_metafunctions.rst b/libs/network/doc/techniques/tag_metafunctions.rst deleted file mode 100644 index 68edd1449..000000000 --- a/libs/network/doc/techniques/tag_metafunctions.rst +++ /dev/null @@ -1,172 +0,0 @@ -Tag metafunctions -================= - -Sometimes you want to vary a function or a type's behavior based on a -static parameter. In the :mod:`cpp-netlib` there are a number of -things you might want to change based on some such parameter -- like -what the underlying string type should be and how large a buffer -should be, among other things. The primary way to define this in a -header-only manner is to use tag-based metafunctions. - -The skeleton of the approach is based on a similar technique for -defining type traits. In the :mod:`cpp-netlib` however the type traits -are defined on opaque tag types which serve to associate results to a -family of metafunctions. - -Template Specialization ------------------------ - -To illustrate this point, let's define a tag ``default_`` which we use -to denote the default implementation of a certain type ``foo``. For -instance we decide that the default string type we will use for -``default_`` tagged ``foo`` specializations will be an -``std::string``. - -In the :mod:`cpp-netlib` this is done by defining a ``string`` -metafunction type that is specialized on the tag ``default_`` whose -nested ``type`` result is the type ``std::string``. In code this would -translate to: - -.. code-block:: c++ - - template - struct string { - typedef void type; - }; - - struct default_; - - template <> - struct string { - typedef std::string type; - }; - -Template Metaprogramming ------------------------- - -Starting with version 0.7, the tag dispatch mechanism changed slightly to use -Boost.MPL_. The idea is still the same, although we can get a little smarter -than just using template specializations. Instead of just defining an opaque -type ``default_``, we use the Boost.MPL equivalent of a vector to define which -root types of properties this ``default_`` tag supports. The idea is to make the -opaque type ``default_`` inherit property tags which the library supports -internally as definite extension points. - -.. _Boost.MPL: http://www.boost.org/libs/mpl/index.html - -Our definition of the ``default_`` tag will then look something like the -following: - -.. code-block:: c++ - - typedef mpl::vector default_tags; - - template - struct components; - - typedef mpl::inherit_linearly< - default_tags, - mpl::inherit - >::type default_; - - template - struct components { - typedef default_tags type; - }; - -In the above listing, ``default_string`` is what we call a "root" tag which is -meant to be combined with other "root" tags to form composite tags. In this case -our composite tag is the tag ``default_``. There are a number of these "root" -tags that :mod:`cpp-netlib` provides. These are in the namespace -``boost::network::tags`` and are defined in ``boost/network/tags.hpp``. - -Using this technique we change slightly our definition of the ``string`` -metafunction class into this: - -.. code-block:: c++ - - template - struct unsupported_tag; - - template - struct string : - mpl::if_< - is_base_of< - tags::default_string, - Tag - >, - std::string, - unsupported_tag - > - {}; - -Notice that we don't have the typedef for ``type`` in the body of ``string`` -anymore, but we do inherit from ``mpl::if_``. Since ``mpl::if_`` is a template -metafunction itself, it contains a definition of the resulting ``type`` which -``string`` inherits. - -You can see the real definition of the ``string`` metafunction in -``boost/network/traits/string.hpp``. - -Using Tags ----------- - -Once we have the defined tag, we can then use this in the definition of our -types. In the definition of the type ``foo`` we use this type function -``string`` and pass the tag type parameter to determine what to use as -the string type in the context of the type ``foo``. In code this would -translate into: - -.. code-block:: c++ - - template - struct foo { - typedef typename string::type string_type; - - // .. use string_type where you need a string. - }; - -Using this approach we can support different types of strings for -different tags on the type ``foo``. In case we want to use a different -type of string for the tag ``default_`` we only change the -composition of the ``string_tags`` MPL vector. For example, in :mod:`cpp-netlib` -there is a root tag ``default_wstring`` which causes the ``string`` metafunction -to define ``std::wstring`` as the resulting type. - -The approach also allows for the control of the structure and features -of types like ``foo`` based on the specialization of the tag. Whole -type function families can be defined on tags where they are supported -and ignored in cases where they are not. - -To illustrate let's define a new tag ``swappable``. Given the above -definition of ``foo``, we want to make the ``swappable``-tagged -``foo`` define a ``swap`` function that extends the original -``default_``-tagged ``foo``. In code this would look like: - -.. code-block:: c++ - - struct swappable; - - template <> - struct foo : foo { - void swap(foo & other) { - // ... - } - }; - -We also for example want to enable an ADL-reachable ``swap`` function: - -.. code-block:: c++ - - struct swappable; - - inline - void swap(foo & left, foo & right) { - left.swap(right); - } - -Overall what the tag-based definition approach allows is for static -definition of extension points that ensures type-safety and -invariants. This keeps the whole extension mechanism static and yet -flexible. - From 90e2198f937846f70ef11e639c3c227e38fd9ad3 Mon Sep 17 00:00:00 2001 From: Dean Berris Date: Tue, 29 Mar 2016 23:55:36 +1100 Subject: [PATCH 003/112] Remove references to sync server, use Doxygen for reference docs --- libs/network/doc/reference/http_server.rst | 493 +++------------------ 1 file changed, 57 insertions(+), 436 deletions(-) diff --git a/libs/network/doc/reference/http_server.rst b/libs/network/doc/reference/http_server.rst index 26ceb9b65..c0022bdda 100644 --- a/libs/network/doc/reference/http_server.rst +++ b/libs/network/doc/reference/http_server.rst @@ -5,9 +5,9 @@ HTTP Server API General ------- -:mod:`cpp-netlib` includes and implements two distinct HTTP server -implementations that you can use and embed in your own applications. Both HTTP -Server implementations: +:mod:`cpp-netlib` includes and implements and asynchronous HTTP server +implementation that you can use and embed in your own applications. The HTTP +Server implementation: * **Cannot be copied.** This means you may have to store instances of the HTTP Server in dynamic memory if you intend to use them as function parameters or @@ -15,60 +15,19 @@ Server implementations: * **Assume that requests made are independent of each other.** None of the HTTP Server implementations support request pipelining (yet) so a single connection only deals with a single request. - * **Are header-only and are compiled-into your application.** Future releases - in case you want to upgrade the implementation you are using in your - application will be distributed as header-only implementations, which means - you have to re-compile your application to use a newer version of the - implementations. - -The HTTP Servers have different semantics, and in some cases require different -APIs from the supplied template parameters. - -Implementations ---------------- - -There are two different user-facing template classes that differentiate the -`Synchronous Servers`_ from the `Asynchronous Servers`_. Both templates take a -single template parameter named ``Handler`` which describes the type of the -Handler function object. - -There are two different Handler concepts, one concept for `Synchronous Servers`_ -and another for `Asynchronous Servers`. - -The SynchronousHandler concept for `Synchronous Servers`_ is described by the -following table: - ---------------- - -**Legend:** - -H - The Handler type. -h - An instance of H. -Req - A type that models the Request Concept. -Res - A type that models the Response Concept. -req - An instance of Req. -res - An instance of Res. - -+----------------+-------------+----------------------------------------------+ -| Construct | Return Type | Description | -+================+=============+==============================================+ -| ``h(req,res)`` | ``void`` | Handle the request; res is passed in as a | -| | | non-const lvalue, which represents the | -| | | response to be returned to the client | -| | | performing the request. | -+----------------+-------------+----------------------------------------------+ - -More information about the internals of the `Synchronous Servers`_ can be found -in the following section. - -The AsynchronousHandler concept for `Asynchronous Servers`_ is described by the -following table: + * **The Handler instance is invoked asynchronously**. This means the I/O + thread used to handle network-related events are free to handle only the + I/O related events. This enables the server to scale better as to the + number of concurrent connections it can handle. + * **The Handler is able to schedule asynchronous actions on the thread pool + associated with the server.** This allows handlers to perform multiple + asynchronous computations that later on perform writes to the connection. + * **The Handler is able to control the (asynchronous) writes to and reads + from the HTTP connection.** Because the connection is available to the + Handler, that means it can write out chunks of data at a time or stream + data through the connection continuously. + +The Handler concept for the HTTP Server is described by the following table: --------------- @@ -95,270 +54,30 @@ conn | | | writing to and reading from the connection.| +------------------+-------------+--------------------------------------------+ -More information about the internals of the `Asynchronous Servers`_ can be found -in the following section. - -Synchronous Servers -------------------- - -The synchronous server implementation is represented by the template ``server`` -in namespace ``boost::network::http``. The ``server`` template takes in a single -template parameter named ``Handler`` which models the SynchronousHandler -concept (described above). - -An instance of Handler is taken in by reference to the constructor of the HTTP -server. This means the Handler is not copied around and only a single instance -of the handler is used for all connections and requests performed against the -HTTP server. - -.. warning:: It is important to note that the HTTP server does not implement any - locking upon invoking the Handler. In case you have any state in the Handler - that will be associated with the synchronous server, you would have to - implement your own synchronization internal to the Handler implementation. - This matters especially if you run the synchronous server in multiple - threads. - -The general pattern of usage for the HTTP Server template is shown below: - -.. code-block:: c++ - - struct handler; - typedef boost::network::http::server http_server; - - struct handler { - void operator()( - http_server::request const & req, - http_server::response & res - ) { - // do something, and then edit the res object here. - } - }; - -More information about the actual HTTP Server API follows in the next section. -It is important to understand that the HTTP Server is actually embedded in your -application, which means you can expose almost all your application logic -through the Handler type, which you can also initialize appropriately. - -API Documentation -~~~~~~~~~~~~~~~~~ - -The following sections assume that the following file has been included: - -.. code-block:: c++ - - #include - -And that the following typedef's have been put in place: - -.. code-block:: c++ - - struct handler_type; - typedef boost::network::http::server http_server; - - struct handler_type { - void operator()(http_server::request const & request, - http_server::response & response) { - // do something here - } - }; - -Constructor -``````````` - -``explicit http_server(options)`` - Construct an HTTP Server instance, passing in a ``server_options`` object. The following table shows the supported options in - ``server_options``. - -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| Parameter Name | Type | Description | -+=======================+==========================================+==================================================================================================+ -| address | string_type | The hostname or IP address from which the server should be bound to. This parameter is required. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| port | string_type | The port to which the server should bind and listen to. This parameter is required. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| thread_pool | ``shared_ptr`` | A shared pointer to an instance of ``boost::network::utils::thread_pool`` -- this is the | -| | | thread pool from where the handler is invoked. This parameter is only applicable and required | -| | | for ``async_server`` instances. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| io_service | ``shared_ptr`` | An optional lvalue to an instance of ``boost::asio::io_service`` which allows the server to use | -| | | an already-constructed ``boost::asio::io_service`` instance instead of instantiating one that it | -| | | manages. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| reuse_address | ``bool`` | A boolean that specifies whether to re-use the address and port on which the server will be | -| | | bound to. This enables or disables the socket option for listener sockets. The default is | -| | | ``false``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| report_aborted | ``bool`` | A boolean that specifies whether the listening socket should report aborted connection attempts | -| | | to the accept handler (an internal detail of cpp-netlib). This is put in place to allow for | -| | | future-proofing the code in case an optional error handler function is supported in later | -| | | releases of cpp-netlib. The default is ``false``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| receive_buffer_size | ``int`` | The size of the socket's receive buffer. The default is defined by Boost.Asio and is | -| | | platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| send_buffer_size | ``int`` | The size of the socket's send buffer. The default is defined by Boost.Asio and is | -| | | platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| receive_low_watermark | ``int`` | The size of the socket's low watermark for its receive buffer. The default is defined by | -| | | Boost.Asio and is platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| send_buffer_size | ``int`` | The size of the socket's send low watermark for its send buffer. The default is defined by | -| | | Boost.Asio and is platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| non_blocking_io | ``bool`` | An optional bool to define whether the socket should use non-blocking I/O in case the platform | -| | | supports it. The default is ``true``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| linger | ``bool`` | An optional bool to determine whether the socket should linger in case there's still data to be | -| | | sent out at the time of its closing. The default is ``true``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| linger_timeout | ``int`` | An optional int to define the timeout to wait for socket closes before it is set to linger. | -| | | The default is ``0``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| context | ``shared_ptr`` | An optional shared pointer to an instance of ``boost::asio::ssl::context`` -- this contains the | -| | | settings needed to support SSL. This parameter is only applicable for ``async_server`` instances.| -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ - -To use the above supported named parameters, you'll have code that looks like the following: - -.. code-block:: c++ - - using namespace boost::network::http; // parameters are in this namespace - handler handler_instance; - sync_server::options options(handler_instance); - options.address("0.0.0.0") - .port("80") - .io_service(boost::make_shared()) - .reuse_address(true); - sync_server instance(options); - instance.run(); - -Public Members -`````````````` - -The following definitions assume that a properly constructed ``http_server`` -instance has been constructed in the following manner: - -.. code-block:: c++ - - handler_type handler; - http_server::options options(handler); - http_server server(options.address("127.0.0.1").port("8000")); - -``server.run()`` - Run the HTTP Server event loop. This function can be run on multiple threads - following the example: - -.. code-block:: c++ - - boost::thread t1(boost::bind(&http_server::run, &server)); - boost::thread t2(boost::bind(&http_server::run, &server)); - server.run(); - t1.join(); - t2.join(); - -``server.stop()`` - Stop the HTTP Server acceptor and wait for all pending requests to finish. - -Response Object -``````````````` - -The response object has its own public member functions which can be very -helpful in certain simple situations. - -``response = http_server::response::stock_reply(status, body)`` - Code like the above should go inside the handler's ``operator()`` overload. - The body parameter is an ``std::string``. The status parameter is any of - the following values from the ``http_server::response`` enum - ``status_type``: - -.. code-block:: c++ - - enum status_type { - ok = 200, - created = 201, - accepted = 202, - no_content = 204, - multiple_choices = 300, - moved_permanently = 301, - moved_temporarily = 302, - not_modified = 304, - bad_request = 400, - unauthorized = 401, - forbidden = 403, - not_found = 404, - not_supported = 405, - not_acceptable = 406, - internal_server_error = 500, - not_implemented = 501, - bad_gateway = 502, - service_unavailable = 503 - }; +--------------- -The response object also has the following publicly accessible member values -which can be directly manipulated by the handler. - -+------------------+----------------------+------------------------------------+ -| Member Name | Type | Description | -+==================+======================+====================================+ -| status | ``status_type`` | The HTTP status of the response. | -+------------------+----------------------+------------------------------------+ -| headers | ``vector
`` | Vector of headers. [#]_ | -+------------------+----------------------+------------------------------------+ -| content | ``string_type`` [#]_ | The contents of the response. | -+------------------+----------------------+------------------------------------+ - -.. [#] A header is a struct of type - ``response_header``. An instance always has the - members ``name`` and ``value`` both of which are of type ``string_type``. -.. [#] ``string_type`` is - ``boost::network::string::type``. - -Asynchronous Servers --------------------- - -The asynchronous server implementation is significantly different to the -synchronous server implementation in three ways: - - #. **The Handler instance is invoked asynchronously**. This means the I/O - thread used to handle network-related events are free to handle only the - I/O related events. This enables the server to scale better as to the - number of concurrent connections it can handle. - #. **The Handler is able to schedule asynchronous actions on the thread pool - associated with the server.** This allows handlers to perform multiple - asynchronous computations that later on perform writes to the connection. - #. **The Handler is able to control the (asynchronous) writes to and reads from - the HTTP connection.** Because the connection is available to the Handler, - that means it can write out chunks of data at a time or stream data through - the connection continuously. - -The asynchronous server is meant to allow for better scalability in terms of the -number of concurrent connections and for performing asynchronous actions within -the handlers. If your application does not need to write out information -asynchronously or perform potentially long computations, then the synchronous -server gives a generally better performance profile than the asynchronous -server. - -The asynchronous server implementation is available from a single user-facing -template named ``async_server``. This template takes in a single template +The HTTP Server is meant to allow for better scalability in terms of the number +of concurrent connections and for performing asynchronous actions within the +handlers. The HTTP Server implementation is available from a single +user-facing template named ``server``. This template takes in a single template parameter which is the type of the Handler to be called once a request has been parsed from a connection. -An instance of Handler is taken as a reference to the constructor similar to the -synchronous server implementation. +An instance of Handler is taken as a reference to the constructor of the server +instance. -.. warning:: The asynchronous server implementation, like the synchronous server - implementation, does not perform any synchronization on the calls to the - Handler invocation. This means if your handler contains or maintains internal - state, you are responsible for implementing your own synchronization on - accesses to the internal state of the Handler. +.. warning:: The HTTP Server implementation does not perform any + synchronization on the calls to the Handler invocation. This means if your + handler contains or maintains internal state, you are responsible for + implementing your own synchronization on accesses to the internal state of + the Handler. -The general pattern for using the ``async_server`` template is shown below: +The general pattern for using the ``server`` template is shown below: .. code-block:: c++ struct handler; - typedef boost::network::http::async_server http_server; + typedef boost::network::http::server http_server; struct handler { void operator()( @@ -371,7 +90,7 @@ The general pattern for using the ``async_server`` template is shown below: }; API Documentation -~~~~~~~~~~~~~~~~~ +----------------- The following sections assume that the following file has been included: @@ -395,135 +114,36 @@ And that the following typedef's have been put in place: }; Constructor -``````````` +~~~~~~~~~~~ ``explicit http_server(options)`` Construct an HTTP server instance passing in a ``server_options`` instance. -Public Members -`````````````` - -The following definitions assume that a properly constructed ``http_server`` -instance has been constructed in the following manner: +Server Options +~~~~~~~~~~~~~~ -.. code-block:: c++ - - handler_type handler; - http_server::options options(handler); - options.thread_pool(boost::make_shared(2)); - http_server server(options.address("127.0.0.1").port("8000")); - -``server.run()`` - Run the HTTP Server event loop. This function can be run on multiple threads - following the example: - -.. code-block:: c++ +.. doxygenstruct:: boost::network::http::server_options + :project: cppnetlib + :members: - boost::thread t1(boost::bind(&http_server::run, &server)); - boost::thread t2(boost::bind(&http_server::run, &server)); - server.run(); - t1.join(); - t2.join(); +Public Members +~~~~~~~~~~~~~~ -``server.stop()`` - Stop the HTTP Server acceptor and wait for all pending requests to finish. +.. doxygenstruct:: boost::network::http::server + :project: cppnetlib + :members: + :undoc-members: Connection Object -````````````````` - -The connection object has its own public member functions which will be the -primary means for reading from and writing to the connection. - -``template write(Range range)`` - The connection object exposes a function ``write`` that can be given a - parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept. - The write function, although it looks synchronous, starts of a series of - asynchronous writes to the connection as soon as the range is serialized to - appropriately sized buffers. - - To use this in your handler, it would look something like this: - -.. code-block:: c++ - - connection->write("Hello, world!"); - std::string sample = "I have a string!"; - connection->write(sample); - -``template void write(Range range, Callback callback)`` - The connection object also exposes a function ``write`` that can be given a - parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept, as - well as a Callback function that returns ``void`` and takes a - ``boost::system::error_code`` as a parameter. This overload of ``write`` is - useful for writing streaming applications that send out chunks of data at a - time, or for writing data that may not all fit in memory right away. - -``template void read(ReadCallback callback)`` - The connection object has a function ``read`` which can be used to read more - information from the connection. This ``read`` function takes in a callback - that can be assigned to a Boost.Function_ with the signature - ``void(input_range,error_code,size_t,connection_ptr)``. The following list - shows what the types actually mean: - - * **input_range** -- ``boost::iterator_range`` : The range - that denotes the data read from the connection. - * **error_code** -- ``boost::system::error_code`` : The error code if - there were any errors encountered from the read. - * **size_t** -- ``std::size_t`` : The number of bytes transferred. - * **connection_ptr** -- ``http_server::connection_ptr`` : A handle to the - current connection, so that it is kept alive at the time of the read - callback invocation. - - This interface is useful when doing reads of uploaded data that can be - potentially large and may not fit in memory. The read handler is then - responsible for dealing with the chunks of data available from the - connection. - -``void set_status(status_t new_status)`` - The ``set_status`` function takes a parameter of type ``status_t`` which is - an enum type nested in ``http_status::connection`` which is given in the - following code listing. - -.. code-block:: c++ - - enum status_t { - ok = 200 - , created = 201 - , accepted = 202 - , no_content = 204 - , multiple_choices = 300 - , moved_permanently = 301 - , moved_temporarily = 302 - , not_modified = 304 - , bad_request = 400 - , unauthorized = 401 - , forbidden = 403 - , not_found = 404 - , not_supported = 405 - , not_acceptable = 406 - , internal_server_error = 500 - , not_implemented = 501 - , bad_gateway = 502 - , service_unavailable = 503 - }; - -.. note:: You may set and re-set the status several times as long as you have - not set the headers or sent data through the connection. If you do this after - data has already been set, the function will throw an instance of - ``std::logic_error``. - -``template void set_headers(Range range)`` - The ``set_headers`` function takes a Single Pass Range of - ``boost::network::http::response_header`` - instances and linearizes them to a buffer with at most - ``BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE`` and - immediately schedules an asynchronous write once that is done. +~~~~~~~~~~~~~~~~~ - The function throws an instance of ``std::logic_error`` if you try to set - the headers for a connection more than once. +.. doxygenstruct:: boost::network::http::async_connection + :project: cppnetlib + :members: -Adding SSL support to Asynchronous Server ------------------------------------------ +Adding SSL support to the HTTP Server +------------------------------------- In order to setup SSL support for an Asynchronous Server, it is best to start from a regular Asynchronous Server (see above). Once this server is setup, SSL can be @@ -533,24 +153,25 @@ used are defined in the link. .. code-block:: c++ // Initialize SSL context - boost::shared_ptr ctx = boost::make_shared(boost::asio::ssl::context::sslv23); + std::shared_ptr ctx = + std::make_shared(asio::ssl::context::sslv23); ctx->set_options( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::single_dh_use); + asio::ssl::context::default_workarounds + | asio::ssl::context::no_sslv3 + | asio::ssl::context::single_dh_use); // Set keys ctx->set_password_callback(password_callback); ctx->use_certificate_chain_file("server.pem"); - ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem); + ctx->use_private_key_file("server.pem", asio::ssl::context::pem); ctx->use_tmp_dh_file("dh512.pem"); handler_type handler; http_server::options options(handler); - options.thread_pool(boost::make_shared(2)); + options.thread_pool(std::make_shared(2)); http_server server(options.address("127.0.0.1").port("8442").context(ctx)); - std::string password_callback(std::size_t max_length, boost::asio::ssl::context_base::password_purpose purpose) { + std::string password_callback(std::size_t max_length, asio::ssl::context_base::password_purpose purpose) { return std::string("test"); } From 3a98ee489d7819f90cd267890ae31ef323f703cd Mon Sep 17 00:00:00 2001 From: Dean Berris Date: Tue, 29 Mar 2016 23:55:52 +1100 Subject: [PATCH 004/112] Regenerate HTML documentation --- libs/network/doc/html/_images/ftp_uri.png | Bin 25570 -> 0 bytes libs/network/doc/html/_images/http_uri.png | Bin 20719 -> 0 bytes libs/network/doc/html/_images/mailto_uri.png | Bin 10220 -> 0 bytes libs/network/doc/html/_sources/contents.txt | 3 - libs/network/doc/html/_sources/history.txt | 54 - libs/network/doc/html/_sources/in_depth.txt | 15 - .../doc/html/_sources/in_depth/http.txt | 180 --- .../_sources/in_depth/http_client_tags.txt | 42 - .../doc/html/_sources/in_depth/message.txt | 233 ---- .../doc/html/_sources/in_depth/uri.txt | 151 --- libs/network/doc/html/_sources/index.txt | 1 - .../html/_sources/reference/http_server.txt | 493 +------ libs/network/doc/html/_sources/techniques.txt | 12 - .../html/_sources/techniques/directives.txt | 92 -- .../html/_sources/techniques/polymorphism.txt | 92 -- .../_sources/techniques/tag_metafunctions.txt | 172 --- libs/network/doc/html/contents.html | 58 +- libs/network/doc/html/examples.html | 2 +- .../doc/html/examples/http/atom_reader.html | 2 +- .../examples/http/hello_world_client.html | 2 +- .../examples/http/hello_world_server.html | 2 +- .../doc/html/examples/http/http_client.html | 2 +- .../doc/html/examples/http/simple_wget.html | 2 +- .../html/examples/http/twitter_search.html | 12 +- libs/network/doc/html/getting_started.html | 2 +- libs/network/doc/html/history.html | 156 --- libs/network/doc/html/in_depth.html | 132 -- libs/network/doc/html/in_depth/http.html | 311 ----- .../doc/html/in_depth/http_client_tags.html | 139 -- libs/network/doc/html/in_depth/message.html | 399 ------ libs/network/doc/html/in_depth/uri.html | 295 ---- libs/network/doc/html/index.html | 3 +- libs/network/doc/html/objects.inv | Bin 1929 -> 4847 bytes libs/network/doc/html/reference.html | 18 +- .../doc/html/reference/http_client.html | 57 +- .../doc/html/reference/http_request.html | 2 +- .../doc/html/reference/http_response.html | 2 +- .../doc/html/reference/http_server.html | 1193 ++++++++++------- libs/network/doc/html/references.html | 2 +- libs/network/doc/html/search.html | 2 +- libs/network/doc/html/searchindex.js | 2 +- libs/network/doc/html/techniques.html | 116 -- .../doc/html/techniques/directives.html | 191 --- .../doc/html/techniques/polymorphism.html | 189 --- .../html/techniques/tag_metafunctions.html | 265 ---- libs/network/doc/html/whats_new.html | 2 +- 46 files changed, 782 insertions(+), 4318 deletions(-) delete mode 100644 libs/network/doc/html/_images/ftp_uri.png delete mode 100644 libs/network/doc/html/_images/http_uri.png delete mode 100644 libs/network/doc/html/_images/mailto_uri.png delete mode 100644 libs/network/doc/html/_sources/history.txt delete mode 100644 libs/network/doc/html/_sources/in_depth.txt delete mode 100644 libs/network/doc/html/_sources/in_depth/http.txt delete mode 100644 libs/network/doc/html/_sources/in_depth/http_client_tags.txt delete mode 100644 libs/network/doc/html/_sources/in_depth/message.txt delete mode 100644 libs/network/doc/html/_sources/in_depth/uri.txt delete mode 100644 libs/network/doc/html/_sources/techniques.txt delete mode 100644 libs/network/doc/html/_sources/techniques/directives.txt delete mode 100644 libs/network/doc/html/_sources/techniques/polymorphism.txt delete mode 100644 libs/network/doc/html/_sources/techniques/tag_metafunctions.txt delete mode 100644 libs/network/doc/html/history.html delete mode 100644 libs/network/doc/html/in_depth.html delete mode 100644 libs/network/doc/html/in_depth/http.html delete mode 100644 libs/network/doc/html/in_depth/http_client_tags.html delete mode 100644 libs/network/doc/html/in_depth/message.html delete mode 100644 libs/network/doc/html/in_depth/uri.html delete mode 100644 libs/network/doc/html/techniques.html delete mode 100644 libs/network/doc/html/techniques/directives.html delete mode 100644 libs/network/doc/html/techniques/polymorphism.html delete mode 100644 libs/network/doc/html/techniques/tag_metafunctions.html diff --git a/libs/network/doc/html/_images/ftp_uri.png b/libs/network/doc/html/_images/ftp_uri.png deleted file mode 100644 index f77d3c87b891e86d794e2ee60255b1f95baf2ddc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25570 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 c6AV1V - struct basic_client; - - } // namespace http - - } // namespace boost - -The ``Tag`` template parameter follows the same tag-dispatch mechanism to -determine the behavior of the ``basic_client``. The interface of -``basic_client`` may change depending on certain properties defined for the tag -you provide. Below is a table of predefined supported tags you can use in your -overload of the ``basic_client``: - ------------- - -.. include:: http_client_tags.rst - -.. _Boost.Thread: http://www.boost.org/libs/thread - - -The default typedef for the HTTP client that is provided uses the -``http_async_8bit_udp_resolve`` tag, and implements HTTP 1.1. The exact -typedef is in the ``boost::network::http`` namespace as the following: - -.. code-block:: c++ - - namespace boost { namespace network { namespace http { - - typedef basic_client - client; - - }}} - - -This type has nested typedefs for the correct types for the ``basic_request`` -and ``basic_response`` templates. To use the correct types for ``basic_request`` -or ``basic_response`` you can use these nested typedefs like so: - - -.. code-block:: c++ - - boost::network::http::client::request request; - boost::network::http::client::response response; - - // or... - using namespace boost::network; - http::client::request request; - http::client::response response; - - -Typical use cases for the HTTP client would look something like the following: - - -.. code-block:: c++ - - using namespace boost::network; - http::request request("http://www.boost.org/"); - request << header("Connection", "close"); - - -The ``basic_client`` implements all HTTP methods as member functions -(HEAD, GET, POST, PUT, DELETE). Therefore, the code to make an HTTP -request looks trivially simple: - - -.. code-block:: c++ - - using namespace boost::network; - http::client client; - http::client::request request("http://www.boost.org/"); - http::client::response response = client.get(request); - - -Accessing data from ``http::response`` is done using wrappers. -To get the response headers, we use the ``headers`` wrapper which -returns, in the default case, a multimap of strings to strings: - - -.. code-block:: c++ - - using namespace boost::network; - typedef headers_range::type response_headers; - boost::range_iterator::type iterator; - - response_headers headers_ = headers(response); - for (iterator it = headers_.begin(); it != headers_.end(); ++it) { - std::cout << it->first << ": " << it->second << std::endl; - } - std::cout << std::endl; - - -HTTP server -``````````` - -As with the HTTP client, the HTTP server that is provided with -cpp-netlib is extensible through the tag mechanism and is embeddable. -The template class declaration of ``basic_server`` is given below: - - -.. code-block:: c++ - - namespace boost { namespace network { namespace http { - - template basic_server; - - }}} - - -The second template argument is used to specify the request handler -type. The request handler type is a functor type which should overload -the function call operator (``RequestHandler::operator()`` should be -overloaded) that takes two parameters: the first one being a reference -to a ``const basic_request`` and the second being a reference to -a ``basic_response`` instance. - -All the logic for parsing the HTTP request and building the ``const -basic_request`` object resides internally in the ``basic_server`` -template. Processing the request is delegated to the -``RequestHandler`` type, and the assumption of which would be that the -response is formed inside the ``RequestHandler`` function call -operator overload. - -The ``basic_server`` template however is only an underlying -implementation while the user-visible implementation is the -``http::server`` template. This simply specializes the -``basic_server`` template to use the ``default_`` tag and forwards the -``RequestHandler`` parameter: - -.. code-block:: c++ - - namespace boost { namespace network { namespace http { - - template - class server : - public basic_server {}; - - }}} - -To use the forwarding server type you just supply the request handler -implementation as the parameter. For example, an "echo" server example -might look something like this: - - -.. code-block:: c++ - - using namespace boost::network; - struct echo; - typedef http::server echo_server; - - struct echo { - void operator () (const echo_server::request &request, - echo_server::response &response) const { - std::string ip = source(request); - response = echo_server::response::stock_reply( - echo_server::response::ok, - body(request)); - std::cerr << "[" << ip << "]: " << request.uri << - " status = " << echo_server::response::ok << '\n'; - } - }; - - -Here, all we're doing is returning the original request body with an -HTTP OK response (200). We are also printing the IP address from where the -request came from. Notice that we are using a wrapper to access the source of -the request. diff --git a/libs/network/doc/html/_sources/in_depth/http_client_tags.txt b/libs/network/doc/html/_sources/in_depth/http_client_tags.txt deleted file mode 100644 index 5d79ed1ea..000000000 --- a/libs/network/doc/html/_sources/in_depth/http_client_tags.txt +++ /dev/null @@ -1,42 +0,0 @@ -+---------------------------------+---------------------------------------------+ -| Tag | Description | -+=================================+=============================================+ -| http_default_8bit_tcp_resolve | This is the default HTTP implementation tag | -| | that resolves addresses with a TCP resolver | -| | and provides a synchronous/blocking HTTP | -| | client interface. | -+---------------------------------+---------------------------------------------+ -| http_default_8bit_udp_resolve | This is similar to the above tag except that| -| | it specifies the HTTP client to use a UDP | -| | resolver. It also provides a synchronous/ | -| | blocking HTTP client interface. | -+---------------------------------+---------------------------------------------+ -| http_keepalive_8bit_tcp_resolve | This tag specifies that the HTTP client by | -| | default will keep connections to the server | -| | alive. It only makes sense if the | -| | ``version_major`` and ``version_minor`` are | -| | both ``1``, to indicate HTTP 1.1. This tag | -| | causes the HTTP client to resolve using a | -| | TCP resolver and provides a synchronous/ | -| | blocking HTTP client interface. | -+---------------------------------+---------------------------------------------+ -| http_keepalive_8bit_udp_resolve | This is similar to the above tag except that| -| | it specifies the HTTP client to use a UDP | -| | resolver. It also provides a synchronous/ | -| | blocking HTTP client interface. | -+---------------------------------+---------------------------------------------+ -| http_async_8bit_tcp_resolve | This tag provides an active HTTP client | -| | object implementation that uses a TCP | -| | resolver. Response objects returned will | -| | encapsulate a number of Boost.Thread_ | -| | shared futures to hold values. Users don't | -| | have to see this as they are implementation | -| | details. | -+---------------------------------+---------------------------------------------+ -| http_async_8bit_udp_resolve | This is similar to the above tag except that| -| | specifies the HTTP client to use a UDP | -| | resolver. | -+---------------------------------+---------------------------------------------+ - -.. _Boost.Thread: http://www.boost.org/libs/thread - diff --git a/libs/network/doc/html/_sources/in_depth/message.txt b/libs/network/doc/html/_sources/in_depth/message.txt deleted file mode 100644 index 51512314b..000000000 --- a/libs/network/doc/html/_sources/in_depth/message.txt +++ /dev/null @@ -1,233 +0,0 @@ -The message template -==================== - -One of the core components in the library is the concept and the -implementation of a common message type. In most (not all) network -protocols, the concept of a message is central to the definition of -the protocol. In HTTP, SMTP, XMPP, and even other protocols like SNMP -and ICMP, there is a common notion of a "packet" or a message. In -cpp-netlib we chose to implement the concept of a message that has the -following common parts: - - * **Source** - every message has a source identifier which varies - from protocol to protocol. - - * **Destination** - every message has a destination identifier which - varies from protocol to protocol. - - * **Headers** - each message is assumed to contain headers, which - may be empty in cases where the protocol does not support it, but - is nonetheless supported by cpp-netlib messages. - - * **Body** - the content area of a message which varies from - protocol to protocol (also sometimes referred to as payload). - -This division is purely logical -- in the underlying implementation, -the message type can choose to have different means of storing the -data, depending on the type used to tag the message. This section -covers the `Message Concept`_ as well as the `basic_message`_ -implementation. - -Message Concept -``````````````` - -.. warning:: The Message framework is deprecated in the 0.11 release, and will - be removed in future versions of the library. - -The Message Concept specifies what the valid operations on a message -are as well as what messages look like semantically. The following -table summarize the operations and syntactic as well as semantic -properties of messages. - -**Legend** - -:M: The message type. -:H: A headers container type. -:m,n: An instance of **M**. -:S: A string type. -:s,k,v: An instance of **S**. -:O: The source type. -:D: The destination type. -:B: The body type. -:T: The Tag type. - -+----------------------------+----------------------+-----------------------------------------+ -| Construct | Result | Description | -+============================+======================+=========================================+ -| ``typename M::tag`` | T | The nested tag type. | -+----------------------------+----------------------+-----------------------------------------+ -| ``M()`` | Instance of M | Default constructible. | -+----------------------------+----------------------+-----------------------------------------+ -| ``M(m)`` | Instance of M | Copy constructible. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m = n;`` | Reference to m | Assignable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``swap(m, n);`` | ``void`` | Swappable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``source(m);`` | Convertible to O | Retrieve the source of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``destination(m);`` | Convertible to D | Retrieve the destination of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``headers(m);`` | Convertible to H | Retrieve the headers of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``body(m);`` | Convertible to B | Retrieve the body of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << source(s);`` | ``M &`` | Set the source of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << destination(s);`` | ``M &`` | Set the destination of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << header(k, v);`` | ``M &`` | Add a header to ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << remove_header(k);`` | ``M &`` | Remove a header from ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``m << body(s);`` | ``M &`` | Set the body of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``source(m,s);`` | ``void`` | Set the source of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``destination(m,s);`` | ``void`` | Set the destination of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``add_header(m, k, v);`` | ``void`` | Add a header to ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``remove_header(m, k);`` | ``void`` | Remove a header from ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``clear_headers(m);`` | ``void`` | Clear the headers of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``body(m,s);`` | ``M &`` | Set the body of ``m``. | -+----------------------------+----------------------+-----------------------------------------+ - -Types that model the Message Concept are meant to encapsulate data -that has a source, a destination, one or more named headers, and a -body/payload. Because the accessors and the directives are not -required to be part of the message type that models the Message -Concept, a message can be implemented as a POD type and have all -manipulations performed in the directive implementations, as well as -value transformations done in the accessors. - -Directives, Modifiers, and Wrappers -``````````````````````````````````` - -In the Message Concept definition there are three basic constructs that follow a -certain pattern. These patterns are Directives_, Modifiers_, and Wrappers_. - -Directives -~~~~~~~~~~ - -A directive is a function object that is applied to a Message. Directives -encapsulate a set of operations that apply to messages. The general requirement -for a Directive is that it should apply these operations on a message. - -A directive may dispatch on the type of the message passed to it at the point of -the function call. Typically, directives are generated using a factory function -that returns the correct directive type. - -For a given directive ``foo_directive`` a generator function called ``foo`` is -typically implemented: - -.. code-block:: c++ - - struct foo_directive { - template - Message & operator()(Message & m) const { - // do something to m - return m; - } - }; - - foo_directive const foo() { - return foo_directive(); - } - - // to apply a directive, we use the << operator - message m; - m << foo(); - -Modifiers -~~~~~~~~~ - -A modifier is generally defined as a free function that takes a reference to a -non-const lvalue message as the first parameter, and any number of parameters. -In the concept definition of the Message Concept, a modifier follows the form: - -.. code-block:: c++ - - modifier(message, ...) - -Modifiers are meant to imply modifications on a message, which also allows for -easier dispatch based on Argument Dependent Lookup (ADL_) on the type of the -message. Note that Directives_ can be implemented in terms of Modifiers and -vice versa, although that is not required nor specified. - -.. _ADL: http://en.wikipedia.org/wiki/Argument-dependent_name_lookup - -Wrappers -~~~~~~~~ - -A Wrapper is basically an implementation detail that ensures that a given -message, when wrapped, can be converted to the associated part of the message. A -wrapper has a type that encapsulates the conversion logic from a message to a -given type. - -An example of a Wrapper would be ``source_wrapper`` which would be returned by a -call to the wrapper generator function ``source``. An example implementation of -the ``source_wrapper`` would look like: - -.. code-block:: c++ - - template class Message> - struct source_wrapper { - Message const & m; - explicit source_wrapper(Message const & m) - : m(m) {} - typedef typename source::type source_type; - operator source_type const & () { - return m.source; - } - operator source_type const () { - return m.source; - } - operator source_type () { - return m.source; - } - }; - - template class Message> - source_wrapper const - source(Message const & message) { - return source_wrapper(message); - } - -This pattern is similar to an adapter, but the specific notion of wrapping a -data type (in this case, an object of a type that models the Message Concept) -using an intermediary wrapper is what is pertained to by the Wrapper pattern. -In this case, the Wrapper is ``source_wrapper`` while ``source`` is merely a -wrapper generator function. - -``basic_message`` -````````````````` - -The default implementation of a simple type that models the Message -Concept is available in cpp-netlib. This default implementation is -named ``basic_message`` which supports a ``Tag`` template -parameter. The definition of ``basic_message`` looks like this: - -.. code-block:: c++ - - template - class basic_message; - -The ``basic_message`` template requires that the following -tag-dispatched metafunctions are defined for the type ``Tag``: - -.. code-block:: c++ - - template - struct string; - - template - struct headers_container; - -All the operations defined by the message concept are implemented by -this basic message type. Other message implementations can either use -this common message type or specialize it according to whether they -want to use different containers or whether it's going to be just a -POD type. diff --git a/libs/network/doc/html/_sources/in_depth/uri.txt b/libs/network/doc/html/_sources/in_depth/uri.txt deleted file mode 100644 index 84eca62e2..000000000 --- a/libs/network/doc/html/_sources/in_depth/uri.txt +++ /dev/null @@ -1,151 +0,0 @@ -The URI class -============= - -In addition to protocol implementations, the :mod:`cpp-netlib` -provides a powerful URI class. The class implements a parser based -on `RFC 3986`_ and `RFC 2732`_. - -Generic URI syntax overview -``````````````````````````` - -A generic URI will take the form:: - - [scheme:]scheme-specific-part[#fragment] - -A URI is known as `absolute` if it specifies the scheme. Otherwise, -it is known as a relative URI. Currently, ``uri`` supports only -absolute URIs. - -URIs can be further classified according to whether they're -hierarchical or opaque (non-hierarchical). - -Some examples of non-hierarchical URIs include:: - - mailto:john.doe@example.com - news:comp.infosystems.www.servers.unix - tel:+1-816-555-1212 - -The data following the first ``":"`` is said to be opaque to the URI -parser and requires no further parsing. By way of example, the -following shows how a non-hierarchical URI is processed by the parser -by defining everything after the ``":"`` to be a part of the path: - -.. image:: ../_static/mailto_uri.png - -A hierarchical URI is identified by a double slash (``"//"``) after -the scheme and a scheme-specific component, which `RFC 3986`_ defines -to be:: - - [scheme:][//authority][path][?query][#fragment] - -The authority component can be further broken down to:: - - [user_info@]host[:port] - -Examples of hierarchical URIs include:: - - http://www.boost.org/ - file:///bin/bash - -The following example, describing a complex URI using FTP, shows how -a URI is broken down by the parser: - -.. image:: ../_static/ftp_uri.png - -Note that the ``authority`` is further subdivided into different -elements. Another example, using HTTP is given below: - -.. image:: ../_static/http_uri.png - -The difference here between the path in a hierarchical URI and that in -the example above for the non-hierarchical URI. - -The ``uri`` class -````````````````` - -As of version 0.9.3, ``uri`` supplies a URI parser and builder. -To use the parser, it's as simple as supplying a string to the -constructor: - -.. code-block:: c++ - - using namespace boost::network; - uri::uri instance("http://cpp-netlib.github.com/"); - assert(instance.is_valid()); - std::cout << "scheme: " << instance.scheme() << std::endl - << "host: " << instance.host() << std::endl; - -The command-line output of this program will be:: - - scheme: http - host: cpp-netlib.github.com - -The ``uri`` builder -``````````````````` - -``uri`` support a stream style syntax to create a URI from it's -elements. For example the program: - -.. code-block:: c++ - - #include - #include - #include - using namespace boost::network; - - int main() { - uri::uri url; - url << uri::scheme("http") - << uri::host("www.github.com") - << uri::path("/cpp-netlib"); - std::cout << url << std::endl; - return 0; - } - -will output:: - - http://www.github.com/cpp-netlib - -``URI Concept`` -``````````````` - -**Legend** - -:U: The URI type. -:u,u_: An instance of **M**. -:S: A string type. -:s,v: An instance of **S**. -:T: The Tag type. - -+----------------------------+----------------------+-----------------------------------------+ -| Construct | Result | Description | -+============================+======================+=========================================+ -| ``U(u)`` | Instance of U | Copy constructible. | -+----------------------------+----------------------+-----------------------------------------+ -| ``U(s)`` | Instance of U | Constructible from string. | -+----------------------------+----------------------+-----------------------------------------+ -| ``u = u_;`` | Reference to u | Assignable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``u = s;`` | Reference to u | Assignable from string. | -+----------------------------+----------------------+-----------------------------------------+ -| ``swap(u, u_);`` | ``void`` | Swappable. | -+----------------------------+----------------------+-----------------------------------------+ -| ``scheme(u);`` | Convertible to S | Retrieve the URI scheme of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``user_info(u);`` | Convertible to S | Retrieve the user info of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``host(u);`` | Convertible to S | Retrieve the host of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``port(u);`` | Convertible to H | Retrieve the port of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``path(u);`` | Convertible to S | Retrieve the path of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``query(u);`` | Convertible to S | Retrieve the query string of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ -| ``fragment(u);`` | Convertible to S | Retrieve the fragment of ``u``. | -+----------------------------+----------------------+-----------------------------------------+ - -.. _`RFC 3986`: http://tools.ietf.org/html/rfc3986 -.. _`RFC 2368`: http://tools.ietf.org/html/rfc2368 -.. _`RFC 3513`: http://tools.ietf.org/html/rfc3513 -.. _`RFC 2732`: http://tools.ietf.org/html/rfc2732 diff --git a/libs/network/doc/html/_sources/index.txt b/libs/network/doc/html/_sources/index.txt index fc9e65405..3329b8a30 100644 --- a/libs/network/doc/html/_sources/index.txt +++ b/libs/network/doc/html/_sources/index.txt @@ -108,7 +108,6 @@ Want to learn more? * :ref:`Take a look at the getting started guide ` * :ref:`Learn from some simple examples ` * :ref:`Find out what's new ` - * :ref:`Study the library in more depth ` * :ref:`Discover more through the full reference ` * :ref:`Full table of contents ` diff --git a/libs/network/doc/html/_sources/reference/http_server.txt b/libs/network/doc/html/_sources/reference/http_server.txt index 26ceb9b65..c0022bdda 100644 --- a/libs/network/doc/html/_sources/reference/http_server.txt +++ b/libs/network/doc/html/_sources/reference/http_server.txt @@ -5,9 +5,9 @@ HTTP Server API General ------- -:mod:`cpp-netlib` includes and implements two distinct HTTP server -implementations that you can use and embed in your own applications. Both HTTP -Server implementations: +:mod:`cpp-netlib` includes and implements and asynchronous HTTP server +implementation that you can use and embed in your own applications. The HTTP +Server implementation: * **Cannot be copied.** This means you may have to store instances of the HTTP Server in dynamic memory if you intend to use them as function parameters or @@ -15,60 +15,19 @@ Server implementations: * **Assume that requests made are independent of each other.** None of the HTTP Server implementations support request pipelining (yet) so a single connection only deals with a single request. - * **Are header-only and are compiled-into your application.** Future releases - in case you want to upgrade the implementation you are using in your - application will be distributed as header-only implementations, which means - you have to re-compile your application to use a newer version of the - implementations. - -The HTTP Servers have different semantics, and in some cases require different -APIs from the supplied template parameters. - -Implementations ---------------- - -There are two different user-facing template classes that differentiate the -`Synchronous Servers`_ from the `Asynchronous Servers`_. Both templates take a -single template parameter named ``Handler`` which describes the type of the -Handler function object. - -There are two different Handler concepts, one concept for `Synchronous Servers`_ -and another for `Asynchronous Servers`. - -The SynchronousHandler concept for `Synchronous Servers`_ is described by the -following table: - ---------------- - -**Legend:** - -H - The Handler type. -h - An instance of H. -Req - A type that models the Request Concept. -Res - A type that models the Response Concept. -req - An instance of Req. -res - An instance of Res. - -+----------------+-------------+----------------------------------------------+ -| Construct | Return Type | Description | -+================+=============+==============================================+ -| ``h(req,res)`` | ``void`` | Handle the request; res is passed in as a | -| | | non-const lvalue, which represents the | -| | | response to be returned to the client | -| | | performing the request. | -+----------------+-------------+----------------------------------------------+ - -More information about the internals of the `Synchronous Servers`_ can be found -in the following section. - -The AsynchronousHandler concept for `Asynchronous Servers`_ is described by the -following table: + * **The Handler instance is invoked asynchronously**. This means the I/O + thread used to handle network-related events are free to handle only the + I/O related events. This enables the server to scale better as to the + number of concurrent connections it can handle. + * **The Handler is able to schedule asynchronous actions on the thread pool + associated with the server.** This allows handlers to perform multiple + asynchronous computations that later on perform writes to the connection. + * **The Handler is able to control the (asynchronous) writes to and reads + from the HTTP connection.** Because the connection is available to the + Handler, that means it can write out chunks of data at a time or stream + data through the connection continuously. + +The Handler concept for the HTTP Server is described by the following table: --------------- @@ -95,270 +54,30 @@ conn | | | writing to and reading from the connection.| +------------------+-------------+--------------------------------------------+ -More information about the internals of the `Asynchronous Servers`_ can be found -in the following section. - -Synchronous Servers -------------------- - -The synchronous server implementation is represented by the template ``server`` -in namespace ``boost::network::http``. The ``server`` template takes in a single -template parameter named ``Handler`` which models the SynchronousHandler -concept (described above). - -An instance of Handler is taken in by reference to the constructor of the HTTP -server. This means the Handler is not copied around and only a single instance -of the handler is used for all connections and requests performed against the -HTTP server. - -.. warning:: It is important to note that the HTTP server does not implement any - locking upon invoking the Handler. In case you have any state in the Handler - that will be associated with the synchronous server, you would have to - implement your own synchronization internal to the Handler implementation. - This matters especially if you run the synchronous server in multiple - threads. - -The general pattern of usage for the HTTP Server template is shown below: - -.. code-block:: c++ - - struct handler; - typedef boost::network::http::server http_server; - - struct handler { - void operator()( - http_server::request const & req, - http_server::response & res - ) { - // do something, and then edit the res object here. - } - }; - -More information about the actual HTTP Server API follows in the next section. -It is important to understand that the HTTP Server is actually embedded in your -application, which means you can expose almost all your application logic -through the Handler type, which you can also initialize appropriately. - -API Documentation -~~~~~~~~~~~~~~~~~ - -The following sections assume that the following file has been included: - -.. code-block:: c++ - - #include - -And that the following typedef's have been put in place: - -.. code-block:: c++ - - struct handler_type; - typedef boost::network::http::server http_server; - - struct handler_type { - void operator()(http_server::request const & request, - http_server::response & response) { - // do something here - } - }; - -Constructor -``````````` - -``explicit http_server(options)`` - Construct an HTTP Server instance, passing in a ``server_options`` object. The following table shows the supported options in - ``server_options``. - -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| Parameter Name | Type | Description | -+=======================+==========================================+==================================================================================================+ -| address | string_type | The hostname or IP address from which the server should be bound to. This parameter is required. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| port | string_type | The port to which the server should bind and listen to. This parameter is required. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| thread_pool | ``shared_ptr`` | A shared pointer to an instance of ``boost::network::utils::thread_pool`` -- this is the | -| | | thread pool from where the handler is invoked. This parameter is only applicable and required | -| | | for ``async_server`` instances. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| io_service | ``shared_ptr`` | An optional lvalue to an instance of ``boost::asio::io_service`` which allows the server to use | -| | | an already-constructed ``boost::asio::io_service`` instance instead of instantiating one that it | -| | | manages. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| reuse_address | ``bool`` | A boolean that specifies whether to re-use the address and port on which the server will be | -| | | bound to. This enables or disables the socket option for listener sockets. The default is | -| | | ``false``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| report_aborted | ``bool`` | A boolean that specifies whether the listening socket should report aborted connection attempts | -| | | to the accept handler (an internal detail of cpp-netlib). This is put in place to allow for | -| | | future-proofing the code in case an optional error handler function is supported in later | -| | | releases of cpp-netlib. The default is ``false``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| receive_buffer_size | ``int`` | The size of the socket's receive buffer. The default is defined by Boost.Asio and is | -| | | platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| send_buffer_size | ``int`` | The size of the socket's send buffer. The default is defined by Boost.Asio and is | -| | | platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| receive_low_watermark | ``int`` | The size of the socket's low watermark for its receive buffer. The default is defined by | -| | | Boost.Asio and is platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| send_buffer_size | ``int`` | The size of the socket's send low watermark for its send buffer. The default is defined by | -| | | Boost.Asio and is platform-dependent. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| non_blocking_io | ``bool`` | An optional bool to define whether the socket should use non-blocking I/O in case the platform | -| | | supports it. The default is ``true``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| linger | ``bool`` | An optional bool to determine whether the socket should linger in case there's still data to be | -| | | sent out at the time of its closing. The default is ``true``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| linger_timeout | ``int`` | An optional int to define the timeout to wait for socket closes before it is set to linger. | -| | | The default is ``0``. | -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ -| context | ``shared_ptr`` | An optional shared pointer to an instance of ``boost::asio::ssl::context`` -- this contains the | -| | | settings needed to support SSL. This parameter is only applicable for ``async_server`` instances.| -+-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ - -To use the above supported named parameters, you'll have code that looks like the following: - -.. code-block:: c++ - - using namespace boost::network::http; // parameters are in this namespace - handler handler_instance; - sync_server::options options(handler_instance); - options.address("0.0.0.0") - .port("80") - .io_service(boost::make_shared()) - .reuse_address(true); - sync_server instance(options); - instance.run(); - -Public Members -`````````````` - -The following definitions assume that a properly constructed ``http_server`` -instance has been constructed in the following manner: - -.. code-block:: c++ - - handler_type handler; - http_server::options options(handler); - http_server server(options.address("127.0.0.1").port("8000")); - -``server.run()`` - Run the HTTP Server event loop. This function can be run on multiple threads - following the example: - -.. code-block:: c++ - - boost::thread t1(boost::bind(&http_server::run, &server)); - boost::thread t2(boost::bind(&http_server::run, &server)); - server.run(); - t1.join(); - t2.join(); - -``server.stop()`` - Stop the HTTP Server acceptor and wait for all pending requests to finish. - -Response Object -``````````````` - -The response object has its own public member functions which can be very -helpful in certain simple situations. - -``response = http_server::response::stock_reply(status, body)`` - Code like the above should go inside the handler's ``operator()`` overload. - The body parameter is an ``std::string``. The status parameter is any of - the following values from the ``http_server::response`` enum - ``status_type``: - -.. code-block:: c++ - - enum status_type { - ok = 200, - created = 201, - accepted = 202, - no_content = 204, - multiple_choices = 300, - moved_permanently = 301, - moved_temporarily = 302, - not_modified = 304, - bad_request = 400, - unauthorized = 401, - forbidden = 403, - not_found = 404, - not_supported = 405, - not_acceptable = 406, - internal_server_error = 500, - not_implemented = 501, - bad_gateway = 502, - service_unavailable = 503 - }; +--------------- -The response object also has the following publicly accessible member values -which can be directly manipulated by the handler. - -+------------------+----------------------+------------------------------------+ -| Member Name | Type | Description | -+==================+======================+====================================+ -| status | ``status_type`` | The HTTP status of the response. | -+------------------+----------------------+------------------------------------+ -| headers | ``vector

`` | Vector of headers. [#]_ | -+------------------+----------------------+------------------------------------+ -| content | ``string_type`` [#]_ | The contents of the response. | -+------------------+----------------------+------------------------------------+ - -.. [#] A header is a struct of type - ``response_header``. An instance always has the - members ``name`` and ``value`` both of which are of type ``string_type``. -.. [#] ``string_type`` is - ``boost::network::string::type``. - -Asynchronous Servers --------------------- - -The asynchronous server implementation is significantly different to the -synchronous server implementation in three ways: - - #. **The Handler instance is invoked asynchronously**. This means the I/O - thread used to handle network-related events are free to handle only the - I/O related events. This enables the server to scale better as to the - number of concurrent connections it can handle. - #. **The Handler is able to schedule asynchronous actions on the thread pool - associated with the server.** This allows handlers to perform multiple - asynchronous computations that later on perform writes to the connection. - #. **The Handler is able to control the (asynchronous) writes to and reads from - the HTTP connection.** Because the connection is available to the Handler, - that means it can write out chunks of data at a time or stream data through - the connection continuously. - -The asynchronous server is meant to allow for better scalability in terms of the -number of concurrent connections and for performing asynchronous actions within -the handlers. If your application does not need to write out information -asynchronously or perform potentially long computations, then the synchronous -server gives a generally better performance profile than the asynchronous -server. - -The asynchronous server implementation is available from a single user-facing -template named ``async_server``. This template takes in a single template +The HTTP Server is meant to allow for better scalability in terms of the number +of concurrent connections and for performing asynchronous actions within the +handlers. The HTTP Server implementation is available from a single +user-facing template named ``server``. This template takes in a single template parameter which is the type of the Handler to be called once a request has been parsed from a connection. -An instance of Handler is taken as a reference to the constructor similar to the -synchronous server implementation. +An instance of Handler is taken as a reference to the constructor of the server +instance. -.. warning:: The asynchronous server implementation, like the synchronous server - implementation, does not perform any synchronization on the calls to the - Handler invocation. This means if your handler contains or maintains internal - state, you are responsible for implementing your own synchronization on - accesses to the internal state of the Handler. +.. warning:: The HTTP Server implementation does not perform any + synchronization on the calls to the Handler invocation. This means if your + handler contains or maintains internal state, you are responsible for + implementing your own synchronization on accesses to the internal state of + the Handler. -The general pattern for using the ``async_server`` template is shown below: +The general pattern for using the ``server`` template is shown below: .. code-block:: c++ struct handler; - typedef boost::network::http::async_server http_server; + typedef boost::network::http::server http_server; struct handler { void operator()( @@ -371,7 +90,7 @@ The general pattern for using the ``async_server`` template is shown below: }; API Documentation -~~~~~~~~~~~~~~~~~ +----------------- The following sections assume that the following file has been included: @@ -395,135 +114,36 @@ And that the following typedef's have been put in place: }; Constructor -``````````` +~~~~~~~~~~~ ``explicit http_server(options)`` Construct an HTTP server instance passing in a ``server_options`` instance. -Public Members -`````````````` - -The following definitions assume that a properly constructed ``http_server`` -instance has been constructed in the following manner: +Server Options +~~~~~~~~~~~~~~ -.. code-block:: c++ - - handler_type handler; - http_server::options options(handler); - options.thread_pool(boost::make_shared(2)); - http_server server(options.address("127.0.0.1").port("8000")); - -``server.run()`` - Run the HTTP Server event loop. This function can be run on multiple threads - following the example: - -.. code-block:: c++ +.. doxygenstruct:: boost::network::http::server_options + :project: cppnetlib + :members: - boost::thread t1(boost::bind(&http_server::run, &server)); - boost::thread t2(boost::bind(&http_server::run, &server)); - server.run(); - t1.join(); - t2.join(); +Public Members +~~~~~~~~~~~~~~ -``server.stop()`` - Stop the HTTP Server acceptor and wait for all pending requests to finish. +.. doxygenstruct:: boost::network::http::server + :project: cppnetlib + :members: + :undoc-members: Connection Object -````````````````` - -The connection object has its own public member functions which will be the -primary means for reading from and writing to the connection. - -``template write(Range range)`` - The connection object exposes a function ``write`` that can be given a - parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept. - The write function, although it looks synchronous, starts of a series of - asynchronous writes to the connection as soon as the range is serialized to - appropriately sized buffers. - - To use this in your handler, it would look something like this: - -.. code-block:: c++ - - connection->write("Hello, world!"); - std::string sample = "I have a string!"; - connection->write(sample); - -``template void write(Range range, Callback callback)`` - The connection object also exposes a function ``write`` that can be given a - parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept, as - well as a Callback function that returns ``void`` and takes a - ``boost::system::error_code`` as a parameter. This overload of ``write`` is - useful for writing streaming applications that send out chunks of data at a - time, or for writing data that may not all fit in memory right away. - -``template void read(ReadCallback callback)`` - The connection object has a function ``read`` which can be used to read more - information from the connection. This ``read`` function takes in a callback - that can be assigned to a Boost.Function_ with the signature - ``void(input_range,error_code,size_t,connection_ptr)``. The following list - shows what the types actually mean: - - * **input_range** -- ``boost::iterator_range`` : The range - that denotes the data read from the connection. - * **error_code** -- ``boost::system::error_code`` : The error code if - there were any errors encountered from the read. - * **size_t** -- ``std::size_t`` : The number of bytes transferred. - * **connection_ptr** -- ``http_server::connection_ptr`` : A handle to the - current connection, so that it is kept alive at the time of the read - callback invocation. - - This interface is useful when doing reads of uploaded data that can be - potentially large and may not fit in memory. The read handler is then - responsible for dealing with the chunks of data available from the - connection. - -``void set_status(status_t new_status)`` - The ``set_status`` function takes a parameter of type ``status_t`` which is - an enum type nested in ``http_status::connection`` which is given in the - following code listing. - -.. code-block:: c++ - - enum status_t { - ok = 200 - , created = 201 - , accepted = 202 - , no_content = 204 - , multiple_choices = 300 - , moved_permanently = 301 - , moved_temporarily = 302 - , not_modified = 304 - , bad_request = 400 - , unauthorized = 401 - , forbidden = 403 - , not_found = 404 - , not_supported = 405 - , not_acceptable = 406 - , internal_server_error = 500 - , not_implemented = 501 - , bad_gateway = 502 - , service_unavailable = 503 - }; - -.. note:: You may set and re-set the status several times as long as you have - not set the headers or sent data through the connection. If you do this after - data has already been set, the function will throw an instance of - ``std::logic_error``. - -``template void set_headers(Range range)`` - The ``set_headers`` function takes a Single Pass Range of - ``boost::network::http::response_header`` - instances and linearizes them to a buffer with at most - ``BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE`` and - immediately schedules an asynchronous write once that is done. +~~~~~~~~~~~~~~~~~ - The function throws an instance of ``std::logic_error`` if you try to set - the headers for a connection more than once. +.. doxygenstruct:: boost::network::http::async_connection + :project: cppnetlib + :members: -Adding SSL support to Asynchronous Server ------------------------------------------ +Adding SSL support to the HTTP Server +------------------------------------- In order to setup SSL support for an Asynchronous Server, it is best to start from a regular Asynchronous Server (see above). Once this server is setup, SSL can be @@ -533,24 +153,25 @@ used are defined in the link. .. code-block:: c++ // Initialize SSL context - boost::shared_ptr ctx = boost::make_shared(boost::asio::ssl::context::sslv23); + std::shared_ptr ctx = + std::make_shared(asio::ssl::context::sslv23); ctx->set_options( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::single_dh_use); + asio::ssl::context::default_workarounds + | asio::ssl::context::no_sslv3 + | asio::ssl::context::single_dh_use); // Set keys ctx->set_password_callback(password_callback); ctx->use_certificate_chain_file("server.pem"); - ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem); + ctx->use_private_key_file("server.pem", asio::ssl::context::pem); ctx->use_tmp_dh_file("dh512.pem"); handler_type handler; http_server::options options(handler); - options.thread_pool(boost::make_shared(2)); + options.thread_pool(std::make_shared(2)); http_server server(options.address("127.0.0.1").port("8442").context(ctx)); - std::string password_callback(std::size_t max_length, boost::asio::ssl::context_base::password_purpose purpose) { + std::string password_callback(std::size_t max_length, asio::ssl::context_base::password_purpose purpose) { return std::string("test"); } diff --git a/libs/network/doc/html/_sources/techniques.txt b/libs/network/doc/html/_sources/techniques.txt deleted file mode 100644 index b52bf7e36..000000000 --- a/libs/network/doc/html/_sources/techniques.txt +++ /dev/null @@ -1,12 +0,0 @@ -Techniques -========== - -The :mod:`cpp-netlib` uses several advanced techniques to achieve it's -aims. This chapter describes some of those techniques. - -.. toctree:: - :maxdepth: 1 - - techniques/tag_metafunctions - techniques/directives - techniques/polymorphism diff --git a/libs/network/doc/html/_sources/techniques/directives.txt b/libs/network/doc/html/_sources/techniques/directives.txt deleted file mode 100644 index e40882d95..000000000 --- a/libs/network/doc/html/_sources/techniques/directives.txt +++ /dev/null @@ -1,92 +0,0 @@ -Directives -========== - -The :mod:`cpp-netlib` uses a technique for allowing message-passing -semantics in a chainable fashion in the form of directives. The basic -concept for directives is, in a general sense, an encapsulated -transformation that can be applied to objects that abide by the -directive protocol. - -Using the object-oriented notion of message passing, where an object -accepts a message (usually a function call) we define a simple DSEL in -order for the protocol to be supported by certain object types. In the -:mod:`cpp-netlib` the protocol implemented is similar to that of the -standard iostream formatting system: - -.. code-block:: c++ - - object << directive1(...) - << directive2(...) - ... - << directiveN(...); - -In :mod:`cpp-netlib` the directives are simple function objects that -take a target object as reference and returns a reference to the same -object as a result. In code the directive pattern looks like the -following: - -.. code-block:: c++ - - struct directive_type { - template - Input & operator()(Input & input) const { - // do something to input - return input; - } - }; - -To simplify directive creation, usually factory or generator functions -are defined to return concrete objects of the directive's type. - -.. code-block:: c++ - - inline - directive_type directive(...) { - return directive_type(); - } - -The trivial implementation of the directive protocol then boils down -to the specialization of the shift-left operator on the target type. - -.. code-block:: c++ - - template - inline target_type & operator<< - (target_type & x, Directive const & f) { - return f(x); - } - -.. todo:: - - An example using a directive. - -The rationale for implementing directives include the following: - - * **Encapsulation** - by moving logic into the directive types the - target object's interface can remain rudimentary and even hidden - to the user's immediate attention. Adding this layer of - indirection also allows for changing the underlying - implementations while maintaining the same syntactic and semantic - properties. - * **Flexibility** - by allowing the creation of directives that are - independent from the target object's type, generic operations can - be applied based on the concept being modeled by the target - type. The flexibility also afforded comes in the directive's - generator function, which can also generate different concrete - directive specializations based on parameters to the function. - * **Extensibility** - because the directives are independent of the - target object's type, new directives can be added and supported - without having to change the target object at all. - * **Reuse** - truly generic directives can then be used for a broad - set of target object types that model the same concepts supported - by the directive. Because the directives are self-contained - objects, the state and other object references it keeps are only - accessible to it and can be re-used in different contexts as well. - -Extending a system that uses directives is trivial in header-only -systems because new directives are simply additive. The protocol is -simple and can be applied to a broad class of situations. - -In a header-only library, the static nature of the wiring and chaining -of the operations lends itself to compiler abuse. A deep enough -nesting of the directives can lead to prolonged compilation times. diff --git a/libs/network/doc/html/_sources/techniques/polymorphism.txt b/libs/network/doc/html/_sources/techniques/polymorphism.txt deleted file mode 100644 index d5e42f8c9..000000000 --- a/libs/network/doc/html/_sources/techniques/polymorphism.txt +++ /dev/null @@ -1,92 +0,0 @@ -Static and dynamic polymorphism -=============================== - - -With a header only library, you can only do so much with static -polymorphism alone. There are some situations where you have to handle -dynamic polymorphism because of unavoidable runtime-based decision -making. Although you can deal with the base types that remain static, -behavior can vary greatly which derived type should be handling the -situation based on runtime values. - -This situation comes up in the :mod:`cpp-netlib` when we decide what -kind of connection handler to use for a given HTTP URI -- whether it's -plain HTTP or HTTPS. Although the HTTP semantics are the same for -HTTP and HTTPS the implementation of the connection handler greatly -varies on whether to use a plain TCP connection or an SSL-wrapped TCP -connection. - -The general pattern or technique is to combine tag-based dispatch with -a strategy factory, all while not requiring any externally built -libraries. Doing it in a header-only library requires a little -creativity and additional layers of indirection that you otherwise -will not need for a library with externally built static/dynamic -libraries. - -First we define the base type which we want to support dynamic -behavior with. There's nothing special with the base type, except -that it supports the tag dispatch earlier defined and has a virtual -destructor. In code it looks like this: - -.. code-block:: c++ - - template - struct base { - virtual void foo() = 0; // make this an abstract base - virtual ~base() { - // do the base destructor thing here. - } - }; - -We then define a set of derived types that specialize the -implementation of the ``foo`` member function. To facilitate the -dispatch of the correct type based on an input, we create a strategy -factory function: - -.. code-block:: c++ - - template - unique_ptr > strategy(int input, Tag) { - unique_ptr > ptr; - switch(input) { - case 0: ptr.reset(new derived0()); break; - case 1: ptr.reset(new derived1()); break; - // ... - default: ptr.reset(0); break; - } - return ptr; - } - - unique_ptr > ptr = - strategy(input, default_()); // input is a runtime value - -The strategy factory can be a standalone function, or a static member -of a factory class that is specialized by tag dispatch. This can be -done like the following: - -.. code-block:: c++ - - template - struct strategy; - - template <> - struct strategy { - static unique_ptr > create(int input) { - unique_ptr > ptr; - switch(input) { - case 0: ptr.reset(new derived0()); break; - case 1: ptr.reset(new derived1()); break; - //... - default: ptr.reset(0); break; - } - return ptr; - } - }; - -This approach allows the header-only libraries to define new dynamic -types in subsequent versions of the library while keeping the -static-dynamic bridge fluid. The only down-side to this is the -possibility of derived type explosion in case there are a lot of -different strategies or specializations available -- this though is -not unique to static-dynamic bridging, but is also a problem with pure -object oriented programming with dynamic polymorphism. diff --git a/libs/network/doc/html/_sources/techniques/tag_metafunctions.txt b/libs/network/doc/html/_sources/techniques/tag_metafunctions.txt deleted file mode 100644 index 68edd1449..000000000 --- a/libs/network/doc/html/_sources/techniques/tag_metafunctions.txt +++ /dev/null @@ -1,172 +0,0 @@ -Tag metafunctions -================= - -Sometimes you want to vary a function or a type's behavior based on a -static parameter. In the :mod:`cpp-netlib` there are a number of -things you might want to change based on some such parameter -- like -what the underlying string type should be and how large a buffer -should be, among other things. The primary way to define this in a -header-only manner is to use tag-based metafunctions. - -The skeleton of the approach is based on a similar technique for -defining type traits. In the :mod:`cpp-netlib` however the type traits -are defined on opaque tag types which serve to associate results to a -family of metafunctions. - -Template Specialization ------------------------ - -To illustrate this point, let's define a tag ``default_`` which we use -to denote the default implementation of a certain type ``foo``. For -instance we decide that the default string type we will use for -``default_`` tagged ``foo`` specializations will be an -``std::string``. - -In the :mod:`cpp-netlib` this is done by defining a ``string`` -metafunction type that is specialized on the tag ``default_`` whose -nested ``type`` result is the type ``std::string``. In code this would -translate to: - -.. code-block:: c++ - - template - struct string { - typedef void type; - }; - - struct default_; - - template <> - struct string { - typedef std::string type; - }; - -Template Metaprogramming ------------------------- - -Starting with version 0.7, the tag dispatch mechanism changed slightly to use -Boost.MPL_. The idea is still the same, although we can get a little smarter -than just using template specializations. Instead of just defining an opaque -type ``default_``, we use the Boost.MPL equivalent of a vector to define which -root types of properties this ``default_`` tag supports. The idea is to make the -opaque type ``default_`` inherit property tags which the library supports -internally as definite extension points. - -.. _Boost.MPL: http://www.boost.org/libs/mpl/index.html - -Our definition of the ``default_`` tag will then look something like the -following: - -.. code-block:: c++ - - typedef mpl::vector default_tags; - - template - struct components; - - typedef mpl::inherit_linearly< - default_tags, - mpl::inherit - >::type default_; - - template - struct components { - typedef default_tags type; - }; - -In the above listing, ``default_string`` is what we call a "root" tag which is -meant to be combined with other "root" tags to form composite tags. In this case -our composite tag is the tag ``default_``. There are a number of these "root" -tags that :mod:`cpp-netlib` provides. These are in the namespace -``boost::network::tags`` and are defined in ``boost/network/tags.hpp``. - -Using this technique we change slightly our definition of the ``string`` -metafunction class into this: - -.. code-block:: c++ - - template - struct unsupported_tag; - - template - struct string : - mpl::if_< - is_base_of< - tags::default_string, - Tag - >, - std::string, - unsupported_tag - > - {}; - -Notice that we don't have the typedef for ``type`` in the body of ``string`` -anymore, but we do inherit from ``mpl::if_``. Since ``mpl::if_`` is a template -metafunction itself, it contains a definition of the resulting ``type`` which -``string`` inherits. - -You can see the real definition of the ``string`` metafunction in -``boost/network/traits/string.hpp``. - -Using Tags ----------- - -Once we have the defined tag, we can then use this in the definition of our -types. In the definition of the type ``foo`` we use this type function -``string`` and pass the tag type parameter to determine what to use as -the string type in the context of the type ``foo``. In code this would -translate into: - -.. code-block:: c++ - - template - struct foo { - typedef typename string::type string_type; - - // .. use string_type where you need a string. - }; - -Using this approach we can support different types of strings for -different tags on the type ``foo``. In case we want to use a different -type of string for the tag ``default_`` we only change the -composition of the ``string_tags`` MPL vector. For example, in :mod:`cpp-netlib` -there is a root tag ``default_wstring`` which causes the ``string`` metafunction -to define ``std::wstring`` as the resulting type. - -The approach also allows for the control of the structure and features -of types like ``foo`` based on the specialization of the tag. Whole -type function families can be defined on tags where they are supported -and ignored in cases where they are not. - -To illustrate let's define a new tag ``swappable``. Given the above -definition of ``foo``, we want to make the ``swappable``-tagged -``foo`` define a ``swap`` function that extends the original -``default_``-tagged ``foo``. In code this would look like: - -.. code-block:: c++ - - struct swappable; - - template <> - struct foo : foo { - void swap(foo & other) { - // ... - } - }; - -We also for example want to enable an ADL-reachable ``swap`` function: - -.. code-block:: c++ - - struct swappable; - - inline - void swap(foo & left, foo & right) { - left.swap(right); - } - -Overall what the tag-based definition approach allows is for static -definition of extension points that ensures type-safety and -invariants. This keeps the whole extension mechanism static and yet -flexible. - diff --git a/libs/network/doc/html/contents.html b/libs/network/doc/html/contents.html index af9c12b4d..ce952c360 100644 --- a/libs/network/doc/html/contents.html +++ b/libs/network/doc/html/contents.html @@ -144,48 +144,6 @@

Navigation

-
  • An in-depth look at the cpp-netlib -
  • -
  • Techniques -
  • -
  • Project history -
  • Reference Manual
  • previous |
  • - + @@ -124,7 +124,7 @@

    Navigation

  • previous |
  • - + @@ -169,7 +169,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/examples/http/hello_world_client.html b/libs/network/doc/html/examples/http/hello_world_client.html index e9ff6a48e..c83408f56 100644 --- a/libs/network/doc/html/examples/http/hello_world_client.html +++ b/libs/network/doc/html/examples/http/hello_world_client.html @@ -6,7 +6,7 @@ - “Hello world” HTTP client — cpp-netlib v0.11.2 + “Hello world” HTTP client — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -186,7 +186,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/examples/http/hello_world_server.html b/libs/network/doc/html/examples/http/hello_world_server.html index cdea75e8f..59a516872 100644 --- a/libs/network/doc/html/examples/http/hello_world_server.html +++ b/libs/network/doc/html/examples/http/hello_world_server.html @@ -6,7 +6,7 @@ - “Hello world” HTTP server — cpp-netlib v0.11.2 + “Hello world” HTTP server — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -236,7 +236,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/examples/http/http_client.html b/libs/network/doc/html/examples/http/http_client.html index b5ef618f8..33eaead94 100644 --- a/libs/network/doc/html/examples/http/http_client.html +++ b/libs/network/doc/html/examples/http/http_client.html @@ -6,7 +6,7 @@ - HTTP client — cpp-netlib v0.11.2 + HTTP client — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -200,7 +200,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/examples/http/simple_wget.html b/libs/network/doc/html/examples/http/simple_wget.html index 709d941cd..5031909b8 100644 --- a/libs/network/doc/html/examples/http/simple_wget.html +++ b/libs/network/doc/html/examples/http/simple_wget.html @@ -6,7 +6,7 @@ - Simple wget — cpp-netlib v0.11.2 + Simple wget — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -197,7 +197,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/examples/http/twitter_search.html b/libs/network/doc/html/examples/http/twitter_search.html index 62018b073..9a5a7ff75 100644 --- a/libs/network/doc/html/examples/http/twitter_search.html +++ b/libs/network/doc/html/examples/http/twitter_search.html @@ -6,7 +6,7 @@ - Twitter search — cpp-netlib v0.11.2 + Twitter search — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -203,7 +203,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/getting_started.html b/libs/network/doc/html/getting_started.html index 3c8a000cc..ec5e72de5 100644 --- a/libs/network/doc/html/getting_started.html +++ b/libs/network/doc/html/getting_started.html @@ -6,7 +6,7 @@ - Getting Started — cpp-netlib v0.11.2 + Getting Started — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -44,7 +44,7 @@

    Navigation

  • previous |
  • - + @@ -345,7 +345,7 @@

    Navigation

  • previous |
  • - + @@ -197,7 +197,7 @@

    Navigation

  • previous |
  • - + @@ -128,7 +128,7 @@

    Navigation

  • previous |
  • - + @@ -756,7 +756,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/reference/http_request.html b/libs/network/doc/html/reference/http_request.html index 2f916959f..d1a959c39 100644 --- a/libs/network/doc/html/reference/http_request.html +++ b/libs/network/doc/html/reference/http_request.html @@ -6,7 +6,7 @@ - HTTP Request — cpp-netlib v0.11.2 + HTTP Request — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -430,7 +430,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/reference/http_response.html b/libs/network/doc/html/reference/http_response.html index 8d8338e5c..b28c02e62 100644 --- a/libs/network/doc/html/reference/http_response.html +++ b/libs/network/doc/html/reference/http_response.html @@ -6,7 +6,7 @@ - HTTP Response — cpp-netlib v0.11.2 + HTTP Response — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -463,7 +463,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/reference/http_server.html b/libs/network/doc/html/reference/http_server.html index d8329e200..1826bc201 100644 --- a/libs/network/doc/html/reference/http_server.html +++ b/libs/network/doc/html/reference/http_server.html @@ -6,7 +6,7 @@ - HTTP Server API — cpp-netlib v0.11.2 + HTTP Server API — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -45,7 +45,7 @@

    Navigation

  • previous |
  • - + @@ -931,7 +931,7 @@

    Navigation

  • previous |
  • - + diff --git a/libs/network/doc/html/references.html b/libs/network/doc/html/references.html index d372a2c6a..b4f5e6a8f 100644 --- a/libs/network/doc/html/references.html +++ b/libs/network/doc/html/references.html @@ -6,7 +6,7 @@ - References — cpp-netlib v0.11.2 + References — cpp-netlib v0.12.0 @@ -14,7 +14,7 @@ - + @@ -40,7 +40,7 @@

    Navigation

  • previous
  • - + @@ -111,7 +111,7 @@

    Navigation

  • previous
  • - +