1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
11#define BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
12
13#include <boost/beast/http/rfc7230.hpp>
14#include <algorithm>
15
16namespace boost {
17namespace beast {
18namespace http {
19
20
21std::string
22param_list::const_iterator::
23unquote(string_view sr)
24{
25    std::string s;
26    s.reserve(sr.size());
27    auto it = sr.begin() + 1;
28    auto end = sr.end() - 1;
29    while(it != end)
30    {
31        if(*it == '\\')
32            ++it;
33        s.push_back(*it);
34        ++it;
35    }
36    return s;
37}
38
39void
40param_list::const_iterator::
41increment()
42{
43    s_.clear();
44    pi_.increment();
45    if(pi_.empty())
46    {
47        pi_.it = pi_.last;
48        pi_.first = pi_.last;
49    }
50    else if(! pi_.v.second.empty() &&
51        pi_.v.second.front() == '"')
52    {
53        s_ = unquote(pi_.v.second);
54        pi_.v.second = string_view{
55            s_.data(), s_.size()};
56    }
57}
58
59void
60ext_list::const_iterator::
61increment()
62{
63    /*
64        ext-list    = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
65        ext         = token param-list
66        param-list  = *( OWS ";" OWS param )
67        param       = token OWS "=" OWS ( token / quoted-string )
68
69        chunked;a=b;i=j;gzip;windowBits=12
70        x,y
71        ,,,,,chameleon
72    */
73    auto const err =
74        [&]
75        {
76            it_ = last_;
77            first_ = last_;
78        };
79    auto need_comma = it_ != first_;
80    v_.first = {};
81    first_ = it_;
82    for(;;)
83    {
84        detail::skip_ows(it_, last_);
85        if(it_ == last_)
86            return err();
87        auto const c = *it_;
88        if(detail::is_token_char(c))
89        {
90            if(need_comma)
91                return err();
92            auto const p0 = it_;
93            for(;;)
94            {
95                ++it_;
96                if(it_ == last_)
97                    break;
98                if(! detail::is_token_char(*it_))
99                    break;
100            }
101            v_.first = string_view{&*p0,
102                static_cast<std::size_t>(it_ - p0)};
103			if (it_ == last_)
104				return;
105            detail::param_iter pi;
106            pi.it = it_;
107            pi.first = it_;
108            pi.last = last_;
109            for(;;)
110            {
111                pi.increment();
112                if(pi.empty())
113                    break;
114            }
115            v_.second = param_list{string_view{&*it_,
116                static_cast<std::size_t>(pi.it - it_)}};
117            it_ = pi.it;
118            return;
119        }
120        if(c != ',')
121            return err();
122        need_comma = false;
123        ++it_;
124    }
125}
126
127auto
128ext_list::
129find(string_view const& s) -> const_iterator
130{
131    return std::find_if(begin(), end(),
132        [&s](value_type const& v)
133        {
134            return beast::iequals(s, v.first);
135        });
136}
137
138bool
139ext_list::
140exists(string_view const& s)
141{
142    return find(s) != end();
143}
144
145void
146token_list::const_iterator::
147increment()
148{
149    /*
150        token-list  = *( "," OWS ) token *( OWS "," [ OWS ext ] )
151    */
152    auto const err =
153        [&]
154        {
155            it_ = last_;
156            first_ = last_;
157        };
158    auto need_comma = it_ != first_;
159    v_ = {};
160    first_ = it_;
161    for(;;)
162    {
163        detail::skip_ows(it_, last_);
164        if(it_ == last_)
165            return err();
166        auto const c = *it_;
167        if(detail::is_token_char(c))
168        {
169            if(need_comma)
170                return err();
171            auto const p0 = it_;
172            for(;;)
173            {
174                ++it_;
175                if(it_ == last_)
176                    break;
177                if(! detail::is_token_char(*it_))
178                    break;
179            }
180            v_ = string_view{&*p0,
181                static_cast<std::size_t>(it_ - p0)};
182            return;
183        }
184        if(c != ',')
185            return err();
186        need_comma = false;
187        ++it_;
188    }
189}
190
191bool
192token_list::
193exists(string_view const& s)
194{
195    return std::find_if(begin(), end(),
196        [&s](value_type const& v)
197        {
198            return beast::iequals(s, v);
199        }
200    ) != end();
201}
202
203} // http
204} // beast
205} // boost
206
207#endif // BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
208