forked from boostorg/beast
Refactor treatment of request-method (API Change):
fix #397 method enum class is added to represent all known request methods. Functions are provided to convert from strings to and from the method enumeration. The fields container is modified to also work with the enum.
This commit is contained in:
1 parent
cd2363e951
commit
f7211da154
21 files changed
+737
-79
No files matched your search
@@ -23,6 +23,7 @@
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/serializer.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/http/verb.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -11,8 +11,10 @@
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <beast/core/detail/empty_base_optimization.hpp>
|
||||
#include <beast/http/verb.hpp>
|
||||
#include <beast/http/detail/fields.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
@@ -59,6 +61,8 @@ class basic_fields :
|
||||
using size_type =
|
||||
typename std::allocator_traits<Allocator>::size_type;
|
||||
|
||||
boost::optional<verb> verb_;
|
||||
|
||||
void
|
||||
delete_all();
|
||||
|
||||
@@ -147,24 +151,6 @@ public:
|
||||
template<class OtherAlloc>
|
||||
basic_fields& operator=(basic_fields<OtherAlloc> const&);
|
||||
|
||||
/// Construct from a field sequence.
|
||||
template<class FwdIt>
|
||||
basic_fields(FwdIt first, FwdIt last);
|
||||
|
||||
/// Returns `true` if the field sequence contains no elements.
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return set_.empty();
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the field sequence.
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return set_.size();
|
||||
}
|
||||
|
||||
/// Returns a const iterator to the beginning of the field sequence.
|
||||
const_iterator
|
||||
begin() const
|
||||
@@ -304,16 +290,13 @@ private:
|
||||
#endif
|
||||
|
||||
string_view
|
||||
method() const
|
||||
{
|
||||
return (*this)[":method"];
|
||||
}
|
||||
method() const;
|
||||
|
||||
void
|
||||
method(string_view const& s)
|
||||
{
|
||||
return this->replace(":method", s);
|
||||
}
|
||||
method(verb v);
|
||||
|
||||
void
|
||||
method(string_view const& s);
|
||||
|
||||
string_view
|
||||
target() const
|
||||
|
||||
@@ -100,6 +100,7 @@ basic_fields(basic_fields&& other)
|
||||
std::move(other.member()))
|
||||
, detail::basic_fields_base(
|
||||
std::move(other.set_), std::move(other.list_))
|
||||
, verb_(other.verb_)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -114,6 +115,7 @@ operator=(basic_fields&& other) ->
|
||||
clear();
|
||||
move_assign(other, std::integral_constant<bool,
|
||||
alloc_traits::propagate_on_container_move_assignment::value>{});
|
||||
verb_ = other.verb_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -124,6 +126,7 @@ basic_fields(basic_fields const& other)
|
||||
select_on_container_copy_construction(other.member()))
|
||||
{
|
||||
copy_from(other);
|
||||
verb_ = other.verb_;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
@@ -135,6 +138,7 @@ operator=(basic_fields const& other) ->
|
||||
clear();
|
||||
copy_assign(other, std::integral_constant<bool,
|
||||
alloc_traits::propagate_on_container_copy_assignment::value>{});
|
||||
verb_ = other.verb_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -144,6 +148,7 @@ basic_fields<Allocator>::
|
||||
basic_fields(basic_fields<OtherAlloc> const& other)
|
||||
{
|
||||
copy_from(other);
|
||||
verb_ = other.verb_;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
@@ -155,18 +160,10 @@ operator=(basic_fields<OtherAlloc> const& other) ->
|
||||
{
|
||||
clear();
|
||||
copy_from(other);
|
||||
verb_ = other.verb_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
template<class FwdIt>
|
||||
basic_fields<Allocator>::
|
||||
basic_fields(FwdIt first, FwdIt last)
|
||||
{
|
||||
for(;first != last; ++first)
|
||||
insert(first->name(), first->value());
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
basic_fields<Allocator>::
|
||||
@@ -260,6 +257,37 @@ replace(string_view const& name,
|
||||
insert(name, value);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
string_view
|
||||
basic_fields<Allocator>::
|
||||
method() const
|
||||
{
|
||||
if(verb_)
|
||||
return to_string(*verb_);
|
||||
return (*this)[":method"];
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
method(verb v)
|
||||
{
|
||||
verb_ = v;
|
||||
this->erase(":method");
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
method(string_view const& s)
|
||||
{
|
||||
verb_ = string_to_verb(s);
|
||||
if(verb_)
|
||||
this->erase(":method");
|
||||
else
|
||||
this->replace(":method", s);
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
//
|
||||
// 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";
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(std::logic_error{"unknown method"});
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
boost::optional<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 boost::none;
|
||||
auto const eq =
|
||||
[](string_view sv, char const* s)
|
||||
{
|
||||
auto p = sv.data();
|
||||
for(;;)
|
||||
{
|
||||
if(*s != *p)
|
||||
return false;
|
||||
++s;
|
||||
++p;
|
||||
if(*s == 0)
|
||||
return *p == 0;
|
||||
}
|
||||
};
|
||||
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 boost::none;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
inline
|
||||
string_view
|
||||
to_string(verb v)
|
||||
{
|
||||
return detail::verb_to_string(v);
|
||||
}
|
||||
|
||||
inline
|
||||
boost::optional<verb>
|
||||
string_to_verb(string_view s)
|
||||
{
|
||||
return detail::string_to_verb(s);
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// 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_VERB_HPP
|
||||
#define BEAST_HTTP_VERB_HPP
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** HTTP request method verbs
|
||||
|
||||
Each verb corresponds to a particular method string
|
||||
used in HTTP request messages.
|
||||
*/
|
||||
enum class verb
|
||||
{
|
||||
/// The DELETE method deletes the specified resource
|
||||
delete_ = 1,
|
||||
|
||||
/** The GET method requests a representation of the specified resource.
|
||||
|
||||
Requests using GET should only retrieve data and should have no other effect.
|
||||
*/
|
||||
get,
|
||||
|
||||
/** The HEAD method asks for a response identical to that of a GET request, but without the response body.
|
||||
|
||||
This is useful for retrieving meta-information written in response
|
||||
headers, without having to transport the entire content.
|
||||
*/
|
||||
head,
|
||||
|
||||
/** The POST method requests that the server accept the entity enclosed in the request as a new subordinate of the web resource identified by the URI.
|
||||
|
||||
The data POSTed might be, for example, an annotation for existing
|
||||
resources; a message for a bulletin board, newsgroup, mailing list,
|
||||
or comment thread; a block of data that is the result of submitting
|
||||
a web form to a data-handling process; or an item to add to a database
|
||||
*/
|
||||
post,
|
||||
|
||||
/** The PUT method requests that the enclosed entity be stored under the supplied URI.
|
||||
|
||||
If the URI refers to an already existing resource, it is modified;
|
||||
if the URI does not point to an existing resource, then the server
|
||||
can create the resource with that URI.
|
||||
*/
|
||||
put,
|
||||
|
||||
/** The CONNECT method converts the request connection to a transparent TCP/IP tunnel.
|
||||
|
||||
This is usually to facilitate SSL-encrypted communication (HTTPS)
|
||||
through an unencrypted HTTP proxy.
|
||||
*/
|
||||
connect,
|
||||
|
||||
/** The OPTIONS method returns the HTTP methods that the server supports for the specified URL.
|
||||
|
||||
This can be used to check the functionality of a web server by requesting
|
||||
'*' instead of a specific resource.
|
||||
*/
|
||||
options,
|
||||
|
||||
/** The TRACE method echoes the received request so that a client can see what (if any) changes or additions have been made by intermediate servers.
|
||||
*/
|
||||
trace,
|
||||
|
||||
// WebDAV
|
||||
|
||||
copy,
|
||||
lock,
|
||||
mkcol,
|
||||
move,
|
||||
propfind,
|
||||
proppatch,
|
||||
search,
|
||||
unlock,
|
||||
bind,
|
||||
rebind,
|
||||
unbind,
|
||||
acl,
|
||||
|
||||
// subversion
|
||||
|
||||
report,
|
||||
mkactivity,
|
||||
checkout,
|
||||
merge,
|
||||
|
||||
// upnp
|
||||
|
||||
msearch,
|
||||
notify,
|
||||
subscribe,
|
||||
unsubscribe,
|
||||
|
||||
// RFC-5789
|
||||
|
||||
patch,
|
||||
purge,
|
||||
|
||||
// CalDAV
|
||||
|
||||
mkcalendar,
|
||||
|
||||
// RFC-2068, section 19.6.1.2
|
||||
|
||||
link,
|
||||
unlink
|
||||
};
|
||||
|
||||
/** Converts a string to the request method verb.
|
||||
|
||||
If the string does not match a known request method,
|
||||
`boost::none` is returned.
|
||||
*/
|
||||
boost::optional<verb>
|
||||
string_to_verb(string_view s);
|
||||
|
||||
/// Returns the text representation of a request method verb.
|
||||
string_view
|
||||
to_string(verb v);
|
||||
|
||||
/// Write the text for a request method verb to an output stream.
|
||||
inline
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, verb v)
|
||||
{
|
||||
return os << to_string(v);
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/verb.ipp>
|
||||
|
||||
#endif
|
||||
@@ -164,7 +164,7 @@ build_request(detail::sec_ws_key_type& key,
|
||||
request_type req;
|
||||
req.target(target);
|
||||
req.version = 11;
|
||||
req.method("GET");
|
||||
req.method(http::verb::get);
|
||||
req.fields.insert("Host", host);
|
||||
req.fields.insert("Upgrade", "websocket");
|
||||
req.fields.insert("Connection", "upgrade");
|
||||
|
||||
Reference in new issue
Block a user