forked from boostorg/beast
Make value optional in param-list
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
1.0.0-b16
|
||||||
|
|
||||||
|
* Make value optional in param-list
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
1.0.0-b15
|
1.0.0-b15
|
||||||
|
|
||||||
* rfc7230 section 3.3.2 compliance
|
* rfc7230 section 3.3.2 compliance
|
||||||
|
@@ -233,6 +233,14 @@ skip_ows(FwdIt& it, FwdIt const& end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class FwdIt>
|
||||||
|
void
|
||||||
|
skip_token(FwdIt& it, FwdIt const& last)
|
||||||
|
{
|
||||||
|
while(it != last && is_tchar(*it))
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
boost::string_ref
|
boost::string_ref
|
||||||
trim(boost::string_ref const& s)
|
trim(boost::string_ref const& s)
|
||||||
@@ -258,14 +266,14 @@ struct param_iter
|
|||||||
using iter_type = boost::string_ref::const_iterator;
|
using iter_type = boost::string_ref::const_iterator;
|
||||||
|
|
||||||
iter_type it;
|
iter_type it;
|
||||||
iter_type begin;
|
iter_type first;
|
||||||
iter_type end;
|
iter_type last;
|
||||||
std::pair<boost::string_ref, boost::string_ref> v;
|
std::pair<boost::string_ref, boost::string_ref> v;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
empty() const
|
empty() const
|
||||||
{
|
{
|
||||||
return begin == it;
|
return first == it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
template<class = void>
|
||||||
@@ -279,59 +287,48 @@ param_iter::
|
|||||||
increment()
|
increment()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
param-list = *( OWS ";" OWS param )
|
||||||
ext = token param-list
|
param = token OWS [ "=" OWS ( token / quoted-string ) ]
|
||||||
param-list = *( OWS ";" OWS param )
|
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
||||||
param = token OWS "=" OWS ( token / quoted-string )
|
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
||||||
|
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||||
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
obs-text = %x80-FF
|
||||||
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
|
||||||
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
||||||
obs-text = %x80-FF
|
|
||||||
|
|
||||||
Example:
|
|
||||||
chunked;a=b;i=j,gzip;windowBits=12
|
|
||||||
x,y
|
|
||||||
*/
|
*/
|
||||||
auto const err =
|
auto const err =
|
||||||
[&]
|
[&]
|
||||||
{
|
{
|
||||||
it = begin;
|
it = first;
|
||||||
};
|
};
|
||||||
v.first.clear();
|
v.first.clear();
|
||||||
v.second.clear();
|
v.second.clear();
|
||||||
detail::skip_ows(it, end);
|
detail::skip_ows(it, last);
|
||||||
begin = it;
|
first = it;
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
if(*it != ';')
|
if(*it != ';')
|
||||||
return err();
|
return err();
|
||||||
++it;
|
++it;
|
||||||
detail::skip_ows(it, end);
|
detail::skip_ows(it, last);
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
// param
|
// param
|
||||||
if(! detail::is_tchar(*it))
|
if(! detail::is_tchar(*it))
|
||||||
return err();
|
return err();
|
||||||
auto const p0 = it;
|
auto const p0 = it;
|
||||||
for(;;)
|
skip_token(++it, last);
|
||||||
{
|
|
||||||
++it;
|
|
||||||
if(it == end)
|
|
||||||
return err();
|
|
||||||
if(! detail::is_tchar(*it))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto const p1 = it;
|
auto const p1 = it;
|
||||||
detail::skip_ows(it, end);
|
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
||||||
if(it == end)
|
detail::skip_ows(it, last);
|
||||||
return err();
|
if(it == last)
|
||||||
|
return;
|
||||||
|
if(*it == ';')
|
||||||
|
return;
|
||||||
if(*it != '=')
|
if(*it != '=')
|
||||||
return err();
|
return err();
|
||||||
++it;
|
++it;
|
||||||
detail::skip_ows(it, end);
|
detail::skip_ows(it, last);
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return;
|
||||||
if(*it == '"')
|
if(*it == '"')
|
||||||
{
|
{
|
||||||
// quoted-string
|
// quoted-string
|
||||||
@@ -339,7 +336,7 @@ increment()
|
|||||||
++it;
|
++it;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
auto c = *it++;
|
auto c = *it++;
|
||||||
if(c == '"')
|
if(c == '"')
|
||||||
@@ -348,13 +345,12 @@ increment()
|
|||||||
continue;
|
continue;
|
||||||
if(c != '\\')
|
if(c != '\\')
|
||||||
return err();
|
return err();
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
c = *it++;
|
c = *it++;
|
||||||
if(! detail::is_qpchar(c))
|
if(! detail::is_qpchar(c))
|
||||||
return err();
|
return err();
|
||||||
}
|
}
|
||||||
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
|
||||||
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -363,15 +359,7 @@ increment()
|
|||||||
if(! detail::is_tchar(*it))
|
if(! detail::is_tchar(*it))
|
||||||
return err();
|
return err();
|
||||||
auto const p2 = it;
|
auto const p2 = it;
|
||||||
for(;;)
|
skip_token(++it, last);
|
||||||
{
|
|
||||||
it++;
|
|
||||||
if(it == end)
|
|
||||||
break;
|
|
||||||
if(! detail::is_tchar(*it))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
|
||||||
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,8 +36,8 @@ public:
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
other.pi_.it == pi_.it &&
|
other.pi_.it == pi_.it &&
|
||||||
other.pi_.end == pi_.end &&
|
other.pi_.last == pi_.last &&
|
||||||
other.pi_.begin == pi_.begin;
|
other.pi_.first == pi_.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -76,11 +76,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class param_list;
|
friend class param_list;
|
||||||
|
|
||||||
const_iterator(iter_type begin, iter_type end)
|
const_iterator(iter_type first, iter_type last)
|
||||||
{
|
{
|
||||||
pi_.it = begin;
|
pi_.it = first;
|
||||||
pi_.begin = begin;
|
pi_.first = first;
|
||||||
pi_.end = end;
|
pi_.last = last;
|
||||||
increment();
|
increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,10 +158,11 @@ increment()
|
|||||||
pi_.increment();
|
pi_.increment();
|
||||||
if(pi_.empty())
|
if(pi_.empty())
|
||||||
{
|
{
|
||||||
pi_.it = pi_.end;
|
pi_.it = pi_.last;
|
||||||
pi_.begin = pi_.end;
|
pi_.first = pi_.last;
|
||||||
}
|
}
|
||||||
else if(pi_.v.second.front() == '"')
|
else if(! pi_.v.second.empty() &&
|
||||||
|
pi_.v.second.front() == '"')
|
||||||
{
|
{
|
||||||
s_ = unquote(pi_.v.second);
|
s_ = unquote(pi_.v.second);
|
||||||
pi_.v.second = boost::string_ref{
|
pi_.v.second = boost::string_ref{
|
||||||
@@ -175,8 +176,8 @@ class ext_list::const_iterator
|
|||||||
{
|
{
|
||||||
ext_list::value_type v_;
|
ext_list::value_type v_;
|
||||||
iter_type it_;
|
iter_type it_;
|
||||||
iter_type begin_;
|
iter_type first_;
|
||||||
iter_type end_;
|
iter_type last_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = ext_list::value_type;
|
using value_type = ext_list::value_type;
|
||||||
@@ -192,8 +193,8 @@ public:
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
other.it_ == it_ &&
|
other.it_ == it_ &&
|
||||||
other.begin_ == begin_ &&
|
other.first_ == first_ &&
|
||||||
other.end_ == end_;
|
other.last_ == last_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -235,8 +236,8 @@ private:
|
|||||||
const_iterator(iter_type begin, iter_type end)
|
const_iterator(iter_type begin, iter_type end)
|
||||||
{
|
{
|
||||||
it_ = begin;
|
it_ = begin;
|
||||||
begin_ = begin;
|
first_ = begin;
|
||||||
end_ = end;
|
last_ = end;
|
||||||
increment();
|
increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,16 +321,16 @@ increment()
|
|||||||
auto const err =
|
auto const err =
|
||||||
[&]
|
[&]
|
||||||
{
|
{
|
||||||
it_ = end_;
|
it_ = last_;
|
||||||
begin_ = end_;
|
first_ = last_;
|
||||||
};
|
};
|
||||||
auto need_comma = it_ != begin_;
|
auto need_comma = it_ != first_;
|
||||||
v_.first = {};
|
v_.first = {};
|
||||||
begin_ = it_;
|
first_ = it_;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
detail::skip_ows(it_, end_);
|
detail::skip_ows(it_, last_);
|
||||||
if(it_ == end_)
|
if(it_ == last_)
|
||||||
return err();
|
return err();
|
||||||
auto const c = *it_;
|
auto const c = *it_;
|
||||||
if(detail::is_tchar(c))
|
if(detail::is_tchar(c))
|
||||||
@@ -340,7 +341,7 @@ increment()
|
|||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
++it_;
|
++it_;
|
||||||
if(it_ == end_)
|
if(it_ == last_)
|
||||||
break;
|
break;
|
||||||
if(! detail::is_tchar(*it_))
|
if(! detail::is_tchar(*it_))
|
||||||
break;
|
break;
|
||||||
@@ -349,8 +350,8 @@ increment()
|
|||||||
static_cast<std::size_t>(it_ - p0)};
|
static_cast<std::size_t>(it_ - p0)};
|
||||||
detail::param_iter pi;
|
detail::param_iter pi;
|
||||||
pi.it = it_;
|
pi.it = it_;
|
||||||
pi.begin = it_;
|
pi.first = it_;
|
||||||
pi.end = end_;
|
pi.last = last_;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
pi.increment();
|
pi.increment();
|
||||||
@@ -375,8 +376,8 @@ class token_list::const_iterator
|
|||||||
{
|
{
|
||||||
token_list::value_type v_;
|
token_list::value_type v_;
|
||||||
iter_type it_;
|
iter_type it_;
|
||||||
iter_type begin_;
|
iter_type first_;
|
||||||
iter_type end_;
|
iter_type last_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = token_list::value_type;
|
using value_type = token_list::value_type;
|
||||||
@@ -392,8 +393,8 @@ public:
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
other.it_ == it_ &&
|
other.it_ == it_ &&
|
||||||
other.begin_ == begin_ &&
|
other.first_ == first_ &&
|
||||||
other.end_ == end_;
|
other.last_ == last_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -435,8 +436,8 @@ private:
|
|||||||
const_iterator(iter_type begin, iter_type end)
|
const_iterator(iter_type begin, iter_type end)
|
||||||
{
|
{
|
||||||
it_ = begin;
|
it_ = begin;
|
||||||
begin_ = begin;
|
first_ = begin;
|
||||||
end_ = end;
|
last_ = end;
|
||||||
increment();
|
increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,16 +493,16 @@ increment()
|
|||||||
auto const err =
|
auto const err =
|
||||||
[&]
|
[&]
|
||||||
{
|
{
|
||||||
it_ = end_;
|
it_ = last_;
|
||||||
begin_ = end_;
|
first_ = last_;
|
||||||
};
|
};
|
||||||
auto need_comma = it_ != begin_;
|
auto need_comma = it_ != first_;
|
||||||
v_ = {};
|
v_ = {};
|
||||||
begin_ = it_;
|
first_ = it_;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
detail::skip_ows(it_, end_);
|
detail::skip_ows(it_, last_);
|
||||||
if(it_ == end_)
|
if(it_ == last_)
|
||||||
return err();
|
return err();
|
||||||
auto const c = *it_;
|
auto const c = *it_;
|
||||||
if(detail::is_tchar(c))
|
if(detail::is_tchar(c))
|
||||||
@@ -512,7 +513,7 @@ increment()
|
|||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
++it_;
|
++it_;
|
||||||
if(it_ == end_)
|
if(it_ == last_)
|
||||||
break;
|
break;
|
||||||
if(! detail::is_tchar(*it_))
|
if(! detail::is_tchar(*it_))
|
||||||
break;
|
break;
|
||||||
|
@@ -15,15 +15,14 @@ namespace http {
|
|||||||
|
|
||||||
/** A list of parameters in a HTTP extension field value.
|
/** A list of parameters in a HTTP extension field value.
|
||||||
|
|
||||||
This container allows iteration of the parameter list
|
This container allows iteration of the parameter list in a HTTP
|
||||||
in a HTTP extension. The parameter list is a series
|
extension. The parameter list is a series of name/value pairs
|
||||||
of "name = value" pairs with each pair starting with
|
with each pair starting with a semicolon. The value is optional.
|
||||||
a semicolon.
|
|
||||||
|
|
||||||
BNF:
|
BNF:
|
||||||
@code
|
@code
|
||||||
param-list = *( OWS ";" OWS param )
|
param-list = *( OWS ";" OWS param )
|
||||||
param = token OWS "=" OWS ( token / quoted-string )
|
param = token OWS [ "=" OWS ( token / quoted-string ) ]
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
If a parsing error is encountered while iterating the string,
|
If a parsing error is encountered while iterating the string,
|
||||||
@@ -48,8 +47,9 @@ class param_list
|
|||||||
public:
|
public:
|
||||||
/** The type of each element in the list.
|
/** The type of each element in the list.
|
||||||
|
|
||||||
The first string in the pair is the name of the
|
The first string in the pair is the name of the parameter,
|
||||||
parameter, and the second string in the pair is its value.
|
and the second string in the pair is its value (which may
|
||||||
|
be empty).
|
||||||
*/
|
*/
|
||||||
using value_type =
|
using value_type =
|
||||||
std::pair<boost::string_ref, boost::string_ref>;
|
std::pair<boost::string_ref, boost::string_ref>;
|
||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
||||||
ext = token param-list
|
ext = token param-list
|
||||||
param-list = *( OWS ";" OWS param )
|
param-list = *( OWS ";" OWS param )
|
||||||
param = token OWS "=" OWS ( token / quoted-string )
|
param = token OWS [ "=" OWS ( token / quoted-string ) ]
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
If a parsing error is encountered while iterating the string,
|
If a parsing error is encountered while iterating the string,
|
||||||
@@ -196,13 +196,13 @@ public:
|
|||||||
|
|
||||||
/** A list of tokens in a comma separated HTTP field value.
|
/** A list of tokens in a comma separated HTTP field value.
|
||||||
|
|
||||||
This container allows iteration of the extensions in a HTTP
|
This container allows iteration of a list of items in a
|
||||||
field value. The extension list is a comma separated list of
|
header field value. The input is a comma separated list of
|
||||||
token parameter list pairs.
|
tokens.
|
||||||
|
|
||||||
BNF:
|
BNF:
|
||||||
@code
|
@code
|
||||||
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
|
token-list = *( "," OWS ) token *( OWS "," [ OWS token ] )
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
If a parsing error is encountered while iterating the string,
|
If a parsing error is encountered while iterating the string,
|
||||||
@@ -226,12 +226,7 @@ class token_list
|
|||||||
boost::string_ref s_;
|
boost::string_ref s_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** The type of each element in the token list.
|
/// The type of each element in the token list.
|
||||||
|
|
||||||
The first element of the pair is the extension token, and the
|
|
||||||
second element of the pair is an iterable container holding the
|
|
||||||
extension's name/value parameters.
|
|
||||||
*/
|
|
||||||
using value_type = boost::string_ref;
|
using value_type = boost::string_ref;
|
||||||
|
|
||||||
/// A constant iterator to the list
|
/// A constant iterator to the list
|
||||||
|
@@ -43,8 +43,11 @@ public:
|
|||||||
{
|
{
|
||||||
s.push_back(';');
|
s.push_back(';');
|
||||||
s.append(str(p.first));
|
s.append(str(p.first));
|
||||||
s.push_back('=');
|
if(! p.second.empty())
|
||||||
s.append(str(p.second));
|
{
|
||||||
|
s.push_back('=');
|
||||||
|
s.append(str(p.second));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -73,18 +76,19 @@ public:
|
|||||||
BEAST_EXPECTS(got == good, fmt(got));
|
BEAST_EXPECTS(got == good, fmt(got));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ce("");
|
||||||
|
ce(";x");
|
||||||
|
ce(";xy");
|
||||||
|
ce(";x;y");
|
||||||
|
|
||||||
ce("");
|
ce("");
|
||||||
cs(" ;\t i =\t 1 \t", ";i=1");
|
cs(" ;\t i =\t 1 \t", ";i=1");
|
||||||
cq("\t; \t xyz=1 ; ijk=\"q\\\"t\"", ";xyz=1;ijk=q\"t");
|
cq("\t; \t xyz=1 ; ijk=\"q\\\"t\"", ";xyz=1;ijk=q\"t");
|
||||||
|
ce(";x;y");
|
||||||
|
|
||||||
// invalid strings
|
// invalid strings
|
||||||
cs(";", "");
|
cs(";", "");
|
||||||
cs(";,", "");
|
cs(";,", "");
|
||||||
cs(";xy", "");
|
|
||||||
cs(";xy", "");
|
|
||||||
cs(";xy ", "");
|
|
||||||
cs(";xy,", "");
|
|
||||||
|
|
||||||
cq(";x=,", "");
|
cq(";x=,", "");
|
||||||
cq(";xy=\"", "");
|
cq(";xy=\"", "");
|
||||||
cq(";xy=\"\x7f", "");
|
cq(";xy=\"\x7f", "");
|
||||||
@@ -136,7 +140,6 @@ public:
|
|||||||
param-list = *( OWS ";" OWS param )
|
param-list = *( OWS ";" OWS param )
|
||||||
param = token OWS "=" OWS ( token / quoted-string )
|
param = token OWS "=" OWS ( token / quoted-string )
|
||||||
*/
|
*/
|
||||||
ce("");
|
|
||||||
cs(",", "");
|
cs(",", "");
|
||||||
cs(", ", "");
|
cs(", ", "");
|
||||||
cs(",\t", "");
|
cs(",\t", "");
|
||||||
@@ -147,12 +150,16 @@ public:
|
|||||||
cs("\t , \t", "");
|
cs("\t , \t", "");
|
||||||
cs(",,", "");
|
cs(",,", "");
|
||||||
cs(" , \t,, \t,", "");
|
cs(" , \t,, \t,", "");
|
||||||
|
cs( "permessage-deflate; client_no_context_takeover; client_max_window_bits",
|
||||||
|
"permessage-deflate;client_no_context_takeover;client_max_window_bits");
|
||||||
|
|
||||||
ce("a");
|
ce("a");
|
||||||
ce("ab");
|
ce("ab");
|
||||||
ce("a,b");
|
ce("a,b");
|
||||||
cs(" a ", "a");
|
cs(" a ", "a");
|
||||||
cs("\t a, b\t , c\t", "a,b,c");
|
cs("\t a, b\t , c\t", "a,b,c");
|
||||||
|
ce("a;b");
|
||||||
|
ce("a;b;c");
|
||||||
|
|
||||||
cs("a; \t i\t=\t \t1\t ", "a;i=1");
|
cs("a; \t i\t=\t \t1\t ", "a;i=1");
|
||||||
ce("a;i=1;j=2;k=3");
|
ce("a;i=1;j=2;k=3");
|
||||||
|
Reference in New Issue
Block a user