Skip to content

Commit bb76f2c

Browse files
committed
Adding more to the asynchronous server implementation.
1 parent 961f68d commit bb76f2c

File tree

14 files changed

+372
-32
lines changed

14 files changed

+372
-32
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#ifndef BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028
2+
#define BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028
3+
4+
// Copyright 2010 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+
#include <boost/network/protocol/http/server/header/name.hpp>
10+
#include <boost/network/protocol/http/server/header/value.hpp>
11+
#include <boost/network/protocol/http/server/header/concept.hpp>
12+
#include <boost/network/constants.hpp>
13+
#include <boost/concept_check.hpp>
14+
15+
namespace boost { namespace network { namespace http {
16+
17+
template <class Tag, class ValueType>
18+
struct linearize {
19+
typedef typename string<Tag>::type string_type;
20+
21+
template <class Arguments>
22+
struct result {
23+
typedef string_type type;
24+
};
25+
26+
BOOST_CONCEPT_REQUIRES(
27+
(Header<ValueType),
28+
(string_type)
29+
) operator()(ValueType & header) {
30+
typedef typename ostringstream<Tag>::type output_stream;
31+
typedef constants<Tag> consts;
32+
output_stream header_line;
33+
header_line << name(header)
34+
<< consts::colon() << consts::space()
35+
<< value(header) << consts::crlf();
36+
return header_line.str();
37+
}
38+
};
39+
40+
} /* linearize */
41+
42+
} /* net */
43+
44+
} /* boost */
45+
46+
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028 */

