C++ c++;正则表达式:如何捕捉子匹配向量
让我们假设它是ECMAScript、c++11的regexp或boost::xpressive 输入时,我有一个字符串,格式为:C++ c++;正则表达式:如何捕捉子匹配向量,c++,regex,parsing,cookies,boost,C++,Regex,Parsing,Cookies,Boost,让我们假设它是ECMAScript、c++11的regexp或boost::xpressive 输入时,我有一个字符串,格式为:key1=value1;键2=值2;key3=value3依此类推,因此该函数的正则表达式为 ((w+)\=(w+)\;)*((\w)+\=(\w)+)\;? 我想将所有键和值放入两个std::vector 所以1,2,3,4号潜艇都有我需要的。并且存在问题-可能\1是一个数组。我没有看到任何接口,我既不能在C++中也不能得到Boo::XPixy。可能在这里,但不太明
key1=value1;键2=值2;key3=value3
依此类推,因此该函数的正则表达式为
((w+)\=(w+)\;)*((\w)+\=(\w)+)\;?
我想将所有键和值放入两个std::vector所以1,2,3,4号潜艇都有我需要的。并且存在问题-可能\1是一个数组。我没有看到任何接口,我既不能在C++中也不能得到Boo::XPixy。可能在这里,但不太明显。尽管您从未回到需求的确切本质上来,但我想向您展示一下我提出的/只是/解析
设置Cookie
响应头的方法,如§4.2.2“设置Cookie语法”中所述
注意
- 这是规范的直接翻译李>
- 我试图严格遵守规范(关于日期格式、数字格式、区分大小写等)李>
- 还要注意的是,这借鉴了Boost Spirit库的丰富经验,因此不可能每个人都以这种方式将规范转换为工作代码
- 此外,通过遵守规范,许多现实生活中的cookie将被拒绝(例如,由于
之后缺少空间)。要使其成为现实生活的证明,需要进行更多的调整(具体来说,更改skipper类型并将子解析器表达式指定为;
s)lexeme
- 最后,关键点:这只是RFC中的一个。还有其他版本,它们指定了此处未涉及的变体。在现实生活中,HTTP客户端必须借助启发式来完善cookies的解密技术。它们通常根据版本切换到完全不同的解析代码 轶事:就在今天,我追踪到我们软件中的一个bug,它被OpenJDK 6吞没了。毫无例外。你猜到了:由于不支持的功能。当然,Java 6很旧,但我们不会在下一个版本之前放弃对它的支持。所以……我们编写了更多的解析代码
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
namespace qi = boost::spirit::qi;
#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/operations.hpp>
namespace http {
class datetime {
using clock = boost::local_time::local_sec_clock;
boost::local_time::local_date_time m_dt;
public:
datetime() : m_dt(clock::local_time(boost::local_time::time_zone_ptr())) {
}
friend std::ostream& operator<<(std::ostream& os, datetime const& o) {
std::ostream imbued(os.rdbuf());
imbued.imbue(std::locale(imbued.getloc(), new boost::local_time::local_time_facet("%a, %d %b %Y %H:%M:%S GMT")));
imbued << o.m_dt;
return os;
}
friend std::istream& operator>>(std::istream& is, datetime& o) {
std::istream imbued(is.rdbuf());
imbued.imbue(std::locale(std::locale::classic(), new boost::local_time::local_time_input_facet("%a, %d %b %Y %H:%M:%S GMT")));
imbued >> o.m_dt;
return is;
}
};
}
namespace ast {
using rfc1123date = http::datetime; // rfc1123 formatting
namespace attr {
struct expires { static constexpr char const* name() { return "expires"; } };
struct max_age { static constexpr char const* name() { return "max-age"; } };
struct domain { static constexpr char const* name() { return "domain"; } };
struct path { static constexpr char const* name() { return "path"; } };
struct secure { static constexpr char const* name() { return "secure"; } };
struct httponly { static constexpr char const* name() { return "httponly"; } };
struct extension { static constexpr char const* name() { return "extension"; } };
}
template <typename tag, typename V = std::string>
struct attribute {
V value;
attribute(V value = {}) : value(std::move(value)) {}
friend std::ostream& operator<<(std::ostream& os, attribute const& attr) {
return os << "[ " << tag::name() << "=" << attr.value << " ]";
}
};
template <typename tag>
struct attribute<tag, void> {
//attribute(bool = true) {};
friend std::ostream& operator<<(std::ostream& os, attribute const&) {
return os << "[ attribute: present ]";
}
};
using expires_av = attribute<attr::expires, rfc1123date>;
using max_age_av = attribute<attr::max_age, int>;
using domain_av = attribute<attr::domain>;
using path_av = attribute<attr::path>;
using secure_av = attribute<attr::secure, void>;
using httponly_av = attribute<attr::httponly, void>;
using extension_av = attribute<attr::extension>;
using cookie_av = boost::variant<
expires_av,
max_age_av,
domain_av,
path_av,
secure_av,
httponly_av,
extension_av
>;
struct cookie_pair {
std::string name, value;
};
struct cookie {
cookie_pair pair;
std::list<cookie_av> attributes;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::cookie_pair,
(std::string, name)
(std::string, value)
)
BOOST_FUSION_ADAPT_STRUCT(ast::cookie,
(ast::cookie_pair, pair)
(std::list<ast::cookie_av>, attributes)
)
namespace ast {
static inline std::ostream& operator<<(std::ostream& os, std::list<cookie_av> const&v) {
os << "{";
std::copy(v.begin(), v.end(), std::ostream_iterator<cookie_av>(os, "; "));
return os << "}";
}
static inline std::ostream& operator<<(std::ostream& os, cookie_pair const&v) { return os << boost::fusion::as_vector(v); }
static inline std::ostream& operator<<(std::ostream& os, cookie const&v) { return os << boost::fusion::as_vector(v); }
}
template <typename It>
struct set_cookie : qi::grammar<It, ast::cookie()> {
set_cookie() : set_cookie::base_type(start) {
using namespace qi;
using boost::proto::deep_copy;
/////////////////////////////////////////////////////////////////
// RFC2616 2.2 token
#define RFC_CTLs "\x01-\x1f\x7f"
constexpr char DQUOTE = '"';
token = +(~char_(RFC_CTLs /*separators:*/ "()<>@,;:\\\"/[]?={} \t") - '\0');
/////////////////////////////////////////////////////////////////
// RFC6265 4.1.1. Syntax (set-cookie)
set_cookie_header = no_case["set-cookie: "] >> set_cookie_string;
set_cookie_string = cookie_pair >> *("; " >> cookie_av);
cookie_pair = cookie_name >> '=' >> cookie_value;
cookie_name = token;
auto cookie_octet = deep_copy(char_("\x21" "\x23-\x2B" "\x2D-\x3A" "\x3C-\x5B" "\x5D-\x7E"));
cookie_value = *cookie_octet | (DQUOTE >> *cookie_octet >> DQUOTE);
// ; US-ASCII characters excluding CTLs,
// ; whitespace DQUOTE, comma, semicolon,
// ; and backslash
cookie_av = expires_av
| max_age_av
| domain_av
| path_av
| secure_av
| httponly_av
| extension_av
;
expires_av = no_case["expires="] >> sane_cookie_date;
sane_cookie_date = stream; // TODO <rfc1123_date, defined in [RFC2616], Section 3.3.1>
max_age_av = no_case["max-age="] >> !char_('0') >> uint_;
// ; In practice, both expires_av and max_age_av
// ; are limited to dates representable by the
// ; user agent.
// non_zero_digit = %x31-39
// ; digits 1 through 9
domain_av = no_case["domain="] >> domain_value;
domain_value = raw [ (alpha >> *(alpha|digit|'-')) % '.'];
// ; defined in [RFC1034], Section 3.5, as
// ; enhanced by [RFC1123], Section 2.1
path_av = no_case["path="] >> path_value;
path_value = *(~char_(RFC_CTLs ";") - '\0'); // <any CHAR except CTLs or ";">
secure_av = no_case["secure"] >> attr(ast::secure_av{});
httponly_av = no_case["httponly"] >> attr(ast::httponly_av{});
extension_av = as_string [*(~char_(RFC_CTLs ";") - '\0')]; // <any CHAR except CTLs or ";">
start = set_cookie_header;
BOOST_SPIRIT_DEBUG_NODES(
(start)
(set_cookie_header) (set_cookie_string)
(cookie_pair) (cookie_name) (cookie_value) (token)
(cookie_av)
(expires_av) (sane_cookie_date)
(max_age_av)
(domain_av) (domain_value)
(path_av) (path_value)
(secure_av)
(httponly_av)
(extension_av)
);
#undef RFC_CTLs
}
private:
qi::rule<It, ast::cookie()> start;
qi::rule<It, std::string()> token, cookie_name, cookie_value, domain_value, path_value;
qi::rule<It, ast::cookie()> set_cookie_header, set_cookie_string;
qi::rule<It, ast::cookie_pair()> cookie_pair;
qi::rule<It, ast::cookie_av()> cookie_av;
qi::rule<It, ast::expires_av()> expires_av;
qi::rule<It, ast::rfc1123date()> sane_cookie_date;
qi::rule<It, ast::max_age_av()> max_age_av; // non_zero_digit;
qi::rule<It, ast::domain_av()> domain_av;
qi::rule<It, ast::path_av()> path_av;
qi::rule<It, ast::secure_av()> secure_av;
qi::rule<It, ast::httponly_av()> httponly_av;
qi::rule<It, ast::extension_av()> extension_av;
};
int main() {
using It = std::string::const_iterator;
for (std::string const s : {
"Set-Cookie: name=value",
"Set-Cookie: name=value; Path=/; Domain=domain.com",
"set-cookie: name=value; path=/; domain=domain.com",
//// not actually rfc 6265 conformant:
//"Set-Cookie: name=value;path=/;domain=domain.com",
// actually a wednesday:
"Set-Cookie: name=value; path=/; domain=.mydomain.com; expires=Thu, 01-Jan-2070 00:00:10 GMT; comment=no_comment"
})
{
It f = s.begin(), l = s.end();
std::cout << "Parsing '" << s << "'\n";
ast::cookie cookie;
bool ok = qi::parse(f,l,set_cookie<It>(),cookie);
if (ok) {
std::cout << " -- Parse success: " << cookie << "\n";
}
else
std::cout << " -- Parse failure\n";
if (f!=l)
std::cout << " -- Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/optional/optional_io.hpp>
namespace qi = boost::spirit::qi;
#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/operations.hpp>
namespace http {
class datetime {
using clock = boost::local_time::local_sec_clock;
boost::local_time::local_date_time m_dt;
public:
datetime() : m_dt(clock::local_time(boost::local_time::time_zone_ptr())) {
}
friend std::ostream& operator<<(std::ostream& os, datetime const& o) {
std::ostream imbued(os.rdbuf());
imbued.imbue(std::locale(imbued.getloc(), new boost::local_time::local_time_facet("%a, %d %b %Y %H:%M:%S GMT")));
imbued << o.m_dt;
return os;
}
friend std::istream& operator>>(std::istream& is, datetime& o) {
std::istream imbued(is.rdbuf());
imbued.imbue(std::locale(std::locale::classic(), new boost::local_time::local_time_input_facet("%a, %d %b %Y %H:%M:%S GMT")));
imbued >> o.m_dt;
return is;
}
};
}
namespace ast {
using boost::optional;
using rfc1123date = http::datetime; // rfc1123 formatting
struct expires_av {
rfc1123date date;
expires_av(rfc1123date date = {}) : date(date) {}
friend std::ostream& operator<<(std::ostream& os, expires_av const& attr) {
return os << "[ expires_av: " << attr.date << " ]";
}
};
struct max_age_av {
unsigned age;
max_age_av(unsigned age = {}) : age(age) {}
friend std::ostream& operator<<(std::ostream& os, max_age_av const& attr) {
return os << "[ max_age_av: " << attr.age << " ]";
}
};
struct string_attribute {
std::string value;
string_attribute(std::string value = "") : value(std::move(value)) {}
friend std::ostream& operator<<(std::ostream& os, string_attribute const& attr) {
return os << "[ string_attribute: " << attr.value << " ]";
}
};
using domain_av = string_attribute;
using path_av = string_attribute;
using extension_av = string_attribute;
struct cookie_av {
optional<expires_av> expires;
optional<max_age_av> max_age;
optional<domain_av> domain;
optional<path_av> path;
bool secure = false;
bool httponly = false;
optional<extension_av> extension;
};
struct cookie_pair {
std::string name, value;
};
struct cookie {
cookie_pair pair;
cookie_av attributes;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::cookie_av,
(optional<ast::expires_av>,expires)
(optional<ast::max_age_av>,max_age)
(optional<ast::domain_av>,domain)
(optional<ast::path_av>,path)
(bool,secure)
(bool,httponly)
(optional<ast::extension_av>,extension)
)
BOOST_FUSION_ADAPT_STRUCT(ast::cookie_pair,
(std::string, name)
(std::string, value)
)
BOOST_FUSION_ADAPT_STRUCT(ast::cookie,
(ast::cookie_pair, pair)
(ast::cookie_av, attributes)
)
namespace ast {
static inline std::ostream& operator<<(std::ostream& os, cookie_av const&v) { return os << boost::fusion::as_vector(v); }
static inline std::ostream& operator<<(std::ostream& os, cookie_pair const&v) { return os << boost::fusion::as_vector(v); }
static inline std::ostream& operator<<(std::ostream& os, cookie const&v) { return os << boost::fusion::as_vector(v); }
}
template <typename It>
struct set_cookie : qi::grammar<It, ast::cookie()> {
set_cookie() : set_cookie::base_type(start) {
using namespace qi;
using boost::proto::deep_copy;
/////////////////////////////////////////////////////////////////
// RFC2616 2.2 token
#define RFC_CTLs "\x01-\x1f\x7f"
constexpr char DQUOTE = '"';
token = +(~char_(RFC_CTLs /*separators:*/ "()<>@,;:\\\"/[]?={} \t") - '\0');
/////////////////////////////////////////////////////////////////
// RFC6265 4.1.1. Syntax (set-cookie)
set_cookie_header = no_case["set-cookie: "] >> set_cookie_string;
set_cookie_string = cookie_pair >> -attributes;
cookie_pair = cookie_name >> '=' >> cookie_value;
cookie_name = token;
auto cookie_octet = deep_copy(char_("\x21" "\x23-\x2B" "\x2D-\x3A" "\x3C-\x5B" "\x5D-\x7E"));
cookie_value = *cookie_octet | (DQUOTE >> *cookie_octet >> DQUOTE);
// ; US-ASCII characters excluding CTLs,
// ; whitespace DQUOTE, comma, semicolon,
// ; and backslash
attributes = ("; " >> expires_av)
^ ("; " >> max_age_av)
^ ("; " >> domain_av)
^ ("; " >> path_av)
^ ("; " >> secure_av)
^ ("; " >> httponly_av)
^ ("; " >> extension_av)
;
expires_av = no_case["expires="] >> sane_cookie_date;
sane_cookie_date = stream; // TODO <rfc1123_date, defined in [RFC2616], Section 3.3.1>
max_age_av = no_case["max-age="] >> !char_('0') >> uint_;
// ; In practice, both expires_av and max_age_av
// ; are limited to dates representable by the
// ; user agent.
// non_zero_digit = %x31-39
// ; digits 1 through 9
domain_av = no_case["domain="] >> domain_value;
domain_value = raw [ (alpha >> *(alpha|digit|'-')) % '.'];
// ; defined in [RFC1034], Section 3.5, as
// ; enhanced by [RFC1123], Section 2.1
path_av = no_case["path="] >> path_value;
path_value = *(~char_(RFC_CTLs ";") - '\0'); // <any CHAR except CTLs or ";">
secure_av = no_case["secure"] >> attr(true);
httponly_av = no_case["httponly"] >> attr(true);
extension_av = as_string [*(~char_(RFC_CTLs ";") - '\0')]; // <any CHAR except CTLs or ";">
start = set_cookie_header;
BOOST_SPIRIT_DEBUG_NODES(
(start)
(set_cookie_header) (set_cookie_string)
(cookie_pair) (cookie_name) (cookie_value) (token)
(attributes)
(expires_av) (sane_cookie_date)
(max_age_av)
(domain_av) (domain_value)
(path_av) (path_value)
(secure_av)
(httponly_av)
(extension_av)
);
#undef RFC_CTLs
}
private:
qi::rule<It, ast::cookie()> start;
qi::rule<It, std::string()> token, cookie_name, cookie_value, domain_value, path_value;
qi::rule<It, ast::cookie()> set_cookie_header, set_cookie_string;
qi::rule<It, ast::cookie_pair()> cookie_pair;
qi::rule<It, ast::cookie_av()> attributes;
qi::rule<It, ast::expires_av()> expires_av;
qi::rule<It, ast::rfc1123date()> sane_cookie_date;
qi::rule<It, ast::max_age_av()> max_age_av; // non_zero_digit;
qi::rule<It, ast::domain_av()> domain_av;
qi::rule<It, ast::path_av()> path_av;
qi::rule<It, bool()> secure_av, httponly_av;
qi::rule<It, ast::extension_av()> extension_av;
};
int main() {
using It = std::string::const_iterator;
for (std::string const s : {
"Set-Cookie: name=value",
"Set-Cookie: name=value; Path=/; Domain=domain.com",
"set-cookie: name=value; path=/; domain=domain.com",
//// not actually rfc 6265 conformant:
//"Set-Cookie: name=value;path=/;domain=domain.com",
// actually a wednesday:
"Set-Cookie: name=value; path=/; domain=.mydomain.com; expires=Thu, 01-Jan-2070 00:00:10 GMT; comment=no_comment"
})
{
It f = s.begin(), l = s.end();
std::cout << "Parsing '" << s << "'\n";
ast::cookie cookie;
bool ok = qi::parse(f,l,set_cookie<It>(),cookie);
if (ok) {
std::cout << " -- Parse success: " << cookie << "\n";
}
else
std::cout << " -- Parse failure\n";
if (f!=l)
std::cout << " -- Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
/#定义BOOST_SPIRIT_调试
#包括
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
#包括
#包括
#包括
#包括
命名空间http{
类日期时间{
使用clock=boost::local_time::local_secu_时钟;
boost::local_time::local_date_time m_dt;
公众:
datetime():m_dt(时钟::本地时间(boost::本地时间::时区ptr()){
}
friend std::ostream&operator>o.m_dt;
回报是;
}
};
}
名称空间ast{
使用boost::可选;
使用rfc1123date=http::datetime;//rfc1123格式
struct\u av{
RFC1123日期;
expires_av(rfc1123date={}):date(date){}
friend std::奥斯特雷姆和运营商你确定没有键包含=
,没有值包含;
,没有不属于键/值的空白,等等吗?否则,一切都会变得更复杂。b)为什么要使用正则表达式?虽然它的代码可能略短一些,但要找到第一个=
,调用substr,对;
,以及大范围内的所有内容都一样循环是你看过一个吗?是的,当然我肯定:)我只是试着不让社区超负荷使用非常复杂的reg-exp。我试着解析Set Cookie:http头。当然我可以使用令牌迭代器,但这样我最终会编写RL降序解析器。我一直希望保持懒惰,让库为我工作。我肯定会使用提升工作精神你确定你在分析吗?这看起来更接近。饼干很容易被低估。。。
using domain_av = string_attribute;
using path_av = string_attribute;
using extension_av = string_attribute;
struct cookie_av {
optional<expires_av> expires;
optional<max_age_av> max_age;
optional<domain_av> domain;
optional<path_av> path;
bool secure = false;
bool httponly = false;
optional<extension_av> extension;
};
struct cookie_pair {
std::string name, value;
};
struct cookie {
cookie_pair pair;
cookie_av attributes;
};
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/optional/optional_io.hpp>
namespace qi = boost::spirit::qi;
#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/operations.hpp>
namespace http {
class datetime {
using clock = boost::local_time::local_sec_clock;
boost::local_time::local_date_time m_dt;
public:
datetime() : m_dt(clock::local_time(boost::local_time::time_zone_ptr())) {
}
friend std::ostream& operator<<(std::ostream& os, datetime const& o) {
std::ostream imbued(os.rdbuf());
imbued.imbue(std::locale(imbued.getloc(), new boost::local_time::local_time_facet("%a, %d %b %Y %H:%M:%S GMT")));
imbued << o.m_dt;
return os;
}
friend std::istream& operator>>(std::istream& is, datetime& o) {
std::istream imbued(is.rdbuf());
imbued.imbue(std::locale(std::locale::classic(), new boost::local_time::local_time_input_facet("%a, %d %b %Y %H:%M:%S GMT")));
imbued >> o.m_dt;
return is;
}
};
}
namespace ast {
using boost::optional;
using rfc1123date = http::datetime; // rfc1123 formatting
struct expires_av {
rfc1123date date;
expires_av(rfc1123date date = {}) : date(date) {}
friend std::ostream& operator<<(std::ostream& os, expires_av const& attr) {
return os << "[ expires_av: " << attr.date << " ]";
}
};
struct max_age_av {
unsigned age;
max_age_av(unsigned age = {}) : age(age) {}
friend std::ostream& operator<<(std::ostream& os, max_age_av const& attr) {
return os << "[ max_age_av: " << attr.age << " ]";
}
};
struct string_attribute {
std::string value;
string_attribute(std::string value = "") : value(std::move(value)) {}
friend std::ostream& operator<<(std::ostream& os, string_attribute const& attr) {
return os << "[ string_attribute: " << attr.value << " ]";
}
};
using domain_av = string_attribute;
using path_av = string_attribute;
using extension_av = string_attribute;
struct cookie_av {
optional<expires_av> expires;
optional<max_age_av> max_age;
optional<domain_av> domain;
optional<path_av> path;
bool secure = false;
bool httponly = false;
optional<extension_av> extension;
};
struct cookie_pair {
std::string name, value;
};
struct cookie {
cookie_pair pair;
cookie_av attributes;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::cookie_av,
(optional<ast::expires_av>,expires)
(optional<ast::max_age_av>,max_age)
(optional<ast::domain_av>,domain)
(optional<ast::path_av>,path)
(bool,secure)
(bool,httponly)
(optional<ast::extension_av>,extension)
)
BOOST_FUSION_ADAPT_STRUCT(ast::cookie_pair,
(std::string, name)
(std::string, value)
)
BOOST_FUSION_ADAPT_STRUCT(ast::cookie,
(ast::cookie_pair, pair)
(ast::cookie_av, attributes)
)
namespace ast {
static inline std::ostream& operator<<(std::ostream& os, cookie_av const&v) { return os << boost::fusion::as_vector(v); }
static inline std::ostream& operator<<(std::ostream& os, cookie_pair const&v) { return os << boost::fusion::as_vector(v); }
static inline std::ostream& operator<<(std::ostream& os, cookie const&v) { return os << boost::fusion::as_vector(v); }
}
template <typename It>
struct set_cookie : qi::grammar<It, ast::cookie()> {
set_cookie() : set_cookie::base_type(start) {
using namespace qi;
using boost::proto::deep_copy;
/////////////////////////////////////////////////////////////////
// RFC2616 2.2 token
#define RFC_CTLs "\x01-\x1f\x7f"
constexpr char DQUOTE = '"';
token = +(~char_(RFC_CTLs /*separators:*/ "()<>@,;:\\\"/[]?={} \t") - '\0');
/////////////////////////////////////////////////////////////////
// RFC6265 4.1.1. Syntax (set-cookie)
set_cookie_header = no_case["set-cookie: "] >> set_cookie_string;
set_cookie_string = cookie_pair >> -attributes;
cookie_pair = cookie_name >> '=' >> cookie_value;
cookie_name = token;
auto cookie_octet = deep_copy(char_("\x21" "\x23-\x2B" "\x2D-\x3A" "\x3C-\x5B" "\x5D-\x7E"));
cookie_value = *cookie_octet | (DQUOTE >> *cookie_octet >> DQUOTE);
// ; US-ASCII characters excluding CTLs,
// ; whitespace DQUOTE, comma, semicolon,
// ; and backslash
attributes = ("; " >> expires_av)
^ ("; " >> max_age_av)
^ ("; " >> domain_av)
^ ("; " >> path_av)
^ ("; " >> secure_av)
^ ("; " >> httponly_av)
^ ("; " >> extension_av)
;
expires_av = no_case["expires="] >> sane_cookie_date;
sane_cookie_date = stream; // TODO <rfc1123_date, defined in [RFC2616], Section 3.3.1>
max_age_av = no_case["max-age="] >> !char_('0') >> uint_;
// ; In practice, both expires_av and max_age_av
// ; are limited to dates representable by the
// ; user agent.
// non_zero_digit = %x31-39
// ; digits 1 through 9
domain_av = no_case["domain="] >> domain_value;
domain_value = raw [ (alpha >> *(alpha|digit|'-')) % '.'];
// ; defined in [RFC1034], Section 3.5, as
// ; enhanced by [RFC1123], Section 2.1
path_av = no_case["path="] >> path_value;
path_value = *(~char_(RFC_CTLs ";") - '\0'); // <any CHAR except CTLs or ";">
secure_av = no_case["secure"] >> attr(true);
httponly_av = no_case["httponly"] >> attr(true);
extension_av = as_string [*(~char_(RFC_CTLs ";") - '\0')]; // <any CHAR except CTLs or ";">
start = set_cookie_header;
BOOST_SPIRIT_DEBUG_NODES(
(start)
(set_cookie_header) (set_cookie_string)
(cookie_pair) (cookie_name) (cookie_value) (token)
(attributes)
(expires_av) (sane_cookie_date)
(max_age_av)
(domain_av) (domain_value)
(path_av) (path_value)
(secure_av)
(httponly_av)
(extension_av)
);
#undef RFC_CTLs
}
private:
qi::rule<It, ast::cookie()> start;
qi::rule<It, std::string()> token, cookie_name, cookie_value, domain_value, path_value;
qi::rule<It, ast::cookie()> set_cookie_header, set_cookie_string;
qi::rule<It, ast::cookie_pair()> cookie_pair;
qi::rule<It, ast::cookie_av()> attributes;
qi::rule<It, ast::expires_av()> expires_av;
qi::rule<It, ast::rfc1123date()> sane_cookie_date;
qi::rule<It, ast::max_age_av()> max_age_av; // non_zero_digit;
qi::rule<It, ast::domain_av()> domain_av;
qi::rule<It, ast::path_av()> path_av;
qi::rule<It, bool()> secure_av, httponly_av;
qi::rule<It, ast::extension_av()> extension_av;
};
int main() {
using It = std::string::const_iterator;
for (std::string const s : {
"Set-Cookie: name=value",
"Set-Cookie: name=value; Path=/; Domain=domain.com",
"set-cookie: name=value; path=/; domain=domain.com",
//// not actually rfc 6265 conformant:
//"Set-Cookie: name=value;path=/;domain=domain.com",
// actually a wednesday:
"Set-Cookie: name=value; path=/; domain=.mydomain.com; expires=Thu, 01-Jan-2070 00:00:10 GMT; comment=no_comment"
})
{
It f = s.begin(), l = s.end();
std::cout << "Parsing '" << s << "'\n";
ast::cookie cookie;
bool ok = qi::parse(f,l,set_cookie<It>(),cookie);
if (ok) {
std::cout << " -- Parse success: " << cookie << "\n";
}
else
std::cout << " -- Parse failure\n";
if (f!=l)
std::cout << " -- Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}