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>::typeresolver_base ;
33
+ typedef typename connection_policy <Tag, version_major, version_minor >::typeconnection_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_typeconst & hostname, string_typeconst & 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_typeconst & method, basic_request<Tag> request_)const {
69
- std::ostreamrequest_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_typeconst & 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_typeconst & 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::istreamresponse_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::istreamresponse_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::socketsocket (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_) {