Files
boost_beast/include/beast/http/impl/verb.ipp
T
Vinnie Falco ac175cb694 Refactor method and verb (API Change):
The verb interfaces now use verb::unknown instead of
boost::optional<verb> == boost::none to indicate that
the request-method is an unrecognized string.

The http::header interface is modified to focus more on the
verb enum rather than the string. For recognized verbs, the
implementation stores an integer instead of the string.
Unknown verbs are still stored as strings.

* header::method now returns a verb
* header::method_string returns the method text
2017-06-04 14:51:41 -07:00

333 lines
6.8 KiB
C++

//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_IMPL_VERB_IPP
#define BEAST_HTTP_IMPL_VERB_IPP
#include <boost/throw_exception.hpp>
#include <stdexcept>
namespace beast {
namespace http {
namespace detail {
template<class = void>
inline
string_view
verb_to_string(verb v)
{
switch(v)
{
case verb::delete_: return "DELETE";
case verb::get: return "GET";
case verb::head: return "HEAD";
case verb::post: return "POST";
case verb::put: return "PUT";
case verb::connect: return "CONNECT";
case verb::options: return "OPTIONS";
case verb::trace: return "TRACE";
case verb::copy: return "COPY";
case verb::lock: return "LOCK";
case verb::mkcol: return "MKCOL";
case verb::move: return "MOVE";
case verb::propfind: return "PROPFIND";
case verb::proppatch: return "PROPPATCH";
case verb::search: return "SEARCH";
case verb::unlock: return "UNLOCK";
case verb::bind: return "BIND";
case verb::rebind: return "REBIND";
case verb::unbind: return "UNBIND";
case verb::acl: return "ACL";
case verb::report: return "REPORT";
case verb::mkactivity: return "MKACTIVITY";
case verb::checkout: return "CHECKOUT";
case verb::merge: return "MERGE";
case verb::msearch: return "M-SEARCH";
case verb::notify: return "NOTIFY";
case verb::subscribe: return "SUBSCRIBE";
case verb::unsubscribe: return "UNSUBSCRIBE";
case verb::patch: return "PATCH";
case verb::purge: return "PURGE";
case verb::mkcalendar: return "MKCALENDAR";
case verb::link: return "LINK";
case verb::unlink: return "UNLINK";
case verb::unknown:
return "<unknown>";
}
BOOST_THROW_EXCEPTION(std::invalid_argument{"unknown verb"});
}
template<class = void>
verb
string_to_verb(string_view v)
{
/*
ACL
BIND
CHECKOUT
CONNECT
COPY
DELETE
GET
HEAD
LINK
LOCK
M-SEARCH
MERGE
MKACTIVITY
MKCALENDAR
MKCOL
MOVE
NOTIFY
OPTIONS
PATCH
POST
PROPFIND
PROPPATCH
PURGE
PUT
REBIND
REPORT
SEARCH
SUBSCRIBE
TRACE
UNBIND
UNLINK
UNLOCK
UNSUBSCRIBE
*/
if(v.size() < 3)
return verb::unknown;
// s must be null terminated
auto const eq =
[](string_view sv, char const* s)
{
auto p = sv.data();
for(;;)
{
if(*s != *p)
return false;
++s;
++p;
if(! *s)
return p == sv.end();
}
};
auto c = v[0];
v.remove_prefix(1);
switch(c)
{
case 'A':
if(v == "CL")
return verb::acl;
break;
case 'B':
if(v == "IND")
return verb::bind;
break;
case 'C':
c = v[0];
v.remove_prefix(1);
switch(c)
{
case 'H':
if(eq(v, "ECKOUT"))
return verb::checkout;
break;
case 'O':
if(eq(v, "NNECT"))
return verb::connect;
if(eq(v, "PY"))
return verb::copy;
// [[fallthrough]]
default:
break;
}
break;
case 'D':
if(eq(v, "ELETE"))
return verb::delete_;
break;
case 'G':
if(eq(v, "ET"))
return verb::get;
break;
case 'H':
if(eq(v, "EAD"))
return verb::head;
break;
case 'L':
if(eq(v, "INK"))
return verb::link;
if(eq(v, "OCK"))
return verb::lock;
break;
case 'M':
c = v[0];
v.remove_prefix(1);
switch(c)
{
case '-':
if(eq(v, "SEARCH"))
return verb::msearch;
break;
case 'E':
if(eq(v, "RGE"))
return verb::merge;
break;
case 'K':
if(eq(v, "ACTIVITY"))
return verb::mkactivity;
if(v[0] == 'C')
{
v.remove_prefix(1);
if(eq(v, "ALENDAR"))
return verb::mkcalendar;
if(eq(v, "OL"))
return verb::mkcol;
break;
}
break;
case 'O':
if(eq(v, "VE"))
return verb::move;
// [[fallthrough]]
default:
break;
}
break;
case 'N':
if(eq(v, "OTIFY"))
return verb::notify;
break;
case 'O':
if(eq(v, "PTIONS"))
return verb::options;
break;
case 'P':
c = v[0];
v.remove_prefix(1);
switch(c)
{
case 'A':
if(eq(v, "TCH"))
return verb::patch;
break;
case 'O':
if(eq(v, "ST"))
return verb::post;
break;
case 'R':
if(eq(v, "OPFIND"))
return verb::propfind;
if(eq(v, "OPPATCH"))
return verb::proppatch;
break;
case 'U':
if(eq(v, "RGE"))
return verb::purge;
if(eq(v, "T"))
return verb::put;
// [[fallthrough]]
default:
break;
}
break;
case 'R':
if(v[0] != 'E')
break;
v.remove_prefix(1);
if(eq(v, "BIND"))
return verb::rebind;
if(eq(v, "PORT"))
return verb::report;
break;
case 'S':
if(eq(v, "EARCH"))
return verb::search;
if(eq(v, "UBSCRIBE"))
return verb::subscribe;
break;
case 'T':
if(eq(v, "RACE"))
return verb::trace;
break;
case 'U':
if(v[0] != 'N')
break;
v.remove_prefix(1);
if(eq(v, "BIND"))
return verb::unbind;
if(eq(v, "LINK"))
return verb::unlink;
if(eq(v, "LOCK"))
return verb::unlock;
if(eq(v, "SUBSCRIBE"))
return verb::unsubscribe;
break;
default:
break;
}
return verb::unknown;
}
} // detail
inline
string_view
to_string(verb v)
{
return detail::verb_to_string(v);
}
inline
verb
string_to_verb(string_view s)
{
return detail::string_to_verb(s);
}
} // http
} // beast
#endif