我已经使用Boost.Spirit实现了HTTP头解析器:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/classic.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <iostream>
#include <string>
using namespace boost;
typedef std::map<std::string, std::string> header_fields_t;
struct HttpRequestHeader
{
std::string _method;
std::string _uri;
std::string _http_version;
header_fields_t _header_fields;
};
BOOST_FUSION_ADAPT_STRUCT
(
HttpRequestHeader,
(std::string, _method)
(std::string, _uri)
(std::string, _http_version)
(header_fields_t, _header_fields)
)
template <typename Iterator>
struct HttpHeaderGrammar: spirit::qi::grammar < Iterator,
HttpRequestHeader(), spirit::ascii::space_type >
{
HttpHeaderGrammar() : HttpHeaderGrammar::base_type(http_header, "HttpHeaderGrammar Grammar")
{
auto eol_rule = spirit::qi::no_skip[spirit::qi::lit('\r')] >> spirit::qi::no_skip[spirit::qi::lit('\n')];
method = spirit::qi::lexeme[+spirit::qi::alpha];
uri = spirit::qi::lexeme[+(spirit::qi::char_ - spirit::qi::space)];
http_ver = spirit::lexeme[spirit::qi::lit("HTTP/") >> +(spirit::qi::char_("0-9."))];
auto field_key = spirit::lexeme[+(spirit::qi::char_("a-zA-Z-") | spirit::qi::digit)];
auto field_value = spirit::lexeme[+(spirit::qi::char_ - '\r' - '\n')];
fields = *(field_key >> ':' >> field_value >> eol_rule);
http_header =
method >> uri >> http_ver >> eol_rule
>> fields
;
BOOST_SPIRIT_DEBUG_NODES((method)(uri)(http_ver)(fields))
}
spirit::qi::rule<Iterator, std::string(), spirit::ascii::space_type> method;
spirit::qi::rule<Iterator, std::string(), spirit::ascii::space_type> uri;
spirit::qi::rule<Iterator, std::string(), spirit::ascii::space_type> http_ver;
spirit::qi::rule<Iterator, std::map<std::string, std::string>(), spirit::ascii::space_type> fields;
spirit::qi::rule<Iterator, HttpRequestHeader(), spirit::ascii::space_type> http_header;
};
int main(int argc, char* argv[])
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Expression parser...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
typedef std::string::const_iterator iterator_type;
HttpHeaderGrammar<iterator_type> httpGrammar;
BOOST_SPIRIT_DEBUG_NODE(httpGrammar);
HttpRequestHeader httpHeader;
std::string str(
"CONNECT www.tutorialspoint.com HTTP/1.1\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n");
{
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
bool r = spirit::qi::phrase_parse(iter, end, httpGrammar, spirit::ascii::space, httpHeader);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << rest << "\"\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
最后,我遇到了两个问题:
1)在Windows上运行时,它可以正常工作并解析。在linux上运行时,解析失败。在调试时,我注意到http请求文本保持“... \\ r \\ n ...”并且看起来像Boost.Spirit错误地继续这些符号。我几乎不明白怎么修错了。
2)我没有看到任何跟踪输出。我做错了什么来制作Boost.Spirit打印跟踪输出?
-Thanks
答案 0 :(得分:3)
确实发生了一些事情:
case 0
)blank
正在征求问题)在这里: Live On Coliru
+alpha
输出:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <map>
#include <iostream>
typedef std::map<std::string, std::string> header_fields_t;
struct HttpRequestHeader
{
std::string _method;
std::string _uri;
std::string _http_version;
header_fields_t _header_fields;
};
BOOST_FUSION_ADAPT_STRUCT(HttpRequestHeader, _method, _uri, _http_version, _header_fields)
namespace qi = boost::spirit::qi;
template <typename Iterator, typename Skipper = qi::ascii::blank_type>
struct HttpHeaderGrammar: qi::grammar <Iterator, HttpRequestHeader(), Skipper> {
HttpHeaderGrammar() : HttpHeaderGrammar::base_type(http_header, "HttpHeaderGrammar Grammar") {
method = +qi::alpha;
uri = +qi::graph;
http_ver = "HTTP/" >> +qi::char_("0-9.");
field_key = +qi::char_("0-9a-zA-Z-");
field_value = +~qi::char_("\r\n");
fields = *(field_key >> ':' >> field_value >> qi::lexeme["\r\n"]);
http_header = method >> uri >> http_ver >> qi::lexeme["\r\n"] >> fields;
BOOST_SPIRIT_DEBUG_NODES((method)(uri)(http_ver)(fields)(http_header))
}
private:
qi::rule<Iterator, std::map<std::string, std::string>(), Skipper> fields;
qi::rule<Iterator, HttpRequestHeader(), Skipper> http_header;
// lexemes
qi::rule<Iterator, std::string()> method, uri, http_ver;
qi::rule<Iterator, std::string()> field_key, field_value;
};
int main()
{
typedef std::string::const_iterator It;
HttpHeaderGrammar<It> httpGrammar;
HttpRequestHeader httpHeader;
std::string str(
"CONNECT www.tutorialspoint.com HTTP/1.1\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n");
It iter = str.begin(), end = str.end();
bool r = phrase_parse(iter, end, httpGrammar, qi::ascii::blank, httpHeader);
if (r && iter == end) {
std::cout << "Parsing succeeded\n";
} else {
std::cout << "Parsing failed\n";
std::cout << "stopped at: \"" << std::string(iter, end) << "\"\n";
}
std::cout << "Bye... :-) \n\n";
}
调试信息:
Parsing succeeded
Bye... :-)