7
7
#ifndef __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
8
8
#define __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
9
9
10
- #ifndef BOOST_NETLIB_VERSION
11
- #define BOOST_NETLIB_VERSION " 0.5"
12
- #endif
13
-
10
+ #include < boost/network/version.hpp>
14
11
#include < boost/network/traits/ostringstream.hpp>
15
12
#include < boost/network/protocol/http/message.hpp>
16
13
#include < boost/network/protocol/http/response.hpp>
17
14
#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>
19
16
#include < boost/asio.hpp>
20
17
#include < boost/lexical_cast.hpp>
21
18
#include < boost/algorithm/string/classification.hpp>
22
19
#include < boost/algorithm/string/split.hpp>
23
- #include < boost/tuple/tuple.hpp>
24
20
#include < boost/foreach.hpp>
25
21
#include < ostream>
26
22
#include < istream>
31
27
namespace boost { namespace network { namespace http {
32
28
33
29
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 {
35
31
36
32
private:
37
- typedef typename resolver_policy <Tag>::type resolver_base ;
33
+ typedef typename connection_policy <Tag, version_major, version_minor >::type connection_base ;
38
34
boost::asio::io_service service_;
39
- typename resolver_base::resolver_type resolver_;
40
- bool follow_redirect_;
35
+ typename connection_base::resolver_type resolver_;
41
36
42
37
typedef typename string<Tag>::type string_type;
43
38
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
-
179
39
basic_response<Tag> const sync_request_skeleton (basic_request<Tag> const & request_, string_type method, bool get_body) {
180
40
using boost::asio::ip::tcp;
181
41
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
+ }
212
46
213
47
public:
214
48
@@ -229,23 +63,23 @@ namespace boost { namespace network { namespace http {
229
63
};
230
64
231
65
basic_client ()
232
- : resolver_base (false ), service_(), resolver_(service_), follow_redirect_( false )
66
+ : connection_base (false , false ), service_(), resolver_(service_)
233
67
{};
234
68
235
69
explicit basic_client (cache_resolved_type (*)())
236
- : resolver_base (true ), service_(), resolver_(service_), follow_redirect_( false )
70
+ : connection_base (true , false ), service_(), resolver_(service_)
237
71
{};
238
72
239
73
explicit basic_client (follow_redirect_type (*)())
240
- : resolver_base (false ), service_(), resolver_(service_), follow_redirect_( true )
74
+ : connection_base (false , true ), service_(), resolver_(service_)
241
75
{};
242
76
243
77
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_)
245
79
{};
246
80
247
81
void clear_resolved_cache () {
248
- resolver_base ::endpoint_cache_.clear ();
82
+ connection_base ::endpoint_cache_.clear ();
249
83
}
250
84
251
85
basic_response<Tag> const head (basic_request<Tag> const & request_) {
0 commit comments