mirror of
https://github.com/matrix-construct/construct
synced 2024-11-17 15:30:52 +01:00
ircd::http: Improve error messages; various cleanup.
This commit is contained in:
parent
bc934abe60
commit
e48c93e42a
1 changed files with 129 additions and 230 deletions
359
ircd/http.cc
359
ircd/http.cc
|
@ -21,29 +21,6 @@
|
||||||
|
|
||||||
#include <ircd/spirit.h>
|
#include <ircd/spirit.h>
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
|
||||||
(
|
|
||||||
ircd::http::line::request,
|
|
||||||
( decltype(ircd::http::line::request::method), method )
|
|
||||||
( decltype(ircd::http::line::request::resource), resource )
|
|
||||||
( decltype(ircd::http::line::request::version), version )
|
|
||||||
)
|
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
|
||||||
(
|
|
||||||
ircd::http::line::response,
|
|
||||||
( decltype(ircd::http::line::response::version), version )
|
|
||||||
( decltype(ircd::http::line::response::status), status )
|
|
||||||
( decltype(ircd::http::line::response::reason), reason )
|
|
||||||
)
|
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
|
||||||
(
|
|
||||||
ircd::http::line::header,
|
|
||||||
( decltype(ircd::http::line::header::first), first )
|
|
||||||
( decltype(ircd::http::line::header::second), second )
|
|
||||||
)
|
|
||||||
|
|
||||||
namespace ircd {
|
namespace ircd {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
|
@ -65,206 +42,6 @@ using qi::raw;
|
||||||
using qi::attr;
|
using qi::attr;
|
||||||
using qi::eps;
|
using qi::eps;
|
||||||
|
|
||||||
template<class it,
|
|
||||||
class top = unused_type>
|
|
||||||
struct grammar
|
|
||||||
:qi::grammar<it, top>
|
|
||||||
,parse::grammar
|
|
||||||
{
|
|
||||||
template<class R = unused_type> using rule = qi::rule<it, R>;
|
|
||||||
|
|
||||||
rule<> NUL;
|
|
||||||
rule<> SP;
|
|
||||||
rule<> HT;
|
|
||||||
rule<> CR;
|
|
||||||
rule<> LF;
|
|
||||||
rule<> CRLF;
|
|
||||||
rule<> colon;
|
|
||||||
|
|
||||||
rule<> WS;
|
|
||||||
rule<> ws;
|
|
||||||
rule<string_view> token;
|
|
||||||
rule<string_view> string;
|
|
||||||
|
|
||||||
rule<string_view> line;
|
|
||||||
rule<string_view> method;
|
|
||||||
rule<string_view> resource;
|
|
||||||
rule<string_view> version;
|
|
||||||
rule<string_view> status;
|
|
||||||
rule<short> status_code;
|
|
||||||
rule<string_view> reason;
|
|
||||||
rule<http::line::request> request_line;
|
|
||||||
rule<http::line::response> response_line;
|
|
||||||
|
|
||||||
rule<string_view> key;
|
|
||||||
rule<string_view> value;
|
|
||||||
rule<http::line::header> header;
|
|
||||||
|
|
||||||
rule<unused_type> headers;
|
|
||||||
rule<unused_type> request;
|
|
||||||
rule<unused_type> response;
|
|
||||||
|
|
||||||
grammar(rule<top> &top_rule, const char *const &name);
|
|
||||||
};
|
|
||||||
|
|
||||||
[[noreturn]]
|
|
||||||
void bail()
|
|
||||||
{
|
|
||||||
throw error(code::BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class it,
|
|
||||||
class top>
|
|
||||||
grammar<it, top>::grammar(qi::rule<it, top> &top_rule,
|
|
||||||
const char *const &name)
|
|
||||||
:grammar<it, top>::base_type
|
|
||||||
{
|
|
||||||
top_rule
|
|
||||||
}
|
|
||||||
,parse::grammar
|
|
||||||
{
|
|
||||||
name
|
|
||||||
}
|
|
||||||
,NUL
|
|
||||||
{
|
|
||||||
lit('\0')
|
|
||||||
,"NUL"
|
|
||||||
}
|
|
||||||
,SP
|
|
||||||
{
|
|
||||||
lit(' ')
|
|
||||||
,"SP"
|
|
||||||
}
|
|
||||||
,HT
|
|
||||||
{
|
|
||||||
lit('\t')
|
|
||||||
,"HT"
|
|
||||||
}
|
|
||||||
,CR
|
|
||||||
{
|
|
||||||
lit('\r')
|
|
||||||
,"CR"
|
|
||||||
}
|
|
||||||
,CRLF
|
|
||||||
{
|
|
||||||
lit('\r') >> lit('\n')
|
|
||||||
,"CRLF"
|
|
||||||
}
|
|
||||||
,colon
|
|
||||||
{
|
|
||||||
lit(':')
|
|
||||||
,"colon"
|
|
||||||
}
|
|
||||||
,WS
|
|
||||||
{
|
|
||||||
(SP | HT)
|
|
||||||
,"whitespace"
|
|
||||||
}
|
|
||||||
,ws
|
|
||||||
{
|
|
||||||
+(SP | HT)
|
|
||||||
,"whitespaces"
|
|
||||||
}
|
|
||||||
,token
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF | WS))]
|
|
||||||
,"token"
|
|
||||||
}
|
|
||||||
,string
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF))]
|
|
||||||
,"string"
|
|
||||||
}
|
|
||||||
,line
|
|
||||||
{
|
|
||||||
-ws >> -string >> CRLF
|
|
||||||
,"line"
|
|
||||||
}
|
|
||||||
,method
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF | WS))]
|
|
||||||
,"method"
|
|
||||||
}
|
|
||||||
,resource
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF | WS))]
|
|
||||||
,"resource"
|
|
||||||
}
|
|
||||||
,version
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF | WS))]
|
|
||||||
,"version"
|
|
||||||
}
|
|
||||||
,status
|
|
||||||
{
|
|
||||||
raw[repeat(3)[char_("0-9")]]
|
|
||||||
,"status"
|
|
||||||
}
|
|
||||||
,status_code
|
|
||||||
{
|
|
||||||
short_
|
|
||||||
,"status code"
|
|
||||||
}
|
|
||||||
,reason
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF))]
|
|
||||||
,"status"
|
|
||||||
}
|
|
||||||
,request_line
|
|
||||||
{
|
|
||||||
method >> +SP >> resource >> +SP >> version
|
|
||||||
,"request line"
|
|
||||||
}
|
|
||||||
,response_line
|
|
||||||
{
|
|
||||||
version >> +SP >> status >> +SP >> reason
|
|
||||||
,"response line"
|
|
||||||
}
|
|
||||||
,key
|
|
||||||
{
|
|
||||||
raw[+(char_ - (NUL | CR | LF | WS | colon))]
|
|
||||||
,"key"
|
|
||||||
}
|
|
||||||
,value
|
|
||||||
{
|
|
||||||
string
|
|
||||||
,"value"
|
|
||||||
}
|
|
||||||
,header
|
|
||||||
{
|
|
||||||
key >> -ws >> colon >> -ws >> value
|
|
||||||
,"header"
|
|
||||||
}
|
|
||||||
,headers
|
|
||||||
{
|
|
||||||
+(-header % CRLF) >> CRLF
|
|
||||||
,"headers"
|
|
||||||
}
|
|
||||||
,request
|
|
||||||
{
|
|
||||||
request_line >> -ws >> CRLF >> headers
|
|
||||||
,"request"
|
|
||||||
}
|
|
||||||
,response
|
|
||||||
{
|
|
||||||
response_line >> -ws >> CRLF >> headers
|
|
||||||
,"response"
|
|
||||||
}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
struct parser
|
|
||||||
:grammar<const char *, unused_type>
|
|
||||||
{
|
|
||||||
static size_t content_length(const string_view &val);
|
|
||||||
|
|
||||||
parser(): grammar { grammar::ws, "http.request" } {}
|
|
||||||
}
|
|
||||||
const parser;
|
|
||||||
|
|
||||||
size_t printed_size(const std::initializer_list<line::header> &headers);
|
|
||||||
size_t print(char *const &buf, const size_t &max, const std::initializer_list<line::header> &headers);
|
|
||||||
|
|
||||||
std::map<code, std::string> reason
|
std::map<code, std::string> reason
|
||||||
{
|
{
|
||||||
{ code::CONTINUE, "Continue"s },
|
{ code::CONTINUE, "Continue"s },
|
||||||
|
@ -295,6 +72,122 @@ std::map<code, std::string> reason
|
||||||
} // namespace http
|
} // namespace http
|
||||||
} // namespace ircd
|
} // namespace ircd
|
||||||
|
|
||||||
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
|
(
|
||||||
|
ircd::http::line::request,
|
||||||
|
( decltype(ircd::http::line::request::method), method )
|
||||||
|
( decltype(ircd::http::line::request::resource), resource )
|
||||||
|
( decltype(ircd::http::line::request::version), version )
|
||||||
|
)
|
||||||
|
|
||||||
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
|
(
|
||||||
|
ircd::http::line::response,
|
||||||
|
( decltype(ircd::http::line::response::version), version )
|
||||||
|
( decltype(ircd::http::line::response::status), status )
|
||||||
|
( decltype(ircd::http::line::response::reason), reason )
|
||||||
|
)
|
||||||
|
|
||||||
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
|
(
|
||||||
|
ircd::http::line::header,
|
||||||
|
( decltype(ircd::http::line::header::first), first )
|
||||||
|
( decltype(ircd::http::line::header::second), second )
|
||||||
|
)
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<class it,
|
||||||
|
class top = unused_type>
|
||||||
|
struct grammar
|
||||||
|
:qi::grammar<it, top>
|
||||||
|
,parse::grammar
|
||||||
|
{
|
||||||
|
template<class R = unused_type> using rule = qi::rule<it, R>;
|
||||||
|
|
||||||
|
rule<> NUL { lit('\0') ,"nul" };
|
||||||
|
|
||||||
|
// insignificant whitespaces
|
||||||
|
rule<> SP { lit('\x20') ,"space" };
|
||||||
|
rule<> HT { lit('\x09') ,"horizontal tab" };
|
||||||
|
rule<> CR { lit('\x0D') ,"carriage return" };
|
||||||
|
rule<> LF { lit('\x0A') ,"line feed" };
|
||||||
|
|
||||||
|
// whitespace skipping
|
||||||
|
rule<> ws { SP | HT ,"whitespace" };
|
||||||
|
|
||||||
|
rule<> CRLF { lit('\r') >> lit('\n') ,"carriage return, line feed" };
|
||||||
|
rule<> colon { lit(':') ,"colon" };
|
||||||
|
|
||||||
|
rule<string_view> token { raw[+(char_ - (NUL | CR | LF | ws))] ,"token" };
|
||||||
|
rule<string_view> string { raw[+(char_ - (NUL | CR | LF))] ,"string" };
|
||||||
|
rule<string_view> line { *ws >> -string >> CRLF ,"line" };
|
||||||
|
|
||||||
|
rule<string_view> method { raw[+(char_ - (NUL | CR | LF | ws))] ,"method" };
|
||||||
|
rule<string_view> resource { raw[+(char_ - (NUL | CR | LF | ws))] ,"resource" };
|
||||||
|
rule<string_view> version { raw[+(char_ - (NUL | CR | LF | ws))] ,"version" };
|
||||||
|
|
||||||
|
rule<string_view> status { raw[repeat(3)[char_("0-9")]] ,"status" };
|
||||||
|
rule<short> status_code { short_ ,"status code" };
|
||||||
|
rule<string_view> reason { raw[+(char_ - (NUL | CR | LF))] ,"status" };
|
||||||
|
|
||||||
|
rule<string_view> key { raw[+(char_ - (NUL | CR | LF | ws | colon))] ,"key" };
|
||||||
|
rule<string_view> value { string ,"value" };
|
||||||
|
rule<line::header> header { key >> *ws >> colon >> *ws >> value ,"header" };
|
||||||
|
rule<unused_type> headers { (header % (*ws >> CRLF)) ,"headers" };
|
||||||
|
|
||||||
|
rule<line::request> request_line
|
||||||
|
{
|
||||||
|
method >> +SP >> resource >> +SP >> version
|
||||||
|
,"request line"
|
||||||
|
};
|
||||||
|
|
||||||
|
rule<line::response> response_line
|
||||||
|
{
|
||||||
|
version >> +SP >> status >> -(+SP >> reason)
|
||||||
|
,"response line"
|
||||||
|
};
|
||||||
|
|
||||||
|
rule<unused_type> request
|
||||||
|
{
|
||||||
|
request_line >> *ws >> CRLF >> -headers >> CRLF
|
||||||
|
,"request"
|
||||||
|
};
|
||||||
|
|
||||||
|
rule<unused_type> response
|
||||||
|
{
|
||||||
|
response_line >> *ws >> CRLF >> -headers >> CRLF
|
||||||
|
,"response"
|
||||||
|
};
|
||||||
|
|
||||||
|
grammar(rule<top> &top_rule, const char *const &name)
|
||||||
|
:grammar<it, top>::base_type
|
||||||
|
{
|
||||||
|
top_rule
|
||||||
|
}
|
||||||
|
,parse::grammar
|
||||||
|
{
|
||||||
|
name
|
||||||
|
}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct parser
|
||||||
|
:grammar<const char *, unused_type>
|
||||||
|
{
|
||||||
|
static size_t content_length(const string_view &val);
|
||||||
|
|
||||||
|
parser(): grammar { grammar::ws, "http.request" } {}
|
||||||
|
}
|
||||||
|
const parser;
|
||||||
|
|
||||||
|
size_t printed_size(const std::initializer_list<line::header> &headers);
|
||||||
|
size_t print(char *const &buf, const size_t &max, const std::initializer_list<line::header> &headers);
|
||||||
|
|
||||||
|
} // namespace http
|
||||||
|
} // namespace ircd
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ircd::http::print(char *const &buf,
|
ircd::http::print(char *const &buf,
|
||||||
const size_t &max,
|
const size_t &max,
|
||||||
|
@ -597,9 +490,12 @@ try
|
||||||
catch(const qi::expectation_failure<const char *> &e)
|
catch(const qi::expectation_failure<const char *> &e)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
snprintf(buf, sizeof(buf), "I require a valid %s starting at character %d.",
|
const auto rule(ircd::string(e.what_));
|
||||||
ircd::string(e.what_).data(),
|
fmt::snprintf(buf, sizeof(buf),
|
||||||
int(e.last - e.first));
|
"I require a valid HTTP %s. You sent %zu invalid characters starting with `%s'.",
|
||||||
|
between(rule, "<", ">"),
|
||||||
|
ssize_t(e.last - e.first),
|
||||||
|
string_view{e.first, e.last});
|
||||||
|
|
||||||
throw error(code::BAD_REQUEST, buf);
|
throw error(code::BAD_REQUEST, buf);
|
||||||
}
|
}
|
||||||
|
@ -608,7 +504,7 @@ ircd::http::line::response::response(const line &line)
|
||||||
{
|
{
|
||||||
static const auto grammar
|
static const auto grammar
|
||||||
{
|
{
|
||||||
parser.response_line
|
eps > parser.response_line
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *start(line.data());
|
const char *start(line.data());
|
||||||
|
@ -631,9 +527,12 @@ try
|
||||||
catch(const qi::expectation_failure<const char *> &e)
|
catch(const qi::expectation_failure<const char *> &e)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
snprintf(buf, sizeof(buf), "I require a valid %s starting at character %d.",
|
const auto rule(ircd::string(e.what_));
|
||||||
ircd::string(e.what_).data(),
|
fmt::snprintf(buf, sizeof(buf),
|
||||||
int(e.last - e.first));
|
"I require a valid HTTP %s. You sent %zu invalid characters starting with `%s'.",
|
||||||
|
between(rule, "<", ">"),
|
||||||
|
ssize_t(e.last - e.first),
|
||||||
|
string_view{e.first, e.last});
|
||||||
|
|
||||||
throw error(code::BAD_REQUEST, buf);
|
throw error(code::BAD_REQUEST, buf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue