Skip to content

Commit ab45ced

Browse files
committed
Supporting BOOST_NETWORK_NO_LIB
This commit actually enables support for the BOOST_NETWORK_NO_LIB macro that will allow users of the library to define this so that there will be no need to have the externally-linked components when the network library is used. This commit only adds the support for the URI parsing parts -- this means that code using the HTTP client code don't need to link the URI parser external library to use it. NOTE: I'm still thinking about whether it's better that the default implementation would remain header-only, and only have a special macro for requiring the externally-linked libraries. I'm still not convinced that the default for header-only would be productive, but I'm still thinking about how to support some sort of backward compatibility for the code that's already using the library in header only mode.
1 parent fee26a1 commit ab45ced

File tree

5 files changed

+365
-307
lines changed

5 files changed

+365
-307
lines changed
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
2+
// Copyright 2010-2011 Dean Michael Berris.
3+
// Copyright 2009 Jeroen Habraken.
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt)
7+
8+
#ifndef PARSE_URI_IMPL_AQAWWXWT
9+
#define PARSE_URI_IMPL_AQAWWXWT
10+
11+
#ifdef BOOST_NETWORK_NO_LIB
12+
#define BOOST_NETWORK_INLINE inline
13+
#else
14+
#define BOOST_NETWORK_INLINE
15+
#endif
16+
17+
#include <boost/spirit/include/phoenix_operator.hpp>
18+
#include <boost/spirit/include/qi_attr.hpp>
19+
#include <boost/spirit/include/qi_core.hpp>
20+
#include <boost/spirit/include/qi_eps.hpp>
21+
#include <boost/spirit/include/qi_grammar.hpp>
22+
#include <boost/spirit/include/qi_omit.hpp>
23+
#include <boost/spirit/include/qi_raw.hpp>
24+
#include <boost/spirit/include/qi_rule.hpp>
25+
#include <boost/spirit/include/qi_sequence.hpp>
26+
#include <boost/spirit/include/version.hpp>
27+
28+
#include <boost/network/uri/detail/uri_parts.hpp>
29+
#include <boost/network/uri/detail/parse_uri.hpp>
30+
31+
#include <boost/fusion/adapted/struct.hpp>
32+
33+
BOOST_FUSION_ADAPT_STRUCT(boost::network::uri::detail::uri_parts_default_base,
34+
(std::string, scheme)
35+
(optional<std::string>, user_info)
36+
(optional<std::string>, host)
37+
(optional<boost::uint16_t>, port)
38+
(optional<std::string>, path)
39+
(optional<std::string>, query)
40+
(optional<std::string>, fragment)
41+
)
42+
43+
BOOST_FUSION_ADAPT_STRUCT(boost::network::uri::detail::uri_parts_wide_base,
44+
(std::wstring, scheme)
45+
(optional<std::wstring>, user_info)
46+
(optional<std::wstring>, host)
47+
(optional<boost::uint16_t>, port)
48+
(optional<std::wstring>, path)
49+
(optional<std::wstring>, query)
50+
(optional<std::wstring>, fragment)
51+
)
52+
53+
namespace boost { namespace spirit { namespace traits {
54+
template <>
55+
struct transform_attribute<
56+
boost::network::uri::detail::uri_parts_default_base,
57+
boost::fusion::tuple<
58+
std::string &,
59+
boost::fusion::tuple<
60+
boost::optional<std::string>&,
61+
boost::optional<std::string>&,
62+
boost::optional<boost::uint16_t> &,
63+
std::string &
64+
>,
65+
optional<std::string>&,
66+
optional<std::string>&
67+
>
68+
#if SPIRIT_VERSION >= 0x2030
69+
, boost::spirit::qi::domain
70+
#endif
71+
>
72+
{
73+
typedef
74+
boost::fusion::tuple<
75+
std::string &,
76+
boost::fusion::tuple<
77+
boost::optional<std::string>&,
78+
boost::optional<std::string>&,
79+
boost::optional<boost::uint16_t> &,
80+
std::string &
81+
>,
82+
optional<std::string>&,
83+
optional<std::string>&
84+
> type;
85+
86+
static type pre(boost::network::uri::detail::uri_parts_default_base & parts) {
87+
boost::fusion::tuple<
88+
boost::optional<std::string> &,
89+
boost::optional<std::string> &,
90+
boost::optional<boost::uint16_t> &,
91+
std::string &
92+
> hier_part =
93+
boost::fusion::tie(
94+
parts.user_info,
95+
parts.host,
96+
parts.port,
97+
parts.path
98+
);
99+
100+
return boost::fusion::tie(
101+
parts.scheme,
102+
hier_part,
103+
parts.query,
104+
parts.fragment
105+
);
106+
}
107+
108+
static void post(boost::network::uri::detail::uri_parts_default_base &, type const &) { }
109+
110+
#if SPIRIT_VERSION >= 0x2030
111+
static void fail(boost::network::uri::detail::uri_parts_default_base & val) { }
112+
#endif
113+
};
114+
115+
#if SPIRIT_VERSION < 0x2030
116+
template <typename Exposed, typename Transformed>
117+
struct transform_attribute<
118+
optional<Exposed>,
119+
Transformed,
120+
typename disable_if<is_same<optional<Exposed>, Transformed> >::type
121+
>
122+
{
123+
typedef Transformed & type;
124+
125+
static Transformed & pre(optional<Exposed> & val) {
126+
if (!val)
127+
val = Transformed();
128+
return boost::get<Transformed>(val);
129+
}
130+
131+
static void post(optional<Exposed> &, Transformed const &) { }
132+
};
133+
#endif
134+
} // namespace traits
135+
} // namespace spirit
136+
} // namespace boost
137+
138+
139+
namespace boost { namespace network { namespace uri { namespace detail {
140+
141+
namespace qi = boost::spirit::qi;
142+
143+
template <typename Iterator>
144+
struct uri_grammar_default : qi::grammar<Iterator, uri_parts_default_base()> {
145+
uri_grammar_default() : uri_grammar_default::base_type(start, "uri") {
146+
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
147+
gen_delims %= qi::char_(":/?#[]@");
148+
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
149+
sub_delims %= qi::char_("!$&'()*+,;=");
150+
// reserved = gen-delims / sub-delims
151+
reserved %= gen_delims | sub_delims;
152+
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
153+
unreserved %= qi::alnum | qi::char_("-._~");
154+
// pct-encoded = "%" HEXDIG HEXDIG
155+
pct_encoded %= qi::char_("%") >> qi::repeat(2)[qi::xdigit];
156+
157+
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
158+
pchar %= qi::raw[
159+
unreserved | pct_encoded | sub_delims | qi::char_(":@")
160+
];
161+
162+
// segment = *pchar
163+
segment %= qi::raw[*pchar];
164+
// segment-nz = 1*pchar
165+
segment_nz %= qi::raw[+pchar];
166+
// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
167+
segment_nz_nc %= qi::raw[
168+
+(unreserved | pct_encoded | sub_delims | qi::char_("@"))
169+
];
170+
// path-abempty = *( "/" segment )
171+
path_abempty %= qi::raw[*(qi::char_("/") >> segment)];
172+
// path-absolute = "/" [ segment-nz *( "/" segment ) ]
173+
path_absolute %= qi::raw[
174+
qi::char_("/")
175+
>> -(segment_nz >> *(qi::char_("/") >> segment))
176+
];
177+
// path-rootless = segment-nz *( "/" segment )
178+
path_rootless %= qi::raw[
179+
segment_nz >> *(qi::char_("/") >> segment)
180+
];
181+
// path-empty = 0<pchar>
182+
path_empty %= qi::eps;
183+
184+
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
185+
scheme %= qi::alpha >> *(qi::alnum | qi::char_("+.-"));
186+
187+
// user_info = *( unreserved / pct-encoded / sub-delims / ":" )
188+
user_info %= qi::raw[
189+
*(unreserved | pct_encoded | sub_delims | qi::char_(":"))
190+
];
191+
192+
// dec-octet = DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
193+
dec_octet %=
194+
!(qi::lit('0') >> qi::digit)
195+
>> qi::raw[
196+
qi::uint_parser<boost::uint8_t, 10, 1, 3>()
197+
];
198+
// IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
199+
ipv4address %= qi::raw[
200+
dec_octet >> qi::repeat(3)[qi::lit('.') >> dec_octet]
201+
];
202+
// reg-name = *( unreserved / pct-encoded / sub-delims )
203+
reg_name %= qi::raw[
204+
*(unreserved | pct_encoded | sub_delims)
205+
];
206+
// TODO, host = IP-literal / IPv4address / reg-name
207+
host %= ipv4address | reg_name;
208+
209+
// query = *( pchar / "/" / "?" )
210+
query %= qi::raw[*(pchar | qi::char_("/?"))];
211+
// fragment = *( pchar / "/" / "?" )
212+
fragment %= qi::raw[*(pchar | qi::char_("/?"))];
213+
214+
// hier-part = "//" authority path-abempty / path-absolute / path-rootless / path-empty
215+
// authority = [ userinfo "@" ] host [ ":" port ]
216+
hier_part %=
217+
(
218+
"//"
219+
>> -(user_info >> '@')
220+
>> host
221+
>> -(':' >> qi::ushort_)
222+
>> path_abempty
223+
)
224+
|
225+
(
226+
qi::attr(optional<std::string>())
227+
>> qi::attr(optional<std::string>())
228+
>> qi::attr(optional<boost::uint16_t>())
229+
>> (
230+
path_absolute
231+
| path_rootless
232+
| path_empty
233+
)
234+
);
235+
236+
uri %=
237+
scheme >> ':'
238+
>> hier_part
239+
>> -('?' >> query)
240+
>> -('#' >> fragment);
241+
242+
start %= uri.alias();
243+
}
244+
245+
typedef std::string string_type;
246+
247+
qi::rule<Iterator, typename string_type::value_type()>
248+
gen_delims, sub_delims, reserved, unreserved;
249+
qi::rule<Iterator, string_type()>
250+
pct_encoded, pchar;
251+
252+
qi::rule<Iterator, string_type()>
253+
segment, segment_nz, segment_nz_nc;
254+
qi::rule<Iterator, string_type()>
255+
path_abempty, path_absolute, path_rootless, path_empty;
256+
257+
qi::rule<Iterator, string_type()>
258+
dec_octet, ipv4address, reg_name, host;
259+
260+
qi::rule<Iterator, string_type()>
261+
scheme, user_info, query, fragment;
262+
263+
qi::rule<Iterator, boost::fusion::tuple<
264+
optional<string_type>&,
265+
optional<string_type>&,
266+
optional<boost::uint16_t>&,
267+
string_type &
268+
>()> hier_part;
269+
270+
// start rule of grammar
271+
qi::rule<Iterator, uri_parts_default_base()> start;
272+
273+
// actual uri parser
274+
qi::rule<
275+
Iterator,
276+
boost::fusion::tuple<
277+
string_type&,
278+
boost::fusion::tuple<
279+
optional<string_type>&,
280+
optional<string_type>&,
281+
optional<boost::uint16_t>&,
282+
string_type &
283+
>,
284+
optional<string_type>&,
285+
optional<string_type>&
286+
>()
287+
> uri;
288+
289+
};
290+
291+
BOOST_NETWORK_INLINE bool parse_uri_impl(boost::iterator_range<std::string::const_iterator> & range, uri_parts_default_base & parts, boost::network::tags::default_string) {
292+
// Qualified boost::begin and boost::end because MSVC complains
293+
// of ambiguity on call to begin(range) and end(rand).
294+
std::string::const_iterator start_ = boost::begin(range);
295+
std::string::const_iterator end_ = boost::end(range);
296+
297+
static uri_grammar_default<std::string::const_iterator> grammar;
298+
299+
bool ok = qi::parse(start_, end_, grammar, parts);
300+
301+
return ok && start_ == end_;
302+
}
303+
304+
BOOST_NETWORK_INLINE bool parse_uri_impl(boost::iterator_range<std::wstring::const_iterator> & range, uri_parts_wide_base & parts, boost::network::tags::default_wstring) {
305+
// TODO implement the grammar that supports wide strings
306+
return false; // this always fails because it's not supported yet!
307+
}
308+
309+
} /* detail */
310+
311+
} /* uri */
312+
313+
} /* network */
314+
315+
} /* boost */
316+
317+
#endif /* PARSE_URI_IMPL_AQAWWXWT */

boost/network/uri/detail/parse_uri.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <boost/network/uri/detail/uri_parts.hpp>
1010
#include <boost/network/support/is_default_string.hpp>
1111
#include <boost/range/iterator_range.hpp>
12+
#ifdef BOOST_NETWORK_NO_LIB
13+
#include <boost/network/uri/detail/impl/parse_uri.ipp>
14+
#endif
1215

1316
namespace boost { namespace network { namespace uri { namespace detail {
1417

@@ -17,8 +20,10 @@ inline bool parse_specific(uri_parts<Tag> & parts) {
1720
return true;
1821
}
1922

23+
#ifndef BOOST_NETWORK_NO_LIB
2024
extern bool parse_uri_impl(boost::iterator_range<std::string::const_iterator> & range, uri_parts_default_base & parts, tags::default_string);
2125
extern bool parse_uri_impl(boost::iterator_range<std::wstring::const_iterator> & range, uri_parts_wide_base & parts, tags::default_wstring);
26+
#endif
2227

2328
template <class Tag>
2429
struct unsupported_tag;

0 commit comments

Comments
 (0)