2020#include < utility>
2121#include < cstdint>
2222#include < algorithm>
23+ #include < sstream>
24+ #include < iterator>
2325#include < boost/range/iterator_range.hpp>
2426#include < boost/range/algorithm/equal.hpp>
2527#include < boost/range/as_literal.hpp>
26- #include " network/http/v2/constants.hpp"
2728#include " network/http/v2/method.hpp"
2829#include " network/http/v2/client/client_errors.hpp"
2930#include " network/uri.hpp"
@@ -226,13 +227,24 @@ namespace network {
226227/* *
227228 * \brief Constructor.
228229*/
229- explicit request (uri destination, std::shared_ptr<byte_source> source =nullptr )
230- : destination_(destination), byte_source_(source) {
231- if (auto scheme = destination.scheme ()) {
230+ explicit request (uri url) {
231+ if (auto scheme = url.scheme ()) {
232232if ((!boost::equal (*scheme,boost::as_literal (" http" ))) &&
233233(!boost::equal (*scheme,boost::as_literal (" https" )))) {
234234throw invalid_url ();
235235 }
236+
237+ path_.assign (std::begin (*url.path ()),std::end (*url.path ()));
238+
239+ std::ostringstream oss;
240+ std::copy (std::begin (*url.host ()),std::end (*url.host ()),
241+ std::ostream_iterator<char >(oss));
242+ if (url.port ()) {
243+ oss <<" :" ;
244+ std::copy (std::begin (*url.port ()),std::end (*url.port ()),
245+ std::ostream_iterator<char >(oss));
246+ }
247+ append_header (" Host" , oss.str ());
236248 }
237249else {
238250throw invalid_url ();
@@ -243,8 +255,8 @@ namespace network {
243255 * \brief Copy constructor.
244256*/
245257request (const request &other)
246- :destination_ (other.destination_ )
247- , method_ (other.method_ )
258+ :method_ (other.method_ )
259+ , path_ (other.path_ )
248260 , version_(other.version_)
249261 , headers_(other.headers_)
250262 , byte_source_(other.byte_source_) { }
@@ -253,8 +265,8 @@ namespace network {
253265 * \brief Move constructor.
254266*/
255267request (request &&other)noexcept
256- : destination_ (std::move(other.destination_ ))
257- , method_ (std::move(other.method_ ))
268+ : method_ (std::move(other.method_ ))
269+ , path_ (std::move(other.path_ ))
258270 , version_(std::move(other.version_))
259271 , headers_(std::move(other.headers_))
260272 , byte_source_(std::move(other.byte_source_)) { }
@@ -278,112 +290,112 @@ namespace network {
278290 * \brief Swap.
279291*/
280292void swap (request &other)noexcept {
281- std::swap (destination_, other.destination_ );
282293std::swap (method_, other.method_ );
294+ std::swap (path_, other.path_ );
283295std::swap (version_, other.version_ );
284296std::swap (headers_, other.headers_ );
285297std::swap (byte_source_, other.byte_source_ );
286298}
287299
288- /* *
289- * \brief Sets the request destination.
290- * \param destination The destination.
291- */
292- void set_destination (uri destination) {
293- destination_ =std::move (destination);
300+ /* *
301+ * \brief Sets the HTTP request method.
302+ * \param method THe HTTP request method.
303+ */
304+ request &method (network::http::v2::method method) {
305+ method_ = method;
306+ return *this ;
294307}
295308
296- /* *
297- * \brief Gets the request destination host.
298- * \return The destination host.
299- * \pre destination_.scheme() != boost::none
300- * \pre destination_.host() != boost::none
301- */
302- string_typehost ()const {
303- assert (destination_.host ());
304- return string_type (std::begin (*destination_.host ()),std::end (*destination_.host ()));
309+ /* *
310+ * \brief Gets the HTTP request method.
311+ * \returns The HTTP request method.
312+ */
313+ network::http::v2::methodmethod ()const {
314+ return method_;
305315}
306316
307- /* *
308- * \brief Gets the request destination port.
309- * \return The destination port.
310- * \pre destination_.scheme() != boost::none
311- * \pre *destination_.scheme() == "http"
312- * \pre *destination_.scheme() == "https"
313- */
314- std::uint16_t port ()const {
315- assert (destination_.scheme ());
316- assert ((string_type (*destination_.scheme ()) ==" http" ) ||
317- (string_type (*destination_.scheme ()) ==" https" ));
318- if (!destination_.port ()) {
319- if (string_type (*destination_.scheme ()) ==" http" ) {
320- return 80 ;
321- }
322- else if (string_type (*destination_.scheme ()) ==" https" ) {
323- return 443 ;
324- }
325- }
326- return *destination_.port <std::uint16_t >();
317+ request &path (std::string path) {
318+ path_ = path;
319+ return *this ;
320+ }
321+
322+ string_typepath ()const {
323+ return path_;
324+ }
325+
326+ /* *
327+ * \brief Sets the HTTP request version.
328+ * \param version 1.0 or 1.1.
329+ */
330+ request &version (string_type version) {
331+ version_ =std::move (version);
332+ return *this ;
333+ }
334+
335+ /* *
336+ * \brief Gets the HTTP request version.
337+ * \returns The HTTP request version.
338+ */
339+ string_typeversion ()const {
340+ return version_;
327341}
328342
329- void set_body (std::shared_ptr<byte_source> byte_source) {
343+ request & body (std::shared_ptr<byte_source> byte_source) {
330344 byte_source_ = byte_source;
331345}
332346
333- void append_header (string_type key, string_type value) {
334- headers_.emplace_back (std::make_pair (key, value));
347+ /* *
348+ * \brief Appends a header to the request.
349+ * \param name The header name.
350+ * \param value The header value.
351+ *
352+ * Duplicates are allowed.
353+ */
354+ request &append_header (string_type name, string_type value) {
355+ headers_.emplace_back (std::make_pair (name, value));
356+ return *this ;
335357}
336358
359+ /* *
360+ * \brief Returns the headers range.
361+ * \returns An iterator range covering all headers.
362+ */
337363boost::iterator_range<const_headers_iterator>headers ()const {
338364return boost::make_iterator_range (std::begin (headers_),std::end (headers_));
339365}
340366
341- void remove_header (string_type key) {
342- bool found_all =false ;
343- while (!found_all) {
344- auto it =std::find_if (std::begin (headers_),std::end (headers_),
345- [&key] (const std::pair<string_type, string_type> &header) {
346- return header.first == key;
347- });
348- found_all = (it ==std::end (headers_));
349- if (!found_all) {
350- headers_.erase (it);
351- }
352- }
367+ /* *
368+ * \brief Removes a header from the request.
369+ * \param name The name of the header to be removed.
370+ *
371+ * If the header name can not be found, nothing happens. If
372+ * the header is duplicated, then both entries are removed.
373+ */
374+ void remove_header (string_type name) {
375+ auto it =std::remove_if (std::begin (headers_),std::end (headers_),
376+ [&name] (const std::pair<string_type, string_type> &header) {
377+ return header.first == name;
378+ });
379+ headers_.erase (it,std::end (headers_));
353380}
354381
382+ /* *
383+ * \brief Clears all HTTP request headers.
384+ */
355385void clear_headers () {
356386headers_type ().swap (headers_);
357387}
358388
359- void set_method (network::http::v2::method method) {
360- method_ = method;
361- }
362-
363- network::http::v2::methodmethod ()const {
364- return method_;
365- }
366-
367- void set_version (string_type version) {
368- version_ =std::move (version);
369- }
370-
371- string_typeversion ()const {
372- return version_;
373- }
374-
375389private:
376390
377- uri destination_;
378391network::http::v2::method method_;
392+ string_type path_;
379393string_type version_;
380394headers_type headers_;
381395std::shared_ptr<byte_source> byte_source_;
382396
383397friend std::ostream &operator << (std::ostream &os,const request &req) {
384- os << req.method_ <<" " << *req.destination_ .path () <<" HTTP/" << req.version_ <<" \r\n " ;
385- os <<" Host:" << *req.destination_ .host ();
386- os <<" \r\n " ;
398+ os << req.method_ <<" " << req.path_ <<" HTTP/" << req.version_ <<" \r\n " ;
387399for (auto header : req.headers_ ) {
388400 os << header.first <<" :" << header.second <<" \r\n " ;
389401 }