77#ifndef __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
88#define __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
99
10- #ifndef BOOST_NETLIB_VERSION
11- #define BOOST_NETLIB_VERSION " 0.5"
12- #endif
13-
10+ #include < boost/network/version.hpp>
1411#include < boost/network/traits/ostringstream.hpp>
1512#include < boost/network/protocol/http/message.hpp>
1613#include < boost/network/protocol/http/response.hpp>
1714#include < boost/network/protocol/http/request.hpp>
18- #include < boost/network/protocol/http/traits/resolver_policy .hpp>
15+ #include < boost/network/protocol/http/traits/connection_policy .hpp>
1916#include < boost/asio.hpp>
2017#include < boost/lexical_cast.hpp>
2118#include < boost/algorithm/string/classification.hpp>
2219#include < boost/algorithm/string/split.hpp>
23- #include < boost/tuple/tuple.hpp>
2420#include < boost/foreach.hpp>
2521#include < ostream>
2622#include < istream>
3127namespace boost { namespace network { namespace http {
3228
3329 template <class Tag , unsigned version_major, unsigned version_minor>
34- class basic_client : resolver_policy <Tag>::type {
30+ class basic_client : connection_policy <Tag, version_major, version_minor >::type {
3531
3632 private:
37- typedef typename resolver_policy <Tag>::type resolver_base ;
33+ typedef typename connection_policy <Tag, version_major, version_minor >::type connection_base ;
3834 boost::asio::io_service service_;
39- typename resolver_base::resolver_type resolver_;
40- bool follow_redirect_;
35+ typename connection_base::resolver_type resolver_;
4136
4237 typedef typename string<Tag>::type string_type;
4338
44- void init_socket (boost::asio::ip::tcp::socket & socket_, string_type const & hostname, string_type const & port) {
45- using boost::asio::ip::tcp;
46-
47- boost::system::error_code error = boost::asio::error::host_not_found;
48-
49- typename resolver_base::resolver_type::iterator endpoint_iterator, end;
50- boost::tie (endpoint_iterator, end) = resolve (resolver_, hostname, port);
51-
52- while (error && endpoint_iterator != end) {
53- socket_.close ();
54- socket_.connect (
55- tcp::endpoint (
56- endpoint_iterator->endpoint ().address ()
57- , endpoint_iterator->endpoint ().port ()
58- )
59- , error
60- );
61- ++endpoint_iterator;
62- }
63-
64- if (error)
65- throw boost::system::system_error (error);
66- };
67-
68- void create_request (boost::asio::streambuf & request_buffer, string_type const & method, basic_request<Tag> request_) const {
69- std::ostream request_stream (&request_buffer);
70-
71- request_stream
72- << method << " " ;
73-
74- if (request_.path ().empty () || request_.path ()[0 ] != ' /' )
75- request_stream << ' /' ;
76-
77- request_stream
78- << request_.path ()
79- ;
80-
81- if (!request_.query ().empty ())
82- request_stream
83- << ' ?'
84- << request_.query ()
85- ;
86-
87- if (!request_.anchor ().empty ())
88- request_stream
89- << ' #'
90- << request_.anchor ()
91- ;
92-
93- request_stream << " HTTP/" << version_major << ' .' << version_minor << " \r\n "
94- << " Host: " << request_.host () << " \r\n "
95- << " Accept: */*\r\n " ;
96-
97- typename headers_range<http::basic_request<Tag> >::type range = headers (request_);
98- BOOST_FOREACH (typename headers_range<http::basic_request<Tag> >::type::value_type const & header, range) {
99- request_stream << header.first << " : " << header.second << " \r\n " ;
100- };
101-
102- range = headers (request_)[" user-agent" ];
103- if (begin (range) == end (range)) request_stream << " User-Agent: cpp-netlib/" << BOOST_NETLIB_VERSION << " \r\n " ;
104-
105- request_stream
106- << " Connection: close\r\n\r\n " ;
107-
108- string_type body_ = body (request_);
109- if (!body_.empty ())
110- request_stream << body_;
111- };
112-
113- void send_request (boost::asio::ip::tcp::socket & socket, string_type const & method, basic_request<Tag> const & request_) const {
114- boost::asio::streambuf request_buffer;
115- create_request (request_buffer, method, request_);
116- write (socket, request_buffer);
117- };
118-
119- void read_status (basic_response<Tag> & response_, boost::asio::ip::tcp::socket & socket, boost::asio::streambuf & response_buffer) const {
120- boost::asio::read_until (socket, response_buffer, " \r\n " );
121- std::istream response_stream (&response_buffer);
122- string_type http_version;
123- unsigned int status_code;
124- string_type status_message;
125- response_stream >> http_version
126- >> status_code;
127- std::getline (response_stream, status_message);
128- trim_left (status_message);
129- trim_right_if (status_message, boost::is_space () || boost::is_any_of (" \r " ));
130-
131- if (!response_stream || http_version.substr (0 , 5 ) != " HTTP/" )
132- throw std::runtime_error (" Invalid response" );
133-
134- response_.version () = http_version;
135- response_.status () = status_code;
136- response_.status_message () = status_message;
137- };
138-
139- void read_headers (basic_response<Tag> & response_, boost::asio::ip::tcp::socket & socket, boost::asio::streambuf & response_buffer) const {
140- boost::asio::read_until (socket, response_buffer, " \r\n\r\n " );
141- std::istream response_stream (&response_buffer);
142- string_type header_line, name;
143- while (std::getline (response_stream, header_line) && header_line != " \r " ) {
144- trim_right_if (header_line, boost::is_space () || boost::is_any_of (" \r " ));
145- typename string_type::size_type colon_offset;
146- if (header_line.size () && header_line[0 ] == ' ' ) {
147- assert (!name.empty ());
148- if (name.empty ())
149- throw std::runtime_error (
150- std::string (" Malformed header: " )
151- + header_line
152- );
153- response_
154- << header (name, trim_left_copy (header_line));
155- } else if ((colon_offset = header_line.find_first_of (' :' )) != string_type::npos) {
156- name = header_line.substr (0 , colon_offset);
157- response_
158- << header (name, header_line.substr (colon_offset+2 ));
159- };
160- };
161- };
162-
163- void read_body (basic_response<Tag> & response_, boost::asio::ip::tcp::socket & socket, boost::asio::streambuf & response_buffer) const {
164- typename ostringstream<Tag>::type body_stream;
165-
166- if (response_buffer.size () > 0 )
167- body_stream << &response_buffer;
168-
169- boost::system::error_code error;
170- while (boost::asio::read (socket, response_buffer, boost::asio::transfer_at_least (1 ), error))
171- body_stream << &response_buffer;
172-
173- if (error != boost::asio::error::eof)
174- throw boost::system::system_error (error);
175-
176- response_ << body (body_stream.str ());
177- };
178-
17939 basic_response<Tag> const sync_request_skeleton (basic_request<Tag> const & request_, string_type method, bool get_body) {
18040 using boost::asio::ip::tcp;
18141
182- basic_request<Tag> request_copy (request_);
183- basic_response<Tag> response_;
184- do {
185- tcp::socket socket (service_);
186- init_socket (socket, request_copy.host (), boost::lexical_cast<string_type>(request_copy.port ()));
187- send_request (socket, method, request_copy);
188-
189- response_ = basic_response<Tag>();
190- response_ << source (request_copy.host ());
191-
192- boost::asio::streambuf response_buffer;
193- read_status (response_, socket, response_buffer);
194- read_headers (response_, socket, response_buffer);
195- if (get_body)
196- read_body (response_, socket, response_buffer);
197-
198- if (follow_redirect_) {
199- uint16_t status = response_.status ();
200- if (status >= 300 && status <= 307 ) {
201- typename headers_range<http::basic_response<Tag> >::type location_range = headers (response_)[" Location" ];
202- typename range_iterator<typename headers_range<http::basic_request<Tag> >::type>::type location_header = begin (location_range);
203- if (location_header != end (location_range)) {
204- request_copy.uri (location_header->second );
205- } else throw std::runtime_error (" Location header not defined in redirect response." );
206- } else break ;
207- } else break ;
208- } while (true );
209-
210- return response_;
211- };
42+ typename connection_base::connection_ptr connection_;
43+ connection_ = connection_base::get_connection (resolver_, request_);
44+ return connection_->send_request (method, request_, get_body);
45+ }
21246
21347 public:
21448
@@ -229,23 +63,23 @@ namespace boost { namespace network { namespace http {
22963 };
23064
23165 basic_client ()
232- : resolver_base (false ), service_(), resolver_(service_), follow_redirect_( false )
66+ : connection_base (false , false ), service_(), resolver_(service_)
23367 {};
23468
23569 explicit basic_client (cache_resolved_type (*)())
236- : resolver_base (true ), service_(), resolver_(service_), follow_redirect_( false )
70+ : connection_base (true , false ), service_(), resolver_(service_)
23771 {};
23872
23973 explicit basic_client (follow_redirect_type (*)())
240- : resolver_base (false ), service_(), resolver_(service_), follow_redirect_( true )
74+ : connection_base (false , true ), service_(), resolver_(service_)
24175 {};
24276
24377 basic_client (cache_resolved_type (*)(), follow_redirect_type (*)())
244- : resolver_base( false ), service_(), resolver_(service_), follow_redirect_( true )
78+ : connection_base( true , true ), service_(), resolver_(service_)
24579 {};
24680
24781 void clear_resolved_cache () {
248- resolver_base ::endpoint_cache_.clear ();
82+ connection_base ::endpoint_cache_.clear ();
24983 }
25084
25185 basic_response<Tag> const head (basic_request<Tag> const & request_) {
0 commit comments