boost/network/protocol/http/connection.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ namespace boost { namespace network { namespace http {
8686
if (done) {
8787
if (request_.method[0] == 'P') {
8888
// look for the content-length header
89-
std::vector<request_header>::iterator it =
89+
typename std::vector<request_header<Tag> >::iterator it =
9090
find_if(
9191
request_.headers.begin(),
9292
request_.headers.end(),

boost/network/protocol/http/header.hpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// ~~~~~~~~~~
44
//
55
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6-
// Copyright (c) 2009 Dean Michael Berris (mikhailberis@gmail.com)
6+
// Copyright (c) 2009,2010 Dean Michael Berris (mikhailberis@gmail.com)
77
// Copyright (c) 2009 Tarroo, Inc.
88
//
99
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -13,20 +13,23 @@
1313
#ifndef HTTP_SERVER3_HEADER_HPP
1414
#define HTTP_SERVER3_HEADER_HPP
1515

16-
#include <string>
16+
#include <boost/network/traits/string.hpp>
1717

1818
namespace boost { namespace network { namespace http {
1919

20-
struct request_header
21-
{
22-
std::string name;
23-
std::string value;
24-
};
25-
26-
inline void swap(request_header & l, request_header & r) {
27-
swap(l.name, r.name);
28-
swap(l.value, r.value);
29-
}
20+
template <class Tag>
21+
struct request_header
22+
{
23+
typedef typename string<Tag>::type string_type;
24+
string_type name;
25+
std::string value;
26+
};
27+
28+
template <class Tag>
29+
inline void swap(request_header<Tag> & l, request_header<Tag> & r) {
30+
swap(l.name, r.name);
31+
swap(l.value, r.value);
32+
}
3033

3134
} // namespace http
3235

boost/network/protocol/http/impl/request.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ namespace boost { namespace network { namespace http {
120120
typedef Tag tag;
121121
typedef typename string<Tag>::type string_type;
122122
typedef typename vector<tags::http_server>::
123-
template apply<request_header>::type
123+
template apply<request_header<Tag> >::type
124124
vector_type;
125125
typedef vector_type headers_container_type;
126126
typedef boost::uint16_t port_type;
@@ -160,12 +160,12 @@ namespace boost { namespace network { namespace http {
160160
/** Specialize the traits for the http_server tag. */
161161
template <>
162162
struct headers_container<http::tags::http_server> :
163-
vector<http::tags::http_server>::apply<http::request_header>
163+
vector<http::tags::http_server>::apply<http::request_header<http::tags::http_server> >
164164
{};
165165

166166
template <>
167167
struct headers_container<http::tags::http_async_server> :
168-
vector<http::tags::http_async_server>::apply<http::request_header>
168+
vector<http::tags::http_async_server>::apply<http::request_header<http::tags::http_async_server> >
169169
{};
170170

171171
namespace http { namespace impl {

boost/network/protocol/http/impl/request_parser.ipp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ boost::tribool basic_request_parser<Tag>::consume(basic_request<Tag> & req, char
207207
}
208208
else
209209
{
210-
req.headers.push_back(request_header());
210+
req.headers.push_back(request_header<Tag>());
211211
req.headers.back().name.push_back(input);
212212
state_ = header_name;
213213
return boost::indeterminate;

boost/network/protocol/http/impl/response.ipp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace boost { namespace network { namespace http {
5151
} status;
5252

5353
/// The headers to be included in the reply.
54-
typedef vector<tags::http_server>::apply<request_header>::type headers_vector;
54+
typedef vector<tags::http_server>::apply<request_header<tags::http_server> >::type headers_vector;
5555
headers_vector headers;
5656

5757
/// The content to be sent in the reply.
@@ -69,7 +69,7 @@ namespace boost { namespace network { namespace http {
6969
std::vector<const_buffer> buffers;
7070
buffers.push_back(to_buffer(status));
7171
for (std::size_t i = 0; i < headers.size(); ++i) {
72-
request_header& h = headers[i];
72+
request_header<tags::http_server> & h = headers[i];
7373
buffers.push_back(buffer(h.name));
7474
buffers.push_back(buffer(name_value_separator));
7575
buffers.push_back(buffer(h.value));

boost/network/protocol/http/server/async_connection.hpp

Lines changed: 116 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,129 @@
66
// (See accompanying file LICENSE_1_0.txt or copy at
77
// http://www.boost.org/LICENSE_1_0.txt)
88

9+
#include <boost/throw_exception.hpp>
10+
#include <boost/scope_exit.hpp>
11+
#include <boost/network/protocol/http/algorithms/linearize.hpp>
12+
#include <boost/network/utils/thread_pool.hpp>
13+
#include <boost/range/algorithm/transform.hpp>
14+
#include <boost/asio/ip/tcp.hpp>
15+
#include <boost/asio/streambuf.hpp>
16+
#include <iterator>
17+
918
namespace boost { namespace network { namespace http {
1019

1120
template <class Tag, class Handler>
12-
struct async_connection {
21+
struct async_connection : boost::enable_shared_from_this<async_connection<Tag,Handler> > {
1322
enum status_t {
1423
ok = 200
15-
, method_not_supported = 306
24+
, created = 201
25+
, accepted = 202
26+
, no_content = 204
27+
, multiple_choices = 300
28+
, moved_permanently = 301
29+
, moved_temporarily = 302
30+
, not_modified = 304
31+
, bad_request = 400
32+
, unauthorized = 401
33+
, forbidden = 403
34+
, not_found = 404
35+
, not_supported = 405
36+
, not_acceptable = 406
37+
, internal_server_error = 500
38+
, not_implemented = 501
39+
, bad_gateway = 502
40+
, service_unavailable = 503
1641
};
42+
43+
async_connection(
44+
asio::io_service & io_service
45+
, Handler & handler
46+
, utils::thread_pool & thread_pool
47+
)
48+
: socket_(io_service)
49+
, handler(handler)
50+
, thread_pool_(thread_pool)
51+
, headers_already_set(false)
52+
{}
53+
54+
/** Function: template <class Range> set_headers(Range headers)
55+
* Precondition: headers have not been set yet
56+
* Postcondition: headers have been set, and cannot be modified anymore.
57+
* Throws: std::logic_error in case the headers have already been set
58+
* and the precondition is not satisfied.
59+
*
60+
* A call to set_headers takes a Range where each element models the
61+
* Header concept. This Range will be linearized onto a buffer, which is
62+
* then sent as soon as the first call to `write` or `flush` commences.
63+
*/
1764
template <class Range>
18-
void set_headers(Range);
19-
void set_status(status_t);
65+
void set_headers(Range headers) {
66+
if (headers_already_set)
67+
boost::throw_exception(std::logic_error("Headers have already been set."));
68+
69+
bool commit = false;
70+
BOOST_SCOPE_EXIT_TPL((&commit)(&headers_already_set))
71+
{
72+
if (!commit) {
73+
headers_already_set = false;
74+
}
75+
} BOOST_SCOPE_EXIT_END
76+
77+
typedef constants<Tag> consts;
78+
79+
std::ostream stream(&headers_buffer);
80+
if (!boost::empty(headers)) {
81+
typedef typename Range::const_iterator iterator;
82+
typedef typename Range::value_type value_type;
83+
typedef typename string<Tag>::type string_type;
84+
boost::transform(headers,
85+
std::ostream_iterator<string_type>(stream),
86+
linearize<Tag, value_type>());
87+
} else {
88+
stream << consts::crlf();
89+
}
90+
stream << consts::crlf();
91+
commit = headers_already_set = true;
92+
}
93+
94+
void set_status(status_t new_status) {
95+
status = new_status;
96+
}
97+
2098
template <class Range>
21-
void write(Range);
22-
void flush();
23-
void close();
99+
void write(Range) {
100+
// linearize the range into a shared array
101+
// schedule a stranded asynchronous write
102+
}
103+
104+
void flush() {
105+
// use this as a synchronization point to ensure
106+
// that data has been written; use a unique_future
107+
}
108+
109+
void close() {
110+
flush();
111+
socket_.shutdown(asio::ip::tcp::socket::shutdown_both);
112+
socket_.close();
113+
}
114+
115+
asio::ip::tcp::socket & socket() { return socket_; }
116+
utils::thread_pool & thread_pool() { return thread_pool_; }
117+
118+
private:
119+
asio::ip::tcp::socket socket_;
120+
Handler & handler;
121+
utils::thread_pool & thread_pool_;
122+
bool headers_already_set;
123+
asio::streambuf headers_buffer;
124+
boost::uint16_t status;
125+
126+
template <class, class> friend struct async_server_base;
127+
128+
void start() {
129+
// FIXME do something!
130+
}
131+
24132
};
25133

26134
} /* http */
@@ -30,3 +138,4 @@ namespace boost { namespace network { namespace http {
30138
} /* boost */
31139

32140
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_CONNECTION_HPP_20101027 */
141+

boost/network/protocol/http/server/async_server.hpp

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,67 @@ namespace boost { namespace network { namespace http {
2424
, string_type const & port
2525
, Handler & handler
2626
, utils::thread_pool & thread_pool)
27-
{}
27+
: handler(handler)
28+
, thread_pool(thread_pool)
29+
, io_service()
30+
, acceptor(io_service)
31+
, stopping(false)
32+
{
33+
using boost::asio::ip::tcp;
34+
tcp::resolver resolver(io_service);
35+
tcp::resolver::query query(address, port);
36+
tcp::endpoint endpoint = *resolver.resolve(query);
37+
acceptor.open(endpoint.protocol());
38+
acceptor.bind(endpoint);
39+
acceptor.listen();
40+
new_connection.reset(new connection(io_service, handler, thread_pool));
41+
acceptor.async_accept(new_connection->socket(),
42+
boost::bind(
43+
&async_server_base<Tag,Handler>::handle_accept
44+
, this
45+
, boost::asio::placeholders::error));
46+
}
2847

29-
void run() {};
48+
void run() {
49+
io_service.run();
50+
};
3051

52+
void stop() {
53+
// stop accepting new requests and let all the existing
54+
// handlers finish.
55+
stopping = true;
56+
acceptor.cancel();
57+
}
58+
59+
private:
60+
Handler & handler;
61+
utils::thread_pool & thread_pool;
62+
asio::io_service io_service;
63+
asio::ip::tcp::acceptor acceptor;
64+
bool stopping;
65+
boost::shared_ptr<async_connection<Tag,Handler> > new_connection;
66+
67+
void handle_accept(boost::system::error_code const & ec) {
68+
if (!ec) {
69+
new_connection->start();
70+
if (!stopping) {
71+
new_connection.reset(
72+
new connection(
73+
io_service
74+
, handler
75+
, thread_pool
76+
)
77+
);
78+
acceptor.async_accept(new_connection->socket(),
79+
boost::bind(
80+
&async_server_base<Tag,Handler>::handle_accept
81+
, this
82+
, boost::asio::placeholders::error
83+
)
84+
);
85+
}
86+
}
87+
}
3188
};
3289

3390
} /* http */

0 commit comments

Comments
 (0)