Skip to content

Commit 96084b8

Browse files
committed
Merge branch '0.7-devel' of github.com:mikhailberis/cpp-netlib
2 parents f068c5c + abc6f01 commit 96084b8

File tree

1 file changed

+323
-0
lines changed

1 file changed

+323
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_PROTOCOL_HANDLER_HPP_20101015
2+
#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_PROTOCOL_HANDLER_HPP_20101015
3+
4+
// Copyright 2010 (C) Dean Michael Berris
5+
// Distributed under the Boost Software License, Version 1.0.
6+
// (See accompanying file LICENSE_1_0.txt or copy at
7+
// http://www.boost.org/LICENSE_1_0.txt)
8+
9+
namespace boost { namespace network { namespace http { namespace impl {
10+
11+
template <class Tag, unsigned version_major, unsigned version_minor>
12+
struct http_async_protocol_handler {
13+
protected:
14+
15+
typedef typename string<Tag>::type string_type;
16+
17+
template <class ResponseType>
18+
void init_response(ResponseType & response_, bool get_body) {
19+
boost::shared_future<string_type> source_future(source_promise.get_future());
20+
source(response_, source_future);
21+
boost::shared_future<string_type> destination_future(destination_promise.get_future());
22+
destination(response_, destination_future);
23+
boost::shared_future<typename headers_container<Tag>::type> headers_future(headers_promise.get_future());
24+
headers(response_, headers_future);
25+
boost::shared_future<string_type> body_future(body_promise.get_future());
26+
body(response_, body_future);
27+
boost::shared_future<string_type> version_future(version_promise.get_future());
28+
version(response_, version_future);
29+
boost::shared_future<boost::uint16_t> status_future(status_promise.get_future());
30+
status(response_, status_future);
31+
boost::shared_future<string_type> status_message_future(status_message_promise.get_future());
32+
status_message(response_, status_message_future);
33+
}
34+
35+
struct to_http_headers {
36+
typedef typename string<Tag>::type string_type;
37+
template <class U>
38+
string_type const operator() (U const & pair) const {
39+
typedef typename ostringstream<Tag>::type ostringstream_type;
40+
typedef constants<Tag> constants;
41+
ostringstream_type header_line;
42+
header_line << pair.first
43+
<< constants::colon()
44+
<< constants::space()
45+
<< pair.second
46+
<< constants::crlf();
47+
return header_line.str();
48+
}
49+
};
50+
51+
template <class RequestType>
52+
string_type init_command_stream(RequestType const & request, string_type const & method) {
53+
typename ostringstream<Tag>::type command_stream;
54+
string_type path_str;
55+
path_str = path(request);
56+
typedef constants<Tag> constants;
57+
command_stream
58+
<< method << constants::space()
59+
<< path_str << constants::space()
60+
<< constants::http_slash() << version_major
61+
<< constants::dot() << version_minor
62+
<< constants::crlf();
63+
64+
typedef typename headers_range<RequestType>::type headers_range_type;
65+
headers_range_type headers_ = headers(request);
66+
boost::range::transform(
67+
headers_,
68+
typename ostream_iterator<Tag, string_type>::type (command_stream),
69+
to_http_headers());
70+
71+
if (boost::empty(headers(request)[constants::host()])) {
72+
string_type host_str = host(request);
73+
command_stream
74+
<< constants::host() << constants::colon() << constants::space() << host_str << constants::crlf();
75+
}
76+
77+
if (boost::empty(headers(request)[constants::accept()])) {
78+
command_stream
79+
<< constants::accept() << constants::colon() << constants::space() << constants::default_accept_mime() << constants::crlf();
80+
}
81+
82+
if (version_major == 1u && version_minor == 1u && boost::empty(headers(request)[constants::accept_encoding()])) {
83+
command_stream
84+
<< constants::accept_encoding() << constants::colon() << constants::space() << constants::default_accept_encoding() << constants::crlf();
85+
}
86+
87+
if (boost::empty(headers(request)[constants::user_agent()])) {
88+
command_stream
89+
<< constants::user_agent() << constants::colon() << constants::space() << constants::cpp_netlib_slash() << BOOST_NETLIB_VERSION << constants::crlf();
90+
}
91+
92+
command_stream << constants::crlf();
93+
94+
return command_stream.str();
95+
}
96+
97+
template <class Socket, class Callback>
98+
logic::tribool parse_version(Socket & socket_, Callback callback) {
99+
logic::tribool parsed_ok;
100+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range;
101+
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
102+
response_parser_type::http_version_done,
103+
part);
104+
if (parsed_ok == true) {
105+
string_type version;
106+
std::swap(version, partial_parsed);
107+
version.append(boost::begin(result_range), boost::end(result_range));
108+
algorithm::trim(version);
109+
version_promise.set_value(version);
110+
part_begin = boost::end(result_range);
111+
} else if (parsed_ok == false) {
112+
std::runtime_error error("Invalid Version Part.");
113+
version_promise.set_exception(boost::copy_exception(error));
114+
status_promise.set_exception(boost::copy_exception(error));
115+
status_message_promise.set_exception(boost::copy_exception(error));
116+
headers_promise.set_exception(boost::copy_exception(error));
117+
source_promise.set_exception(boost::copy_exception(error));
118+
destination_promise.set_exception(boost::copy_exception(error));
119+
body_promise.set_exception(boost::copy_exception(error));
120+
} else {
121+
partial_parsed.append(
122+
boost::begin(result_range),
123+
boost::end(result_range)
124+
);
125+
part_begin = part.begin();
126+
boost::asio::async_read(
127+
socket_,
128+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
129+
callback
130+
);
131+
}
132+
return parsed_ok;
133+
}
134+
135+
template <class Socket, class Callback>
136+
logic::tribool parse_status(Socket & socket_, Callback callback) {
137+
logic::tribool parsed_ok;
138+
typename buffer_type::const_iterator part_end = part.end();
139+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range,
140+
input_range = boost::make_iterator_range(part_begin, part_end);
141+
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
142+
response_parser_type::http_status_done,
143+
input_range);
144+
if (parsed_ok == true) {
145+
string_type status;
146+
std::swap(status, partial_parsed);
147+
status.append(boost::begin(result_range), boost::end(result_range));
148+
trim(status);
149+
boost::uint16_t status_int = lexical_cast<boost::uint16_t>(status);
150+
status_promise.set_value(status_int);
151+
part_begin = boost::end(result_range);
152+
} else if (parsed_ok == false) {
153+
std::runtime_error error("Invalid status part.");
154+
status_promise.set_exception(boost::copy_exception(error));
155+
status_message_promise.set_exception(boost::copy_exception(error));
156+
headers_promise.set_exception(boost::copy_exception(error));
157+
source_promise.set_exception(boost::copy_exception(error));
158+
destination_promise.set_exception(boost::copy_exception(error));
159+
body_promise.set_exception(boost::copy_exception(error));
160+
} else {
161+
partial_parsed.append(
162+
boost::begin(result_range),
163+
boost::end(result_range)
164+
);
165+
part_begin = part.begin();
166+
boost::asio::async_read(socket_,
167+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
168+
callback
169+
);
170+
}
171+
return parsed_ok;
172+
}
173+
174+
template <class Socket, class Callback>
175+
logic::tribool parse_status_message(Socket & socket_, Callback callback) {
176+
logic::tribool parsed_ok;
177+
typename buffer_type::const_iterator part_end = part.end();
178+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range,
179+
input_range = boost::make_iterator_range(part_begin, part_end);
180+
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
181+
response_parser_type::http_status_message_done,
182+
input_range);
183+
if (parsed_ok == true) {
184+
string_type status_message;
185+
std::swap(status_message, partial_parsed);
186+
status_message.append(boost::begin(result_range), boost::end(result_range));
187+
algorithm::trim(status_message);
188+
status_message_promise.set_value(status_message);
189+
part_begin = boost::end(result_range);
190+
} else if (parsed_ok == false) {
191+
std::runtime_error error("Invalid status message part.");
192+
status_message_promise.set_exception(boost::copy_exception(error));
193+
headers_promise.set_exception(boost::copy_exception(error));
194+
source_promise.set_exception(boost::copy_exception(error));
195+
destination_promise.set_exception(boost::copy_exception(error));
196+
body_promise.set_exception(boost::copy_exception(error));
197+
} else {
198+
partial_parsed.append(
199+
boost::begin(result_range),
200+
boost::end(result_range));
201+
part_begin = part.begin();
202+
boost::asio::async_read(
203+
socket_,
204+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
205+
callback
206+
);
207+
}
208+
return parsed_ok;
209+
}
210+
211+
void parse_headers_real(string_type & headers_part) {
212+
typename boost::iterator_range<typename string_type::const_iterator>
213+
input_range = boost::make_iterator_range(headers_part)
214+
, result_range;
215+
logic::tribool parsed_ok;
216+
response_parser_type headers_parser(response_parser_type::http_header_line_done);
217+
typename headers_container<Tag>::type headers;
218+
std::pair<string_type,string_type> header_pair;
219+
while (!boost::empty(input_range)) {
220+
fusion::tie(parsed_ok, result_range) = headers_parser.parse_until(
221+
response_parser_type::http_header_colon
222+
, input_range);
223+
if (headers_parser.state() != response_parser_type::http_header_colon) break;
224+
header_pair.first = string_type(
225+
boost::begin(result_range),
226+
boost::end(result_range));
227+
input_range.advance_begin(boost::distance(result_range));
228+
fusion::tie(parsed_ok, result_range) = headers_parser.parse_until(
229+
response_parser_type::http_header_line_done
230+
, input_range);
231+
header_pair.second = string_type(
232+
boost::begin(result_range),
233+
boost::end(result_range));
234+
input_range.advance_begin(boost::distance(result_range));
235+
236+
trim(header_pair.first);
237+
if (header_pair.first.size() > 1) {
238+
header_pair.first.erase(
239+
header_pair.first.size() - 1
240+
);
241+
}
242+
trim(header_pair.second);
243+
headers.insert(header_pair);
244+
}
245+
headers_promise.set_value(headers);
246+
}
247+
248+
template <class Socket, class Callback>
249+
fusion::tuple<logic::tribool, size_t> parse_headers(Socket & socket_, Callback callback) {
250+
logic::tribool parsed_ok;
251+
typename buffer_type::const_iterator part_end = part.end();
252+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range,
253+
input_range = boost::make_iterator_range(part_begin, part_end);
254+
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
255+
response_parser_type::http_headers_done,
256+
input_range);
257+
if (parsed_ok == true) {
258+
string_type headers_string;
259+
std::swap(headers_string, partial_parsed);
260+
headers_string.append(boost::begin(result_range), boost::end(result_range));
261+
part_begin = boost::end(result_range);
262+
this->parse_headers_real(headers_string);
263+
} else if (parsed_ok == false) {
264+
std::runtime_error error("Invalid header part.");
265+
headers_promise.set_exception(boost::copy_exception(error));
266+
body_promise.set_exception(boost::copy_exception(error));
267+
source_promise.set_exception(boost::copy_exception(error));
268+
destination_promise.set_exception(boost::copy_exception(error));
269+
} else {
270+
partial_parsed.append(boost::begin(result_range), boost::end(result_range));
271+
part_begin = part.begin();
272+
boost::asio::async_read(
273+
socket_,
274+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
275+
callback
276+
);
277+
}
278+
return fusion::make_tuple(
279+
parsed_ok,
280+
std::distance(
281+
boost::end(result_range)
282+
, part_end
283+
)
284+
);
285+
}
286+
287+
template <class Socket, class Callback>
288+
void parse_body(Socket & socket_, Callback callback, size_t bytes) {
289+
partial_parsed.append(part_begin, bytes);
290+
part_begin = part.begin();
291+
boost::asio::async_read(
292+
socket_,
293+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
294+
callback
295+
);
296+
}
297+
298+
typedef response_parser<Tag> response_parser_type;
299+
typedef boost::array<typename char_<Tag>::type, 1024> buffer_type;
300+
301+
response_parser_type response_parser_;
302+
boost::promise<string_type> version_promise;
303+
boost::promise<boost::uint16_t> status_promise;
304+
boost::promise<string_type> status_message_promise;
305+
boost::promise<typename headers_container<Tag>::type> headers_promise;
306+
boost::promise<string_type> source_promise;
307+
boost::promise<string_type> destination_promise;
308+
boost::promise<string_type> body_promise;
309+
buffer_type part;
310+
typename buffer_type::const_iterator part_begin;
311+
string_type partial_parsed;
312+
};
313+
314+
315+
} /* impl */
316+
317+
} /* http */
318+
319+
} /* network */
320+
321+
} /* boost */
322+
323+
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_PROTOCOL_HANDLER_HPP_20101015 */

0 commit comments

Comments
 (0)