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
Lines changed: 323 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy