20
20
#include < utility>
21
21
#include < cstdint>
22
22
#include < algorithm>
23
+ #include < sstream>
24
+ #include < iterator>
23
25
#include < boost/range/iterator_range.hpp>
24
26
#include < boost/range/algorithm/equal.hpp>
25
27
#include < boost/range/as_literal.hpp>
26
- #include " network/http/v2/constants.hpp"
27
28
#include " network/http/v2/method.hpp"
28
29
#include " network/http/v2/client/client_errors.hpp"
29
30
#include " network/uri.hpp"
@@ -226,13 +227,24 @@ namespace network {
226
227
/* *
227
228
* \brief Constructor.
228
229
*/
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 ()) {
232
232
if ((!boost::equal (*scheme, boost::as_literal (" http" ))) &&
233
233
(!boost::equal (*scheme, boost::as_literal (" https" )))) {
234
234
throw invalid_url ();
235
235
}
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 ());
236
248
}
237
249
else {
238
250
throw invalid_url ();
@@ -243,8 +255,8 @@ namespace network {
243
255
* \brief Copy constructor.
244
256
*/
245
257
request (const request &other)
246
- : destination_ (other.destination_ )
247
- , method_ (other.method_ )
258
+ : method_ (other.method_ )
259
+ , path_ (other.path_ )
248
260
, version_(other.version_)
249
261
, headers_(other.headers_)
250
262
, byte_source_(other.byte_source_) { }
@@ -253,8 +265,8 @@ namespace network {
253
265
* \brief Move constructor.
254
266
*/
255
267
request (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_ ))
258
270
, version_(std::move(other.version_))
259
271
, headers_(std::move(other.headers_))
260
272
, byte_source_(std::move(other.byte_source_)) { }
@@ -278,112 +290,112 @@ namespace network {
278
290
* \brief Swap.
279
291
*/
280
292
void swap (request &other) noexcept {
281
- std::swap (destination_, other.destination_ );
282
293
std::swap (method_, other.method_ );
294
+ std::swap (path_, other.path_ );
283
295
std::swap (version_, other.version_ );
284
296
std::swap (headers_, other.headers_ );
285
297
std::swap (byte_source_, other.byte_source_ );
286
298
}
287
299
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 ;
294
307
}
295
308
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_type host () 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::method method () const {
314
+ return method_;
305
315
}
306
316
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_type path () 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_type version () const {
340
+ return version_;
327
341
}
328
342
329
- void set_body (std::shared_ptr<byte_source> byte_source) {
343
+ request & body (std::shared_ptr<byte_source> byte_source) {
330
344
byte_source_ = byte_source;
331
345
}
332
346
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 ;
335
357
}
336
358
359
+ /* *
360
+ * \brief Returns the headers range.
361
+ * \returns An iterator range covering all headers.
362
+ */
337
363
boost::iterator_range<const_headers_iterator> headers () const {
338
364
return boost::make_iterator_range (std::begin (headers_), std::end (headers_));
339
365
}
340
366
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_));
353
380
}
354
381
382
+ /* *
383
+ * \brief Clears all HTTP request headers.
384
+ */
355
385
void clear_headers () {
356
386
headers_type ().swap (headers_);
357
387
}
358
388
359
- void set_method (network::http::v2::method method) {
360
- method_ = method;
361
- }
362
-
363
- network::http::v2::method method () const {
364
- return method_;
365
- }
366
-
367
- void set_version (string_type version) {
368
- version_ = std::move (version);
369
- }
370
-
371
- string_type version () const {
372
- return version_;
373
- }
374
-
375
389
private:
376
390
377
- uri destination_;
378
391
network::http::v2::method method_;
392
+ string_type path_;
379
393
string_type version_;
380
394
headers_type headers_;
381
395
std::shared_ptr<byte_source> byte_source_;
382
396
383
397
friend 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 " ;
387
399
for (auto header : req.headers_ ) {
388
400
os << header.first << " : " << header.second << " \r\n " ;
389
401
}
0 commit comments