Skip to content

Commit db3d633

Browse files
author
mikhail_beris
committed
Initial implementation of the HTTP 1.0 client, request, and response objects. Accompanying unit test at test/http_1_0_test.cpp shows basic usage scenarios.
1 parent 11567ac commit db3d633

File tree

11 files changed

+359
-2
lines changed

11 files changed

+359
-2
lines changed

Jamroot

+2
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ local BOOST_ROOT = [ modules.peek : BOOST_ROOT ] ;
1111
use-project /boost : $(BOOST_ROOT) ;
1212

1313
using testing ;
14+
15+
build-project libs/network/test ;

boost/network.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// Date: May 20, 2007
1313

1414
#include <boost/network/message.hpp> // message type implementation
15+
#include <boost/network/protocol.hpp> // protocols implementation
1516

1617
#endif // __NETWORK_HPP__
1718

boost/network/message.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ namespace boost { namespace network {
3232
namespace boost { namespace network {
3333

3434
struct tags {
35-
struct default_ { };
35+
struct default_ {
36+
typedef std::string str_type;
37+
};
3638
};
3739

3840
/** The common message type.

boost/network/protocol.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef __NETWORK_PROTOCOLS_20070908_1_HPP__
8+
#define __NETWORK_PROTOCOLS_20070908_1_HPP__
9+
10+
// Include all protocol implementation headers in protocol/*
11+
// Author: Dean Michael Berris
12+
// Date Created: Oct. 08, 2007
13+
14+
#include <boost/network/protocol/http.hpp> // include HTTP implementation
15+
16+
#endif // __NETWORK_PROTOCOLS_20070908-1_HPP__

boost/network/protocol/http.hpp

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef __NETWORK_PROTOCOL_HTTP_20070908_1_HPP__
8+
#define __NETWORK_PROTOCOL_HTTP_20070908_1_HPP__
9+
10+
// Include HTTP implementation headers
11+
// Author: Dean Michael Berris
12+
// Date Created: Oct. 08, 2007
13+
14+
#include <boost/network/protocol/http/request.hpp>
15+
#include <boost/network/protocol/http/response.hpp>
16+
#include <boost/network/protocol/http/client.hpp>
17+
18+
#endif // __NETWORK_PROTOCOL_HTTP_20070908-1_HPP__
+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
8+
#define __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
9+
10+
#include <boost/network/protocol/http/response.hpp>
11+
#include <boost/asio.hpp>
12+
#include <boost/lexical_cast.hpp>
13+
#include <sstream>
14+
#include <string>
15+
16+
namespace boost { namespace network { namespace http {
17+
18+
template <class tag, unsigned int version_major = 1, unsigned version_minor = 0>
19+
class basic_client {
20+
21+
public:
22+
23+
response const get (basic_request<tag> const & request_) {
24+
// TODO: use Asio's iostream interface to perform
25+
// a synchronous request for data via HTTP
26+
// and then craft a response object to be returned
27+
// based on the headers received, and the contents
28+
using namespace boost::asio;
29+
30+
ip::tcp::iostream socket_stream(request_.host(), boost::lexical_cast<typename tag::str_type>(request_.port()), ip::tcp::resolver_query::numeric_service);
31+
socket_stream
32+
<< "GET /"
33+
<< request_.path()
34+
;
35+
36+
if (request_.query() != "")
37+
socket_stream
38+
<< '?'
39+
<< request_.query()
40+
;
41+
42+
if (request_.anchor() != "")
43+
socket_stream
44+
<< '#'
45+
<< request_.anchor()
46+
;
47+
48+
socket_stream << " HTTP/" << version_major << '.' << version_minor << "\r\n"
49+
<< "Host: " << request_.host() << "\r\n\r\n";
50+
51+
socket_stream << std::flush;
52+
53+
response response_;
54+
std::ostringstream body_stream;
55+
56+
while (!socket_stream.eof()) {
57+
typename tag::str_type line;
58+
std::getline(socket_stream, line);
59+
if (line.size() == 0u) {
60+
break;
61+
};
62+
response_
63+
<<
64+
header( line.substr(0, line.find(':')) ,
65+
line.find(' ') == tag::str_type::npos ?
66+
tag::str_type()
67+
: line.substr(line.find(' ') + 1));
68+
};
69+
70+
while (!socket_stream.eof()) {
71+
typename tag::str_type line;
72+
std::getline(socket_stream, line);
73+
body_stream << line;
74+
};
75+
76+
response_ << body(body_stream.str());
77+
return response_;
78+
};
79+
80+
};
81+
82+
typedef basic_client<tags::default_, 1, 0> client;
83+
84+
}; // namespace http
85+
86+
}; // namespace network
87+
88+
}; // namespace boost
89+
90+
#endif // __NETWORK_PROTOCOL_HTTP_CLIENT_20070908_1_HPP__
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef __NETWORK_PROTOCOL_HTTP_REQUEST_IMPL_20070908_1_HPP__
8+
#define __NETWORK_PROTOCOL_HTTP_REQUEST_IMPL_20070908_1_HPP__
9+
10+
#include <boost/fusion/sequence/container/map.hpp>
11+
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
12+
#include <boost/fusion/sequence/intrinsic/value_at_key.hpp>
13+
14+
#include <boost/spirit.hpp>
15+
#include <boost/spirit/phoenix.hpp>
16+
17+
namespace boost { namespace network { namespace http {
18+
19+
/** request.hpp
20+
*
21+
* This file implements the basic request object required
22+
* by the HTTP client implementation. The basic_request
23+
* object encapsulates a URI which is parsed at runtime.
24+
* The data is broken up according to the URI specifications
25+
* RFC 3986 -- http://www.ietf.org/rfc/rfc3986.txt -- and
26+
* represented as a Fusion Map.
27+
*/
28+
29+
template <class tag>
30+
class basic_request {
31+
struct tags {
32+
struct protocol { };
33+
struct host { };
34+
struct port { };
35+
struct path { };
36+
struct query { };
37+
struct anchor { };
38+
};
39+
40+
typedef fusion::map<
41+
fusion::pair<typename tags::protocol,typename tag::str_type>,
42+
fusion::pair<typename tags::host,typename tag::str_type>,
43+
fusion::pair<typename tags::port,unsigned int>,
44+
fusion::pair<typename tags::path,typename tag::str_type>,
45+
fusion::pair<typename tags::query,typename tag::str_type>,
46+
fusion::pair<typename tags::anchor,typename tag::str_type>
47+
> uri_parts_type;
48+
49+
mutable uri_parts_type uri_parts;
50+
51+
public:
52+
explicit basic_request(typename tag::str_type const & uri) {
53+
using namespace boost::spirit;
54+
using namespace phoenix;
55+
56+
fusion::at_key<typename tags::port>(uri_parts) = 80u;
57+
58+
parse(
59+
uri.begin(), uri.end(),
60+
// the parser
61+
str_p("http")[
62+
var(fusion::at_key<typename tags::protocol>(uri_parts))
63+
= construct_<typename tag::str_type>(arg1, arg2)
64+
]
65+
>> str_p("://")
66+
>> (+(alnum_p | '.' | '-' | '_'))[
67+
var(fusion::at_key<typename tags::host>(uri_parts))
68+
= construct_<typename tag::str_type>(arg1, arg2)
69+
]
70+
>> !(
71+
ch_p(':')
72+
>> uint_p[
73+
var(fusion::at_key<typename tags::port>(uri_parts))
74+
= arg1
75+
]
76+
>> !ch_p('/')
77+
)
78+
>> (+(alnum_p | '/' | '%' | '_' | '-' | '.'))[
79+
var(fusion::at_key<typename tags::path>(uri_parts))
80+
= construct_<typename tag::str_type>(arg1, arg2)
81+
]
82+
>> !(ch_p('?')
83+
>> (+(alnum_p | '&' | '=' | '%' | '_' ))[
84+
var(fusion::at_key<typename tags::query>(uri_parts))
85+
= construct_<typename tag::str_type>(arg1, arg2)
86+
]
87+
)
88+
>> !(ch_p('#')
89+
>> (+(alnum_p | '_' | '%' | '-'))[
90+
var(fusion::at_key<typename tags::anchor>(uri_parts))
91+
= construct_<typename tag::str_type>(arg1, arg2)
92+
]
93+
)
94+
>> end_p
95+
,
96+
nothing_p // no skip parser
97+
);
98+
};
99+
100+
// conversion from a message object into a basic_request
101+
basic_request(basic_message<tag> const & message_) {
102+
//TODO: contruct from a network message object
103+
};
104+
105+
basic_request(basic_request const & other) :
106+
uri_parts(other.uri_parts)
107+
{ };
108+
109+
typename tag::str_type const host() const {
110+
return fusion::at_key<tags::host>(uri_parts);
111+
};
112+
113+
unsigned int port() const {
114+
return fusion::at_key<tags::port>(uri_parts);
115+
};
116+
117+
typename tag::str_type const path() const {
118+
return fusion::at_key<tags::path>(uri_parts);
119+
};
120+
121+
typename tag::str_type const query() const {
122+
return fusion::at_key<tags::query>(uri_parts);
123+
};
124+
125+
typename tag::str_type const anchor() const {
126+
return fusion::at_key<tags::anchor>(uri_parts);
127+
};
128+
};
129+
130+
}; // namespace http
131+
132+
}; // namespace network
133+
134+
}; // namespace boost
135+
136+
#endif // __NETWORK_PROTOCOL_HTTP_REQUEST_IMPL_20070908_1_HPP__
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef __NETWORK_PROTOCOL_HTTP_REQUEST_20070908_1_HPP__
8+
#define __NETWORK_PROTOCOL_HTTP_REQUEST_20070908_1_HPP__
9+
10+
// Implement the HTTP Request Object
11+
12+
#include <boost/network/message.hpp>
13+
14+
// forward declarations
15+
namespace boost { namespace network { namespace http {
16+
17+
template <class tag>
18+
class basic_request;
19+
20+
typedef basic_request<tags::default_> request;
21+
22+
}; // namespace http
23+
24+
}; // namespace network
25+
26+
}; // namespace boost
27+
28+
#include <boost/network/protocol/http/client.hpp>
29+
#include <boost/network/protocol/http/impl/request.hpp>
30+
31+
#endif // __NETWORK_PROTOCOL_HTTP_REQUEST_20070908-1_HPP__
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef __NETWORK_PROTOCOL_HTTP_RESPONSE_20070908_1_HPP__
8+
#define __NETWORK_PROTOCOL_HTTP_RESPONSE_20070908_1_HPP__
9+
10+
#include <boost/network/message.hpp>
11+
12+
namespace boost { namespace network { namespace http {
13+
14+
template <class tag>
15+
struct basic_response : public basic_message<tag> {
16+
typedef typename basic_message<tag>::headers_container_type headers_container_type;
17+
};
18+
19+
typedef basic_response<tags::default_> response;
20+
21+
}; // namespace http
22+
23+
}; // namespace network
24+
25+
}; // namespace boost
26+
27+
#endif // __NETWORK_PROTOCOL_HTTP_RESPONSE_20070908-1_HPP__

libs/network/test/Jamfile.v2

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ project network_test :
88
requirements
99
<include>../../../
1010
<source>/boost//unit_test_framework
11-
# <link>static
11+
<source>/boost//system
12+
<source>/boost//date_time
13+
<source>/boost//regex
14+
<link>static
1215
;
1316

1417
unit-test message_test : message_test.cpp ;
1518

1619
unit-test message_transform_test : message_transform_test.cpp ;
20+
21+
unit-test http_1_0_test : http_1_0_test.cpp ;

libs/network/test/http_1_0_test.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
// Copyright Dean Michael Berris 2007.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#define BOOST_TEST_MODULE http 1.0 test
8+
#include <boost/test/unit_test.hpp>
9+
#include <boost/network.hpp>
10+
#include <iostream>
11+
12+
BOOST_AUTO_TEST_CASE(constructor_test) {
13+
using namespace boost::network;
14+
http::request request("http://boost.org");
15+
BOOST_CHECK_EQUAL ( request.host() , "boost.org" );
16+
BOOST_CHECK_EQUAL ( request.port() , 80u );
17+
BOOST_CHECK_EQUAL ( request.path() , "" );
18+
}
19+
20+
BOOST_AUTO_TEST_CASE(http_get_test) {
21+
using namespace boost::network;
22+
http::request request("http://boost.org/");
23+
http::client client_;
24+
http::response response_;
25+
response_ = client_.get(request);
26+
headers_range<http::response>::type range = headers(response_)["Content-Length"];
27+
BOOST_CHECK ( range.first != range.second );
28+
BOOST_CHECK ( body(response_).size() != 0 );
29+
};

0 commit comments

Comments
 (0)