// Copyright Dean Michael Berris 2007.
// Copyright Michael Dickey 2008.
// Copyright Kim Grasman 2008.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef __NETWORK_UTILS_URI_20080916_HPP__
#define __NETWORK_UTILS_URI_20080916_HPP__
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
#include <boost/fusion/sequence/intrinsic/value_at_key.hpp>
#include <boost/spirit.hpp>
#include <boost/spirit/phoenix.hpp>
// include message declaration
#include "boost/network/uri_fwd.hpp"
namespace boost { namespace network {
/** uri.hpp
*
* This file implements the basic request object required
* by the HTTP client implementation. The uri
* object encapsulates a URI which is parsed at runtime.
* The data is broken up according to the URI specifications
* RFC 3986 -- http://www.ietf.org/rfc/rfc3986.txt -- using
* Fusion, and exposed as a typed struct.
*/
template <
class Tags
>
class basic_uri {
typedef Tags tags;
typedef fusion::map<
fusion::pair<typename tags::scheme, std::string>,
fusion::pair<typename tags::host, std::string>,
fusion::pair<typename tags::port, unsigned int>,
fusion::pair<typename tags::path, std::string>,
fusion::pair<typename tags::query, std::string>,
fusion::pair<typename tags::fragment, std::string>
> uri_parts_type;
uri_parts_type uri_parts;
public:
basic_uri() {
}
explicit basic_uri(std::string const & uri_) {
parse(uri_, uri_parts);
}
bool valid() const {
return (!scheme().empty() && !host().empty());
}
std::string const& scheme() const {
return fusion::at_key<typename tags::scheme>(uri_parts);
}
std::string& scheme() {
return fusion::at_key<typename tags::scheme>(uri_parts);
}
std::string const& host() const {
return fusion::at_key<typename tags::host>(uri_parts);
}
std::string& host() {
return fusion::at_key<typename tags::host>(uri_parts);
}
unsigned int& port() {
return fusion::at_key<typename tags::port>(uri_parts);
}
unsigned int port() const {
return fusion::at_key<typename tags::port>(uri_parts);
}
std::string& path() {
return fusion::at_key<typename tags::path>(uri_parts);
}
std::string const& path() const {
return fusion::at_key<typename tags::path>(uri_parts);
}
std::string& query() {
return fusion::at_key<typename tags::query>(uri_parts);
}
std::string const& query() const {
return fusion::at_key<typename tags::query>(uri_parts);
}
std::string& fragment() {
return fusion::at_key<typename tags::fragment>(uri_parts);
}
std::string const& fragment() const {
return fusion::at_key<typename tags::fragment>(uri_parts);
}
bool operator==(basic_uri const& other) const {
return (scheme() == other.scheme() &&
host() == other.host() &&
port() == other.port() &&
path() == other.path() &&
query() == other.query() &&
fragment() == other.fragment());
}
std::string str() const {
if (!valid())
return std::string();
std::ostringstream builder;
builder << scheme() << "://";
builder << host();
if (port() != 0)
builder << ":" << port();
builder << path();
if (!query().empty())
builder << "?" << query();
if (!fragment().empty())
builder << "#" << fragment();
return builder.str();
}
private:
static void parse(std::string const& uri_, uri_parts_type& parts) {
using namespace boost::spirit;
using namespace phoenix;
boost::spirit::parse(
uri_.begin(), uri_.end(),
// the parser
(
(+alnum_p) [
var(fusion::at_key<typename tags::scheme>(parts))
= construct_<std::string>(arg1, arg2)
]
>> str_p("://")
)
>>
(+(alnum_p | '.' | '-' | '_')) [
var(fusion::at_key<typename tags::host>(parts))
= construct_<std::string>(arg1, arg2)
]
>>
!(
ch_p(':')
>>
uint_p [
var(fusion::at_key<typename tags::port>(parts))
= arg1
]
>> !ch_p('/')
)
>>
(+(alnum_p | '/' | '%' | '_' | '-' | '.')) [
var(fusion::at_key<typename tags::path>(parts))
= construct_<std::string>(arg1, arg2)
]
>>
!(
ch_p('?')
>>
(+(alnum_p | '&' | '=' | '%' | '_' )) [
var(fusion::at_key<typename tags::query>(parts))
= construct_<std::string>(arg1, arg2)
]
)
>> !(ch_p('#')
>>
(+(alnum_p | '_' | '%' | '-')) [
var(fusion::at_key<typename tags::fragment>(parts))
= construct_<std::string>(arg1, arg2)
]
)
>>
end_p
, nothing_p // no skip parser
);
normalize_path(parts);
}
static void normalize_path(uri_parts_type& parts) {
std::string &path = fusion::at_key<typename tags::path>(parts);
if (path.empty() || path[0] != '/')
path = "/" + path;
}
};
// typedef basic_uri<default_tags> uri;
} // namespace network
} // namespace boost
#endif // __NETWORK_UTILS_URI_20080916_HPP__