1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#include <boost/http/method.hpp>
10  
#include <boost/http/method.hpp>
11  
#include <boost/http/detail/sv.hpp>
11  
#include <boost/http/detail/sv.hpp>
12  
#include <boost/throw_exception.hpp>
12  
#include <boost/throw_exception.hpp>
13  
#include <ostream>
13  
#include <ostream>
14  

14  

15  
namespace boost {
15  
namespace boost {
16  
namespace http {
16  
namespace http {
17  

17  

18  
core::string_view
18  
core::string_view
19  
to_string(method v)
19  
to_string(method v)
20  
{
20  
{
21  
    using namespace detail::string_literals;
21  
    using namespace detail::string_literals;
22  
    switch(v)
22  
    switch(v)
23  
    {
23  
    {
24  
    case method::delete_:       return "DELETE"_sv;
24  
    case method::delete_:       return "DELETE"_sv;
25  
    case method::get:           return "GET"_sv;
25  
    case method::get:           return "GET"_sv;
26  
    case method::head:          return "HEAD"_sv;
26  
    case method::head:          return "HEAD"_sv;
27  
    case method::post:          return "POST"_sv;
27  
    case method::post:          return "POST"_sv;
28  
    case method::put:           return "PUT"_sv;
28  
    case method::put:           return "PUT"_sv;
29  
    case method::connect:       return "CONNECT"_sv;
29  
    case method::connect:       return "CONNECT"_sv;
30  
    case method::options:       return "OPTIONS"_sv;
30  
    case method::options:       return "OPTIONS"_sv;
31  
    case method::trace:         return "TRACE"_sv;
31  
    case method::trace:         return "TRACE"_sv;
32  

32  

33  
    case method::copy:          return "COPY"_sv;
33  
    case method::copy:          return "COPY"_sv;
34  
    case method::lock:          return "LOCK"_sv;
34  
    case method::lock:          return "LOCK"_sv;
35  
    case method::mkcol:         return "MKCOL"_sv;
35  
    case method::mkcol:         return "MKCOL"_sv;
36  
    case method::move:          return "MOVE"_sv;
36  
    case method::move:          return "MOVE"_sv;
37  
    case method::propfind:      return "PROPFIND"_sv;
37  
    case method::propfind:      return "PROPFIND"_sv;
38  
    case method::proppatch:     return "PROPPATCH"_sv;
38  
    case method::proppatch:     return "PROPPATCH"_sv;
39  
    case method::search:        return "SEARCH"_sv;
39  
    case method::search:        return "SEARCH"_sv;
40  
    case method::unlock:        return "UNLOCK"_sv;
40  
    case method::unlock:        return "UNLOCK"_sv;
41  
    case method::bind:          return "BIND"_sv;
41  
    case method::bind:          return "BIND"_sv;
42  
    case method::rebind:        return "REBIND"_sv;
42  
    case method::rebind:        return "REBIND"_sv;
43  
    case method::unbind:        return "UNBIND"_sv;
43  
    case method::unbind:        return "UNBIND"_sv;
44  
    case method::acl:           return "ACL"_sv;
44  
    case method::acl:           return "ACL"_sv;
45  

45  

46  
    case method::report:        return "REPORT"_sv;
46  
    case method::report:        return "REPORT"_sv;
47  
    case method::mkactivity:    return "MKACTIVITY"_sv;
47  
    case method::mkactivity:    return "MKACTIVITY"_sv;
48  
    case method::checkout:      return "CHECKOUT"_sv;
48  
    case method::checkout:      return "CHECKOUT"_sv;
49  
    case method::merge:         return "MERGE"_sv;
49  
    case method::merge:         return "MERGE"_sv;
50  

50  

51  
    case method::msearch:       return "M-SEARCH"_sv;
51  
    case method::msearch:       return "M-SEARCH"_sv;
52  
    case method::notify:        return "NOTIFY"_sv;
52  
    case method::notify:        return "NOTIFY"_sv;
53  
    case method::subscribe:     return "SUBSCRIBE"_sv;
53  
    case method::subscribe:     return "SUBSCRIBE"_sv;
54  
    case method::unsubscribe:   return "UNSUBSCRIBE"_sv;
54  
    case method::unsubscribe:   return "UNSUBSCRIBE"_sv;
55  

55  

56  
    case method::patch:         return "PATCH"_sv;
56  
    case method::patch:         return "PATCH"_sv;
57  
    case method::purge:         return "PURGE"_sv;
57  
    case method::purge:         return "PURGE"_sv;
58  

58  

59  
    case method::mkcalendar:    return "MKCALENDAR"_sv;
59  
    case method::mkcalendar:    return "MKCALENDAR"_sv;
60  

60  

61  
    case method::link:          return "LINK"_sv;
61  
    case method::link:          return "LINK"_sv;
62  
    case method::unlink:        return "UNLINK"_sv;
62  
    case method::unlink:        return "UNLINK"_sv;
63  

63  

64  
    case method::unknown:
64  
    case method::unknown:
65  
        return "<unknown>"_sv;
65  
        return "<unknown>"_sv;
66  
    }
66  
    }
67  

67  

68  
    BOOST_THROW_EXCEPTION(
68  
    BOOST_THROW_EXCEPTION(
69  
        std::invalid_argument("unknown method"));
69  
        std::invalid_argument("unknown method"));
70  
}
70  
}
71  

71  

72  
method
72  
method
73  
string_to_method(
73  
string_to_method(
74  
    core::string_view v)
74  
    core::string_view v)
75  
{
75  
{
76  
/*
76  
/*
77  
    ACL
77  
    ACL
78  
    BIND
78  
    BIND
79  
    CHECKOUT
79  
    CHECKOUT
80  
    CONNECT
80  
    CONNECT
81  
    COPY
81  
    COPY
82  
    DELETE
82  
    DELETE
83  
    GET
83  
    GET
84  
    HEAD
84  
    HEAD
85  
    LINK
85  
    LINK
86  
    LOCK
86  
    LOCK
87  
    M-SEARCH
87  
    M-SEARCH
88  
    MERGE
88  
    MERGE
89  
    MKACTIVITY
89  
    MKACTIVITY
90  
    MKCALENDAR
90  
    MKCALENDAR
91  
    MKCOL
91  
    MKCOL
92  
    MOVE
92  
    MOVE
93  
    NOTIFY
93  
    NOTIFY
94  
    OPTIONS
94  
    OPTIONS
95  
    PATCH
95  
    PATCH
96  
    POST
96  
    POST
97  
    PROPFIND
97  
    PROPFIND
98  
    PROPPATCH
98  
    PROPPATCH
99  
    PURGE
99  
    PURGE
100  
    PUT
100  
    PUT
101  
    REBIND
101  
    REBIND
102  
    REPORT
102  
    REPORT
103  
    SEARCH
103  
    SEARCH
104  
    SUBSCRIBE
104  
    SUBSCRIBE
105  
    TRACE
105  
    TRACE
106  
    UNBIND
106  
    UNBIND
107  
    UNLINK
107  
    UNLINK
108  
    UNLOCK
108  
    UNLOCK
109  
    UNSUBSCRIBE
109  
    UNSUBSCRIBE
110  
*/
110  
*/
111  
    using namespace detail::string_literals;
111  
    using namespace detail::string_literals;
112  
    if(v.size() < 3)
112  
    if(v.size() < 3)
113  
        return method::unknown;
113  
        return method::unknown;
114  
    auto c = v[0];
114  
    auto c = v[0];
115  
    v.remove_prefix(1);
115  
    v.remove_prefix(1);
116  
    switch(c)
116  
    switch(c)
117  
    {
117  
    {
118  
    case 'A':
118  
    case 'A':
119  
        if(v == "CL"_sv)
119  
        if(v == "CL"_sv)
120  
            return method::acl;
120  
            return method::acl;
121  
        break;
121  
        break;
122  

122  

123  
    case 'B':
123  
    case 'B':
124  
        if(v == "IND"_sv)
124  
        if(v == "IND"_sv)
125  
            return method::bind;
125  
            return method::bind;
126  
        break;
126  
        break;
127  

127  

128  
    case 'C':
128  
    case 'C':
129  
        c = v[0];
129  
        c = v[0];
130  
        v.remove_prefix(1);
130  
        v.remove_prefix(1);
131  
        switch(c)
131  
        switch(c)
132  
        {
132  
        {
133  
        case 'H':
133  
        case 'H':
134  
            if(v == "ECKOUT"_sv)
134  
            if(v == "ECKOUT"_sv)
135  
                return method::checkout;
135  
                return method::checkout;
136  
            break;
136  
            break;
137  

137  

138  
        case 'O':
138  
        case 'O':
139  
            if(v == "NNECT"_sv)
139  
            if(v == "NNECT"_sv)
140  
                return method::connect;
140  
                return method::connect;
141  
            if(v == "PY"_sv)
141  
            if(v == "PY"_sv)
142  
                return method::copy;
142  
                return method::copy;
143  
            BOOST_FALLTHROUGH;
143  
            BOOST_FALLTHROUGH;
144  

144  

145  
        default:
145  
        default:
146  
            break;
146  
            break;
147  
        }
147  
        }
148  
        break;
148  
        break;
149  

149  

150  
    case 'D':
150  
    case 'D':
151  
        if(v == "ELETE"_sv)
151  
        if(v == "ELETE"_sv)
152  
            return method::delete_;
152  
            return method::delete_;
153  
        break;
153  
        break;
154  

154  

155  
    case 'G':
155  
    case 'G':
156  
        if(v == "ET"_sv)
156  
        if(v == "ET"_sv)
157  
            return method::get;
157  
            return method::get;
158  
        break;
158  
        break;
159  

159  

160  
    case 'H':
160  
    case 'H':
161  
        if(v == "EAD"_sv)
161  
        if(v == "EAD"_sv)
162  
            return method::head;
162  
            return method::head;
163  
        break;
163  
        break;
164  

164  

165  
    case 'L':
165  
    case 'L':
166  
        if(v == "INK"_sv)
166  
        if(v == "INK"_sv)
167  
            return method::link;
167  
            return method::link;
168  
        if(v == "OCK"_sv)
168  
        if(v == "OCK"_sv)
169  
            return method::lock;
169  
            return method::lock;
170  
        break;
170  
        break;
171  

171  

172  
    case 'M':
172  
    case 'M':
173  
        c = v[0];
173  
        c = v[0];
174  
        v.remove_prefix(1);
174  
        v.remove_prefix(1);
175  
        switch(c)
175  
        switch(c)
176  
        {
176  
        {
177  
        case '-':
177  
        case '-':
178  
            if(v == "SEARCH"_sv)
178  
            if(v == "SEARCH"_sv)
179  
                return method::msearch;
179  
                return method::msearch;
180  
            break;
180  
            break;
181  

181  

182  
        case 'E':
182  
        case 'E':
183  
            if(v == "RGE"_sv)
183  
            if(v == "RGE"_sv)
184  
                return method::merge;
184  
                return method::merge;
185  
            break;
185  
            break;
186  

186  

187  
        case 'K':
187  
        case 'K':
188  
            if(v == "ACTIVITY"_sv)
188  
            if(v == "ACTIVITY"_sv)
189  
                return method::mkactivity;
189  
                return method::mkactivity;
190  
            if(v[0] == 'C')
190  
            if(v[0] == 'C')
191  
            {
191  
            {
192  
                v.remove_prefix(1);
192  
                v.remove_prefix(1);
193  
                if(v == "ALENDAR"_sv)
193  
                if(v == "ALENDAR"_sv)
194  
                    return method::mkcalendar;
194  
                    return method::mkcalendar;
195  
                if(v == "OL"_sv)
195  
                if(v == "OL"_sv)
196  
                    return method::mkcol;
196  
                    return method::mkcol;
197  
                break;
197  
                break;
198  
            }
198  
            }
199  
            break;
199  
            break;
200  

200  

201  
        case 'O':
201  
        case 'O':
202  
            if(v == "VE"_sv)
202  
            if(v == "VE"_sv)
203  
                return method::move;
203  
                return method::move;
204  
            BOOST_FALLTHROUGH;
204  
            BOOST_FALLTHROUGH;
205  

205  

206  
        default:
206  
        default:
207  
            break;
207  
            break;
208  
        }
208  
        }
209  
        break;
209  
        break;
210  

210  

211  
    case 'N':
211  
    case 'N':
212  
        if(v == "OTIFY"_sv)
212  
        if(v == "OTIFY"_sv)
213  
            return method::notify;
213  
            return method::notify;
214  
        break;
214  
        break;
215  

215  

216  
    case 'O':
216  
    case 'O':
217  
        if(v == "PTIONS"_sv)
217  
        if(v == "PTIONS"_sv)
218  
            return method::options;
218  
            return method::options;
219  
        break;
219  
        break;
220  

220  

221  
    case 'P':
221  
    case 'P':
222  
        c = v[0];
222  
        c = v[0];
223  
        v.remove_prefix(1);
223  
        v.remove_prefix(1);
224  
        switch(c)
224  
        switch(c)
225  
        {
225  
        {
226  
        case 'A':
226  
        case 'A':
227  
            if(v == "TCH"_sv)
227  
            if(v == "TCH"_sv)
228  
                return method::patch;
228  
                return method::patch;
229  
            break;
229  
            break;
230  

230  

231  
        case 'O':
231  
        case 'O':
232  
            if(v == "ST"_sv)
232  
            if(v == "ST"_sv)
233  
                return method::post;
233  
                return method::post;
234  
            break;
234  
            break;
235  

235  

236  
        case 'R':
236  
        case 'R':
237  
            if(v == "OPFIND"_sv)
237  
            if(v == "OPFIND"_sv)
238  
                return method::propfind;
238  
                return method::propfind;
239  
            if(v == "OPPATCH"_sv)
239  
            if(v == "OPPATCH"_sv)
240  
                return method::proppatch;
240  
                return method::proppatch;
241  
            break;
241  
            break;
242  

242  

243  
        case 'U':
243  
        case 'U':
244  
            if(v == "RGE"_sv)
244  
            if(v == "RGE"_sv)
245  
                return method::purge;
245  
                return method::purge;
246  
            if(v == "T"_sv)
246  
            if(v == "T"_sv)
247  
                return method::put;
247  
                return method::put;
248  
            BOOST_FALLTHROUGH;
248  
            BOOST_FALLTHROUGH;
249  

249  

250  
        default:
250  
        default:
251  
            break;
251  
            break;
252  
        }
252  
        }
253  
        break;
253  
        break;
254  

254  

255  
    case 'R':
255  
    case 'R':
256  
        if(v[0] != 'E')
256  
        if(v[0] != 'E')
257  
            break;
257  
            break;
258  
        v.remove_prefix(1);
258  
        v.remove_prefix(1);
259  
        if(v == "BIND"_sv)
259  
        if(v == "BIND"_sv)
260  
            return method::rebind;
260  
            return method::rebind;
261  
        if(v == "PORT"_sv)
261  
        if(v == "PORT"_sv)
262  
            return method::report;
262  
            return method::report;
263  
        break;
263  
        break;
264  

264  

265  
    case 'S':
265  
    case 'S':
266  
        if(v == "EARCH"_sv)
266  
        if(v == "EARCH"_sv)
267  
            return method::search;
267  
            return method::search;
268  
        if(v == "UBSCRIBE"_sv)
268  
        if(v == "UBSCRIBE"_sv)
269  
            return method::subscribe;
269  
            return method::subscribe;
270  
        break;
270  
        break;
271  

271  

272  
    case 'T':
272  
    case 'T':
273  
        if(v == "RACE"_sv)
273  
        if(v == "RACE"_sv)
274  
            return method::trace;
274  
            return method::trace;
275  
        break;
275  
        break;
276  

276  

277  
    case 'U':
277  
    case 'U':
278  
        if(v[0] != 'N')
278  
        if(v[0] != 'N')
279  
            break;
279  
            break;
280  
        v.remove_prefix(1);
280  
        v.remove_prefix(1);
281  
        if(v == "BIND"_sv)
281  
        if(v == "BIND"_sv)
282  
            return method::unbind;
282  
            return method::unbind;
283  
        if(v == "LINK"_sv)
283  
        if(v == "LINK"_sv)
284  
            return method::unlink;
284  
            return method::unlink;
285  
        if(v == "LOCK"_sv)
285  
        if(v == "LOCK"_sv)
286  
            return method::unlock;
286  
            return method::unlock;
287  
        if(v == "SUBSCRIBE"_sv)
287  
        if(v == "SUBSCRIBE"_sv)
288  
            return method::unsubscribe;
288  
            return method::unsubscribe;
289  
        break;
289  
        break;
290  

290  

291  
    default:
291  
    default:
292  
        break;
292  
        break;
293  
    }
293  
    }
294  

294  

295  
    return method::unknown;
295  
    return method::unknown;
296  
}
296  
}
297  

297  

298  
std::ostream&
298  
std::ostream&
299  
operator<<(
299  
operator<<(
300  
    std::ostream& os,
300  
    std::ostream& os,
301  
    method v)
301  
    method v)
302  
{
302  
{
303  
    os << to_string(v);
303  
    os << to_string(v);
304  
    return os;
304  
    return os;
305  
}
305  
}
306  

306  

307  
} // http
307  
} // http
308  
} // boost
308  
} // boost