diff --git a/boost/network/protocol/http/request/request.ipp b/boost/network/protocol/http/request/request.ipp index 6febaa3e6..fe5e04ad8 100644 --- a/boost/network/protocol/http/request/request.ipp +++ b/boost/network/protocol/http/request/request.ipp @@ -9,6 +9,7 @@ #include #include +#include #ifdef BOOST_NETWORK_DEBUG BOOST_CONCEPT_ASSERT((boost::network::http::ClientRequest)); @@ -21,6 +22,9 @@ struct request_pimpl { explicit request_pimpl(std::string const & url) : uri_(url) + , read_offset_(0) + , source_() + , headers_() {} request_pimpl* clone() { @@ -31,14 +35,78 @@ struct request_pimpl { uri_ = uri; } + void set_uri(uri::uri const & uri) { + uri_ = uri; + } + void get_uri(std::string &uri) { uri = uri_.string(); } + void get_uri(uri::uri &uri) { + uri = uri_; + } + + void append_header(std::string const & name, std::string const & value) { + headers_.insert(std::make_pair(name, value)); + } + + void get_headers(function predicate, + function inserter) const { + headers_type::const_iterator it = headers_.begin(); + for (; it != headers_.end(); ++it) { + if (predicate(it->first, it->second)) { + inserter(it->first, it->second); + } + } + } + + void get_headers(function inserter) const { + headers_type::const_iterator it = headers_.begin(); + for (; it != headers_.end(); ++it) { + inserter(it->first, it->second); + } + } + + void get_headers(std::string const &name, + function inserter) const { + headers_type::const_iterator it = headers_.begin(); + for (; it != headers_.end(); ++it) { + if (it->first == name) { + inserter(it->first, it->second); + } + } + } + + void set_source(std::string const &source) { + source_ = source; + } + + void get_source(std::string &source) const { + source = source_; + } + + size_t read_offset() const { + return read_offset_; + } + + void advance_read_offset(size_t bytes) { + read_offset_ += bytes; + } + private: + typedef std::multimap headers_type; + uri::uri uri_; + size_t read_offset_; + std::string source_; + headers_type headers_; + request_pimpl(request_pimpl const &other) : uri_(other.uri_) + , read_offset_(other.read_offset_) + , source_(other.source_) + , headers_(other.headers_) {} }; @@ -68,47 +136,113 @@ void request::swap(request & other) { // From message_base... // Mutators -void request::set_destination(std::string const & destination){} -void request::set_source(std::string const & source){} +void request::set_destination(std::string const & destination) { +} + +void request::set_source(std::string const & source) { + pimpl_->set_source(source); +} + void request::append_header(std::string const & name, - std::string const & value){} -void request::remove_headers(std::string const & name){} -void request::remove_headers(){} -void request::set_body(std::string const & body){} -void request::append_body(std::string const & data){} + std::string const & value) { + pimpl_->append_header(name, value); +} + +void request::remove_headers(std::string const & name) { +} + +void request::remove_headers() { +} + +void request::set_body(std::string const & body) { + this->clear(); + this->append(body.data(), body.size()); +} + +void request::append_body(std::string const & data) { + this->append(data.data(), data.size()); +} // Retrievers -void request::get_destination(std::string & destination) const{} -void request::get_source(std::string & source) const{} -void request::get_headers(function inserter) const{} -void request::get_headers(std::string const & name, function inserter) const{} -void request::get_headers(function predicate, function inserter) const{} -void request::get_body(std::string & body) const{} -void request::get_body(function)> chunk_reader, size_t size) const{} +void request::get_destination(std::string & destination) const { +} + +void request::get_source(std::string & source) const { + pimpl_->get_source(source); +} + +void request::get_headers(function inserter) const { + pimpl_->get_headers(inserter); +} + +void request::get_headers(std::string const & name, function inserter) const { + pimpl_->get_headers(name, inserter); +} + +void request::get_headers(function predicate, function inserter) const { + pimpl_->get_headers(predicate, inserter); +} + +void request::get_body(std::string & body) const { + this->flatten(body); +} + +void request::get_body(function)> chunk_reader, size_t size) const { + scoped_array local_buffer(new (std::nothrow) char[size]); + size_t bytes_read = this->read(local_buffer.get(), + pimpl_->read_offset(), + size); + pimpl_->advance_read_offset(bytes_read); + char const * begin = local_buffer.get(); + char const * end = local_buffer.get() + bytes_read; + chunk_reader(make_iterator_range(begin, end)); +} // From request_base... // Setters -void request::set_method(std::string const & method){} -void request::set_status(std::string const & status){} -void request::set_status_message(std::string const & status_message){} -void request::set_body_writer(function writer){} +void request::set_method(std::string const & method) { +} + +void request::set_status(std::string const & status) { +} + +void request::set_status_message(std::string const & status_message) { +} + +void request::set_body_writer(function writer) { +} + void request::set_uri(std::string const &uri) { pimpl_->set_uri(uri); } -void request::set_uri(network::uri::uri const &uri){} + +void request::set_uri(network::uri::uri const &uri) { + pimpl_->set_uri(uri); +} // Getters -void request::get_uri(network::uri::uri &uri) const{} +void request::get_uri(network::uri::uri &uri) const { + pimpl_->get_uri(uri); +} void request::get_uri(std::string &uri) const { pimpl_->get_uri(uri); } -void request::get_method(std::string & method) const{} -void request::get_status(std::string & status) const{} -void request::get_status_message(std::string & status_message) const{} -void request::get_body(function chunk_reader) const{} -void request::get_body(std::string const & body) const{} +void request::get_method(std::string & method) const { +} + +void request::get_status(std::string & status) const { +} + +void request::get_status_message(std::string & status_message) const { +} + +void request::get_body(function chunk_reader) const { +} + +void request::get_body(std::string const & body) const { +} } // namespace http diff --git a/boost/network/protocol/http/request/request_base.hpp b/boost/network/protocol/http/request/request_base.hpp index 0e257c7c5..596453415 100644 --- a/boost/network/protocol/http/request/request_base.hpp +++ b/boost/network/protocol/http/request/request_base.hpp @@ -27,8 +27,8 @@ struct request_storage_base { protected: request_storage_base(size_t chunk_size = BOOST_NETWORK_BUFFER_CHUNK); virtual void append(char const *data, size_t size); - virtual size_t read(char *destination, size_t offset, size_t size); - virtual void flatten(std::string &destination); + virtual size_t read(char *destination, size_t offset, size_t size) const; + virtual void flatten(std::string &destination) const; virtual void clear(); virtual ~request_storage_base(); diff --git a/boost/network/protocol/http/request/request_base.ipp b/boost/network/protocol/http/request/request_base.ipp index aaf052821..eeed24c3d 100644 --- a/boost/network/protocol/http/request/request_base.ipp +++ b/boost/network/protocol/http/request/request_base.ipp @@ -20,8 +20,8 @@ request_base::~request_base() { struct request_storage_base_pimpl { request_storage_base_pimpl(size_t chunk_size); void append(char const *data, size_t size); - size_t read(char *destination, size_t offset, size_t size); - void flatten(std::string &destination); + size_t read(char *destination, size_t offset, size_t size) const; + void flatten(std::string &destination) const; void clear(); request_storage_base_pimpl clone() const; ~request_storage_base_pimpl(); @@ -45,11 +45,11 @@ void request_storage_base::append(char const *data, size_t size) { pimpl_->append(data, size); } -size_t request_storage_base::read(char *destination, size_t offset, size_t size) { +size_t request_storage_base::read(char *destination, size_t offset, size_t size) const { return pimpl_->read(destination, offset, size); } -void request_storage_base::flatten(std::string &destination) { +void request_storage_base::flatten(std::string &destination) const { pimpl_->flatten(destination); } @@ -90,7 +90,7 @@ void request_storage_base_pimpl::append(char const *data, size_t size) { } } -size_t request_storage_base_pimpl::read(char *destination, size_t offset, size_t size) { +size_t request_storage_base_pimpl::read(char *destination, size_t offset, size_t size) const { if (chunks_.empty()) return 0; // First we find which chunk we're going to read from using the provided // offset and some arithmetic to determine the correct one. @@ -114,7 +114,7 @@ size_t request_storage_base_pimpl::read(char *destination, size_t offset, size_t return read_count; } -void request_storage_base_pimpl::flatten(std::string &destination) { +void request_storage_base_pimpl::flatten(std::string &destination) const { chunks_vector::const_iterator chunk_iterator = chunks_.begin(); for (; chunk_iterator != chunks_.end(); ++chunk_iterator) { destination.append(chunk_iterator->first, chunk_iterator->second); diff --git a/libs/network/test/http/CMakeLists.txt b/libs/network/test/http/CMakeLists.txt index 3de77f4fc..7f1535e00 100644 --- a/libs/network/test/http/CMakeLists.txt +++ b/libs/network/test/http/CMakeLists.txt @@ -26,6 +26,7 @@ if (Boost_FOUND) target_link_libraries(cpp-netlib-http-${test} ${Boost_LIBRARIES} cppnetlib-message + cppnetlib-message-wrappers cppnetlib-uri cppnetlib-http-message) set_target_properties(cpp-netlib-http-${test} diff --git a/libs/network/test/http/request_test.cpp b/libs/network/test/http/request_test.cpp index 4c35453ad..225417f82 100644 --- a/libs/network/test/http/request_test.cpp +++ b/libs/network/test/http/request_test.cpp @@ -6,9 +6,12 @@ #define BOOST_TEST_MODULE HTTP Request Test #include +#include #include namespace http = boost::network::http; +namespace uri = boost::network::uri; +namespace net = boost::network; BOOST_AUTO_TEST_CASE(request_construction) { http::request request; @@ -25,3 +28,26 @@ BOOST_AUTO_TEST_CASE(request_uri_test) { BOOST_CHECK_EQUAL(std::string("http://www.google.com/"), original); BOOST_CHECK_EQUAL(original, copied); } + +BOOST_AUTO_TEST_CASE(request_basics_test) { + http::request request; + request.set_uri("http://www.google.com/"); + request.set_source("127.0.0.1"); + request.set_destination("http://www.google.com/"); + request.append_header("X-Referer", "http://cpp-netlib.github.com/"); + request.append_header("Connection", "close"); + request.append_body("The quick brown fox jumps over the lazy dog!"); + + uri::uri uri_; + std::string source_, destination_, body_; + net::headers_wrapper::range_type headers_range = headers(request); + request.get_uri(uri_); + request.get_source(source_); + request.get_destination(destination_); + request.get_body(body_); + + BOOST_CHECK_EQUAL(uri_.string(), std::string("http://www.google.com/")); + BOOST_CHECK_EQUAL(source_, std::string("127.0.0.1")); + BOOST_CHECK_EQUAL(body_, std::string("The quick brown fox jumps over the lazy dog!")); + BOOST_CHECK(!boost::empty(headers_range)); +}