diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index 7457615ce..9213f98a0 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -351,6 +351,8 @@
+
+
@@ -378,26 +380,34 @@
-
+
True
True
+
+ True
+
True
True
-
-
+
+
+
+
+
+ True
+
True
@@ -407,6 +417,9 @@
True
+
+ True
+
True
@@ -3067,8 +3080,6 @@
-
-
True
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index f5fb75f2a..846d48ee5 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -915,6 +915,9 @@
beast
+
+ beast\http
+
beast\http
@@ -948,30 +951,39 @@
beast\http\impl
-
+
beast\http\impl
beast\http\impl
+
+ beast\http\impl
+
beast\http\impl
beast\http\impl
-
- beast\http
-
beast\http
beast\http
+
+ beast\http
+
beast\http
+
+ beast\http
+
+
+ beast\http\tests
+
beast\http\tests
@@ -981,6 +993,9 @@
beast\http\tests
+
+ beast\http\tests
+
beast\http\tests
@@ -4236,9 +4251,6 @@
ripple\overlay\impl
-
- ripple\overlay\impl
-
ripple\overlay\impl
diff --git a/src/beast/beast/http/HTTP.unity.cpp b/src/beast/beast/http/HTTP.unity.cpp
index 07bd3cd69..0e748e61c 100644
--- a/src/beast/beast/http/HTTP.unity.cpp
+++ b/src/beast/beast/http/HTTP.unity.cpp
@@ -24,13 +24,16 @@
#include
#include
#include
-#include
+#include
#include
+#include
#include
#include
+#include
#include
#include
#include
+#include
#include
diff --git a/src/beast/beast/http/basic_message.h b/src/beast/beast/http/basic_message.h
new file mode 100644
index 000000000..84629466c
--- /dev/null
+++ b/src/beast/beast/http/basic_message.h
@@ -0,0 +1,509 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_HTTP_MESSAGE_H_INCLUDED
+#define BEAST_HTTP_MESSAGE_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+class basic_message
+{
+public:
+ class parser;
+
+ typedef boost::system::error_code error_code;
+
+private:
+ class element
+ : public boost::intrusive::set_base_hook <
+ boost::intrusive::link_mode <
+ boost::intrusive::normal_link>
+ >
+ , public boost::intrusive::list_base_hook <
+ boost::intrusive::link_mode <
+ boost::intrusive::normal_link>
+ >
+ {
+ public:
+ element (std::string const& f, std::string const& v)
+ : field (f)
+ , value (v)
+ {
+ }
+
+ std::string field;
+ std::string value;
+ };
+
+ struct less : private beast::ci_less
+ {
+ template
+ bool
+ operator() (String const& lhs, element const& rhs) const
+ {
+ return beast::ci_less::operator() (lhs, rhs.field);
+ }
+
+ template
+ bool
+ operator() (element const& lhs, String const& rhs) const
+ {
+ return beast::ci_less::operator() (lhs.field, rhs);
+ }
+ };
+
+ class headers_t : private less
+ {
+ private:
+ typedef boost::intrusive::make_list
+ >::type list_t;
+
+ typedef boost::intrusive::make_set
+ >::type set_t;
+
+ list_t list_;
+ set_t set_;
+
+ public:
+ typedef list_t::const_iterator iterator;
+
+ ~headers_t()
+ {
+ clear();
+ }
+
+ headers_t() = default;
+
+ headers_t (headers_t&& other)
+ : list_ (std::move(other.list_))
+ , set_ (std::move(other.set_))
+ {
+
+ }
+
+ headers_t (headers_t const& other)
+ {
+ for (auto const& e : other.list_)
+ append (e.field, e.value);
+ }
+
+ headers_t&
+ operator= (headers_t&& other)
+ {
+ list_ = std::move(other.list_);
+ set_ = std::move(other.set_);
+ }
+
+ headers_t&
+ operator= (headers_t const& other)
+ {
+ clear();
+ for (auto const& e : other.list_)
+ append (e.field, e.value);
+ }
+
+ void
+ clear()
+ {
+ for (auto iter (list_.begin()); iter != list_.end();)
+ {
+ element* const p (&*iter);
+ ++iter;
+ delete p;
+ }
+ }
+
+ iterator
+ begin() const
+ {
+ return list_.cbegin();
+ }
+
+ iterator
+ end() const
+ {
+ return list_.cend();
+ }
+
+ iterator
+ cbegin() const
+ {
+ return list_.cbegin();
+ }
+
+ iterator
+ cend() const
+ {
+ return list_.cend();
+ }
+
+ iterator
+ find (std::string const& field) const
+ {
+ auto const iter (set_.find (field,
+ std::cref(static_cast(*this))));
+ if (iter == set_.end())
+ return list_.end();
+ return list_.iterator_to (*iter);
+ }
+
+ std::string const&
+ operator[] (std::string const& field) const
+ {
+ static std::string none;
+ auto const found (find (field));
+ if (found == end())
+ return none;
+ return found->value;
+ }
+
+ void
+ append (std::string const& field, std::string const& value)
+ {
+ set_t::insert_commit_data d;
+ auto const result (set_.insert_check (field,
+ std::cref(static_cast(*this)), d));
+ if (result.second)
+ {
+ element* const p (new element (field, value));
+ list_.push_back (*p);
+ auto const iter (set_.insert_commit (*p, d));
+ return;
+ }
+ // If field already exists, append comma
+ // separated value as per RFC2616 section 4.2
+ auto& cur (result.first->value);
+ cur.reserve (cur.size() + 1 + value.size());
+ cur.append (1, ',');
+ cur.append (value);
+ }
+ };
+
+ bool request_;
+
+ // request
+ beast::http::method_t method_;
+ std::string url_;
+
+ // response
+ int status_;
+ std::string reason_;
+
+ // message
+ std::pair version_;
+ bool keep_alive_;
+ bool upgrade_;
+
+public:
+ ~basic_message() = default;
+
+ basic_message()
+ : request_ (true)
+ , method_ (beast::http::method_t::http_get)
+ , url_ ("/")
+ , status_ (200)
+ , version_ (1, 1)
+ , keep_alive_ (false)
+ , upgrade_ (false)
+ {
+ }
+
+ basic_message (basic_message&& other)
+ : request_ (true)
+ , method_ (std::move(other.method_))
+ , url_ (std::move(other.url_))
+ , status_ (other.status_)
+ , reason_ (std::move(other.reason_))
+ , version_ (other.version_)
+ , keep_alive_ (other.keep_alive_)
+ , upgrade_ (other.upgrade_)
+ , headers (std::move(other.headers))
+ {
+ }
+
+ bool
+ request() const
+ {
+ return request_;
+ }
+
+ void
+ request (bool value)
+ {
+ request_ = value;
+ }
+
+ // Request
+
+ void
+ method (beast::http::method_t http_method)
+ {
+ method_ = http_method;
+ }
+
+ beast::http::method_t
+ method() const
+ {
+ return method_;
+ }
+
+ void
+ url (std::string const& s)
+ {
+ url_ = s;
+ }
+
+ std::string const&
+ url() const
+ {
+ return url_;
+ }
+
+ /** Returns `false` if this is not the last message.
+ When keep_alive returns `false`:
+ * Server roles respond with a "Connection: close" header.
+ * Client roles close the connection.
+ */
+ bool
+ keep_alive() const
+ {
+ return keep_alive_;
+ }
+
+ /** Set the keep_alive setting. */
+ void
+ keep_alive (bool value)
+ {
+ keep_alive_ = value;
+ }
+
+ /** Returns `true` if this is an HTTP Upgrade message.
+ @note Upgrade messages have no content body.
+ */
+ bool
+ upgrade() const
+ {
+ return upgrade_;
+ }
+
+ /** Set the upgrade setting. */
+ void
+ upgrade (bool value)
+ {
+ upgrade_ = value;
+ }
+
+ int
+ status() const
+ {
+ return status_;
+ }
+
+ void
+ status (int code)
+ {
+ status_ = code;
+ }
+
+ std::string const&
+ reason() const
+ {
+ return reason_;
+ }
+
+ void
+ reason (std::string const& text)
+ {
+ reason_ = text;
+ }
+
+ // Message
+
+ void
+ version (int major, int minor)
+ {
+ version_ = std::make_pair (major, minor);
+ }
+
+ std::pair
+ version() const
+ {
+ return version_;
+ }
+
+ // Memberspace
+ headers_t headers;
+};
+
+//------------------------------------------------------------------------------
+
+class basic_message::parser : public beast::http::parser
+{
+private:
+ basic_message& message_;
+
+public:
+ parser (basic_message& message, bool request)
+ : beast::http::parser (request)
+ , message_ (message)
+ {
+ message_.request(request);
+ }
+
+private:
+ void
+ on_start () override
+ {
+ }
+
+ bool
+ on_request (method_t method, std::string const& url,
+ int major, int minor, bool keep_alive, bool upgrade) override
+ {
+ message_.method (method);
+ message_.url (url);
+ message_.version (major, minor);
+ message_.keep_alive(keep_alive);
+ message_.upgrade(upgrade);
+ return upgrade ? false : false;
+ }
+
+ bool
+ on_response (int status, std::string const& text,
+ int major, int minor, bool keep_alive, bool upgrade) override
+ {
+ message_.status (status);
+ message_.reason (text);
+ message_.version (major, minor);
+ message_.keep_alive(keep_alive);
+ message_.upgrade(upgrade);
+ return upgrade ? false : false;
+ }
+
+ void
+ on_field (std::string const& field, std::string const& value) override
+ {
+ message_.headers.append (field, value);
+ }
+
+ void
+ on_body (void const* data, std::size_t bytes) override
+ {
+ }
+
+ void
+ on_complete() override
+ {
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template
+void
+xwrite (AsioStreamBuf& stream, std::string const& s)
+{
+ stream.commit (boost::asio::buffer_copy (
+ stream.prepare (s.size()), boost::asio::buffer(s)));
+}
+
+template
+void
+xwrite (AsioStreamBuf& stream, char const* s)
+{
+ auto const len (::strlen(s));
+ stream.commit (boost::asio::buffer_copy (
+ stream.prepare (len), boost::asio::buffer (s, len)));
+}
+
+template
+void
+xwrite (AsioStreamBuf& stream, basic_message const& m)
+{
+ if (m.request())
+ {
+ xwrite (stream, to_string(m.method()));
+ xwrite (stream, " ");
+ xwrite (stream, m.url());
+ xwrite (stream, " HTTP/");
+ xwrite (stream, std::to_string(m.version().first));
+ xwrite (stream, ".");
+ xwrite (stream, std::to_string(m.version().second));
+ }
+ else
+ {
+ xwrite (stream, "HTTP/");
+ xwrite (stream, std::to_string(m.version().first));
+ xwrite (stream, ".");
+ xwrite (stream, std::to_string(m.version().second));
+ xwrite (stream, " ");
+ xwrite (stream, std::to_string(m.status()));
+ xwrite (stream, " ");
+ xwrite (stream, m.reason());
+ }
+ xwrite (stream, "\r\n");
+ for (auto const& header : m.headers)
+ {
+ xwrite (stream, header.field);
+ xwrite (stream, ": ");
+ xwrite (stream, header.value);
+ xwrite (stream, "\r\n");
+ }
+ xwrite (stream, "\r\n");
+}
+
+template
+std::string
+to_string (basic_message const& m)
+{
+ std::stringstream ss;
+ if (m.request())
+ ss << to_string(m.method()) << " " << m.url() << " HTTP/" <<
+ std::to_string(m.version().first) << "." <<
+ std::to_string(m.version().second) << "\r\n";
+ else
+ ss << "HTTP/" << std::to_string(m.version().first) << "." <<
+ std::to_string(m.version().second) << " " <<
+ std::to_string(m.status()) << " " << m.reason() << "\r\n";
+ for (auto const& header : m.headers)
+ ss << header.field << ": " << header.value << "\r\n";
+ ss << "\r\n";
+ return ss.str();
+}
+
+} // http
+} // beast
+
+#endif
\ No newline at end of file
diff --git a/src/beast/beast/http/impl/message_parser.cpp b/src/beast/beast/http/impl/message_parser.cpp
deleted file mode 100644
index 61db041d4..000000000
--- a/src/beast/beast/http/impl/message_parser.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of Beast: https://github.com/vinniefalco/Beast
- Copyright 2013, Vinnie Falco
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-//==============================================================================
-
-#include
-#include
-
-namespace beast {
-namespace http {
-
-message_parser::message_parser (bool request)
- : complete_ (false)
- , checked_url_ (false)
-{
- static_assert (sizeof(joyent::http_parser) == sizeof(state_t),
- "state_t size must match http_parser size");
-
- static_assert (sizeof(joyent::http_parser_settings) == sizeof(hooks_t),
- "hooks_t size must match http_parser_settings size");
-
- auto s (reinterpret_cast (&state_));
- s->data = this;
-
- auto h (reinterpret_cast (&hooks_));
- h->on_message_begin = &message_parser::cb_message_start;
- h->on_url = &message_parser::cb_url;
- h->on_status = &message_parser::cb_status;
- h->on_header_field = &message_parser::cb_header_field;
- h->on_header_value = &message_parser::cb_header_value;
- h->on_headers_complete = &message_parser::cb_headers_done;
- h->on_body = &message_parser::cb_body;
- h->on_message_complete = &message_parser::cb_message_complete;
-
- joyent::http_parser_init (s, request
- ? joyent::http_parser_type::HTTP_REQUEST
- : joyent::http_parser_type::HTTP_RESPONSE);
-}
-
-std::pair
-message_parser::write_one (void const* in, std::size_t bytes)
-{
- std::pair result (error_code(), 0);
- auto s (reinterpret_cast (&state_));
- auto h (reinterpret_cast (&hooks_));
- result.second = joyent::http_parser_execute (s, h,
- static_cast (in), bytes);
- result.first = ec_;
- return result;
-}
-
-//------------------------------------------------------------------------------
-
-int
-message_parser::check_url()
-{
- if (! checked_url_)
- {
- checked_url_ = true;
- auto const p (reinterpret_cast (&state_));
- ec_ = on_request (
- joyent::convert_http_method (joyent::http_method(p->method)),
- p->http_major, p->http_minor, url_);
- if (ec_)
- return 1;
- }
- return 0;
-}
-
-int
-message_parser::do_message_start ()
-{
- return ec_ ? 1 : 0;
-}
-
-int
-message_parser::do_url (char const* in, std::size_t bytes)
-{
- url_.append (static_cast (in), bytes);
- return 0;
-}
-
-int
-message_parser::do_status (char const* in, std::size_t bytes)
-{
- return ec_ ? 1 : 0;
-}
-
-int
-message_parser::do_header_field (char const* in, std::size_t bytes)
-{
- if (check_url())
- return 1;
- if (! value_.empty())
- {
- ec_ = on_field (field_, value_);
- if (ec_)
- return 1;
- field_.clear();
- value_.clear();
- }
- field_.append (static_cast (in), bytes);
- return 0;
-}
-
-int
-message_parser::do_header_value (char const* in, std::size_t bytes)
-{
- value_.append (static_cast (in), bytes);
- return 0;
-}
-
-// Returning 1 from here tells the joyent parser
-// that the message has no body (e.g. a HEAD request).
-//
-int
-message_parser::do_headers_done ()
-{
- if (check_url())
- return 1;
- if (! value_.empty())
- {
- ec_ = on_field (field_, value_);
- if (ec_)
- return 1;
- field_.clear();
- value_.clear();
- }
- return ec_ ? 1 : 0;
-}
-
-int
-message_parser::do_body (char const* in, std::size_t bytes)
-{
- return ec_ ? 1 : 0;
-}
-
-int
-message_parser::do_message_complete ()
-{
- complete_ = true;
- return 0;
-}
-
-//------------------------------------------------------------------------------
-
-int
-message_parser::cb_message_start (joyent::http_parser* p)
-{
- return reinterpret_cast (
- p->data)->do_message_start();
-}
-
-int
-message_parser::cb_url (joyent::http_parser* p,
- char const* in, std::size_t bytes)
-{
- return reinterpret_cast (
- p->data)->do_url (in, bytes);
-}
-
-int
-message_parser::cb_status (joyent::http_parser* p,
- char const* in, std::size_t bytes)
-{
- return reinterpret_cast (
- p->data)->do_status (in, bytes);
-}
-
-int
-message_parser::cb_header_field (joyent::http_parser* p,
- char const* in, std::size_t bytes)
-{
- return reinterpret_cast (
- p->data)->do_header_field (in, bytes);
-}
-
-int
-message_parser::cb_header_value (joyent::http_parser* p,
- char const* in, std::size_t bytes)
-{
- return reinterpret_cast (
- p->data)->do_header_value (in, bytes);
-}
-
-int
-message_parser::cb_headers_done (joyent::http_parser* p)
-{
- return reinterpret_cast (
- p->data)->do_headers_done();
-}
-
-int
-message_parser::cb_body (joyent::http_parser* p,
- char const* in, std::size_t bytes)
-{
- return reinterpret_cast (
- p->data)->do_body (
- in, bytes);
-}
-
-int
-message_parser::cb_message_complete (joyent::http_parser* p)
-{
- return reinterpret_cast (
- p->data)->do_message_complete();
-}
-
-} // http
-} // beast
diff --git a/src/beast/beast/http/impl/method.cpp b/src/beast/beast/http/impl/method.cpp
new file mode 100644
index 000000000..9cc119c19
--- /dev/null
+++ b/src/beast/beast/http/impl/method.cpp
@@ -0,0 +1,124 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013: Vinnie Falco
+
+ Permission to use: copy: modify: and/or distribute this software for any
+ purpose with or without fee is hereby granted: provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL : DIRECT: INDIRECT: OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE: DATA OR PROFITS: WHETHER IN AN
+ ACTION OF CONTRACT: NEGLIGENCE OR OTHER TORTIOUS ACTION: ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+
+namespace beast {
+namespace http {
+
+std::string
+to_string (method_t m)
+{
+ switch(m)
+ {
+ case method_t::http_delete: return "DELETE";
+ case method_t::http_get: return "GET";
+ case method_t::http_head: return "HEAD";
+ case method_t::http_post: return "POST";
+ case method_t::http_put: return "PUT";
+
+ case method_t::http_connect: return "CONNECT";
+ case method_t::http_options: return "OPTIONS";
+ case method_t::http_trace: return "TRACE";
+
+ case method_t::http_copy: return "COPY";
+ case method_t::http_lock: return "LOCK";
+ case method_t::http_mkcol: return "MKCOL";
+ case method_t::http_move: return "MOVE";
+ case method_t::http_propfind: return "PROPFIND";
+ case method_t::http_proppatch: return "PROPPATCH";
+ case method_t::http_search: return "SEARCH";
+ case method_t::http_unlock: return "UNLOCK";
+
+ case method_t::http_report: return "REPORT";
+ case method_t::http_mkactivity: return "MKACTIVITY";
+ case method_t::http_checkout: return "CHECKOUT";
+ case method_t::http_merge: return "MERGE";
+
+ case method_t::http_msearch: return "MSEARCH";
+ case method_t::http_notify: return "NOTIFY";
+ case method_t::http_subscribe: return "SUBSCRIBE";
+ case method_t::http_unsubscribe: return "UNSUBSCRIBE";
+
+ case method_t::http_patch: return "PATCH";
+ case method_t::http_purge: return "PURGE";
+
+ default:
+ assert(false);
+ break;
+ };
+
+ return "GET";
+}
+
+std::string
+status_text (int status)
+{
+ switch(status)
+ {
+ case 100: return "Continue";
+ case 101: return "Switching Protocols";
+ case 200: return "OK";
+ case 201: return "Created";
+ case 202: return "Accepted";
+ case 203: return "Non-Authoritative Information";
+ case 204: return "No Content";
+ case 205: return "Reset Content";
+ case 206: return "Partial Content";
+ case 300: return "Multiple Choices";
+ case 301: return "Moved Permanently";
+ case 302: return "Found";
+ case 303: return "See Other";
+ case 304: return "Not Modified";
+ case 305: return "Use Proxy";
+ //case 306: return "";
+ case 307: return "Temporary Redirect";
+ case 400: return "Bad Request";
+ case 401: return "Unauthorized";
+ case 402: return "Payment Required";
+ case 403: return "Forbidden";
+ case 404: return "Not Found";
+ case 405: return "Method Not Allowed";
+ case 406: return "Not Acceptable";
+ case 407: return "Proxy Authentication Required";
+ case 408: return "Request Timeout";
+ case 409: return "Conflict";
+ case 410: return "Gone";
+ case 411: return "Length Required";
+ case 412: return "Precondition Failed";
+ case 413: return "Request Entity Too Large";
+ case 414: return "Request-URI Too Long";
+ case 415: return "Unsupported Media Type";
+ case 416: return "Requested Range Not Satisfiable";
+ case 417: return "Expectation Failed";
+ case 500: return "Internal Server Error";
+ case 501: return "Not Implemented";
+ case 502: return "Bad Gateway";
+ case 503: return "Service Unavailable";
+ case 504: return "Gateway Timeout";
+ case 505: return "HTTP Version Not Supported";
+ default:
+ break;
+ }
+ return "Unknown HTTP status";
+}
+
+}
+}
diff --git a/src/beast/beast/http/impl/parser.cpp b/src/beast/beast/http/impl/parser.cpp
new file mode 100644
index 000000000..d34709c1b
--- /dev/null
+++ b/src/beast/beast/http/impl/parser.cpp
@@ -0,0 +1,232 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+parser::parser (bool request)
+{
+ static_assert (sizeof(joyent::http_parser) == sizeof(state_t),
+ "state_t size must match http_parser size");
+
+ static_assert (sizeof(joyent::http_parser_settings) == sizeof(hooks_t),
+ "hooks_t size must match http_parser_settings size");
+
+ auto s (reinterpret_cast (&state_));
+ s->data = this;
+
+ auto h (reinterpret_cast (&hooks_));
+ h->on_message_begin = &parser::cb_message_start;
+ h->on_url = &parser::cb_url;
+ h->on_status = &parser::cb_status;
+ h->on_header_field = &parser::cb_header_field;
+ h->on_header_value = &parser::cb_header_value;
+ h->on_headers_complete = &parser::cb_headers_complete;
+ h->on_body = &parser::cb_body;
+ h->on_message_complete = &parser::cb_message_complete;
+
+ joyent::http_parser_init (s, request
+ ? joyent::http_parser_type::HTTP_REQUEST
+ : joyent::http_parser_type::HTTP_RESPONSE);
+}
+
+std::pair
+parser::write (void const* data, std::size_t bytes)
+{
+ std::pair result (error_code(), 0);
+ auto s (reinterpret_cast (&state_));
+ auto h (reinterpret_cast (&hooks_));
+ result.second = joyent::http_parser_execute (s, h,
+ static_cast (data), bytes);
+ result.first = ec_;
+ return result;
+}
+
+parser::error_code
+parser::eof()
+{
+ auto s (reinterpret_cast (&state_));
+ auto h (reinterpret_cast (&hooks_));
+ joyent::http_parser_execute (s, h, nullptr, 0);
+ return ec_;
+}
+
+//------------------------------------------------------------------------------
+
+void
+parser::check_header()
+{
+ if (! value_.empty())
+ {
+ rfc2616::trim_right_in_place (value_);
+ on_field (field_, value_);
+ field_.clear();
+ value_.clear();
+ }
+}
+
+int
+parser::do_message_start ()
+{
+ complete_ = false;
+ url_.clear();
+ status_.clear();
+ field_.clear();
+ value_.clear();
+ on_start();
+ return 0;
+}
+
+int
+parser::do_url (char const* in, std::size_t bytes)
+{
+ url_.append (static_cast (in), bytes);
+ return 0;
+}
+
+int
+parser::do_status (char const* in, std::size_t bytes)
+{
+ status_.append (static_cast (in), bytes);
+ return 0;
+}
+
+int
+parser::do_header_field (char const* in, std::size_t bytes)
+{
+ check_header();
+ field_.append (static_cast (in), bytes);
+ return 0;
+}
+
+int
+parser::do_header_value (char const* in, std::size_t bytes)
+{
+ value_.append (static_cast (in), bytes);
+ return 0;
+}
+
+/* Called when all the headers are complete but before
+ the content body, if present.
+ Returning 1 from here tells the joyent parser
+ that the message has no body (e.g. a HEAD request).
+*/
+int
+parser::do_headers_complete()
+{
+ check_header();
+ auto const p (reinterpret_cast (&state_));
+ bool const keep_alive (joyent::http_should_keep_alive (p) != 0);
+ if (p->type == joyent::http_parser_type::HTTP_REQUEST)
+ return on_request (joyent::convert_http_method (
+ joyent::http_method(p->method)), url_,
+ p->http_major, p->http_minor, keep_alive, p->upgrade) ? 0 : 1;
+ return on_response (p->status_code, status_,
+ p->http_major, p->http_minor, keep_alive, p->upgrade) ? 0 : 1;
+}
+
+/* Called repeatedly for the content body. The passed buffer
+ has already had the transfer-encoding removed.
+*/
+int
+parser::do_body (char const* in, std::size_t bytes)
+{
+ on_body (in, bytes);
+ return 0;
+}
+
+/* Called when the both the headers and content body (if any) are complete. */
+int
+parser::do_message_complete ()
+{
+ complete_ = true;
+ on_complete();
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+
+int
+parser::cb_message_start (joyent::http_parser* p)
+{
+ return reinterpret_cast (
+ p->data)->do_message_start();
+}
+
+int
+parser::cb_url (joyent::http_parser* p,
+ char const* in, std::size_t bytes)
+{
+ return reinterpret_cast (
+ p->data)->do_url (in, bytes);
+}
+
+int
+parser::cb_status (joyent::http_parser* p,
+ char const* in, std::size_t bytes)
+{
+ return reinterpret_cast (
+ p->data)->do_status (in, bytes);
+}
+
+int
+parser::cb_header_field (joyent::http_parser* p,
+ char const* in, std::size_t bytes)
+{
+ return reinterpret_cast (
+ p->data)->do_header_field (in, bytes);
+}
+
+int
+parser::cb_header_value (joyent::http_parser* p,
+ char const* in, std::size_t bytes)
+{
+ return reinterpret_cast (
+ p->data)->do_header_value (in, bytes);
+}
+
+int
+parser::cb_headers_complete (joyent::http_parser* p)
+{
+ return reinterpret_cast (
+ p->data)->do_headers_complete();
+}
+
+int
+parser::cb_body (joyent::http_parser* p,
+ char const* in, std::size_t bytes)
+{
+ return reinterpret_cast (
+ p->data)->do_body (
+ in, bytes);
+}
+
+int
+parser::cb_message_complete (joyent::http_parser* p)
+{
+ return reinterpret_cast (
+ p->data)->do_message_complete();
+}
+
+} // http
+} // beast
diff --git a/src/beast/beast/http/method.h b/src/beast/beast/http/method.h
index 1a95c5d44..e7f7d63c1 100644
--- a/src/beast/beast/http/method.h
+++ b/src/beast/beast/http/method.h
@@ -21,6 +21,7 @@
#define BEAST_HTTP_METHOD_H_INCLUDED
#include
+#include
namespace beast {
namespace http {
@@ -65,6 +66,20 @@ enum class method_t
http_purge
};
+std::string
+to_string (method_t m);
+
+template
+Stream&
+operator<< (Stream& s, method_t m)
+{
+ return s << to_string(m);
+}
+
+/** Returns the string corresponding to the numeric HTTP status code. */
+std::string
+status_text (int status);
+
}
}
diff --git a/src/beast/beast/http/message_parser.h b/src/beast/beast/http/parser.h
similarity index 53%
rename from src/beast/beast/http/message_parser.h
rename to src/beast/beast/http/parser.h
index 7ff7d6e24..dba185e24 100644
--- a/src/beast/beast/http/message_parser.h
+++ b/src/beast/beast/http/parser.h
@@ -17,10 +17,11 @@
*/
//==============================================================================
-#ifndef BEAST_HTTP_MESSAGE_PARSER_H_INCLUDED
-#define BEAST_HTTP_MESSAGE_PARSER_H_INCLUDED
+#ifndef BEAST_HTTP_PARSER_H_INCLUDED
+#define BEAST_HTTP_PARSER_H_INCLUDED
#include
+#include
#include
#include
#include
@@ -35,7 +36,7 @@ struct http_parser;
namespace http {
-class message_parser
+class parser
{
public:
typedef boost::system::error_code error_code;
@@ -82,9 +83,9 @@ private:
char state_ [sizeof(state_t)];
char hooks_ [sizeof(hooks_t)];
- bool complete_;
+ bool complete_ = false;
std::string url_;
- bool checked_url_;
+ std::string status_;
std::string field_;
std::string value_;
@@ -94,7 +95,7 @@ protected:
process an HTTP request.
*/
explicit
- message_parser (bool request);
+ parser (bool request);
public:
/** Returns `true` if parsing is complete.
@@ -109,18 +110,18 @@ public:
/** Write data to the parser.
The return value includes the error code if any,
and the number of bytes consumed in the input sequence.
+ @param data A buffer containing the data to write
+ @param bytes The size of the buffer pointed to by data.
*/
std::pair
- write_one (void const* in, std::size_t bytes);
-
- template
- std::pair
- write_one (ConstBuffer const& buffer)
- {
- return write_one (boost::asio::buffer_cast (buffer),
- boost::asio::buffer_size (buffer));
- }
+ write (void const* data, std::size_t bytes);
+ /** Write a set of buffer data to the parser.
+ The return value includes the error code if any,
+ and the number of bytes consumed in the input sequence.
+ @param buffers The buffers to write. These must meet the
+ requirements of ConstBufferSequence.
+ */
template
std::pair
write (ConstBufferSequence const& buffers)
@@ -129,7 +130,9 @@ public:
for (auto const& buffer : buffers)
{
std::size_t bytes_consumed;
- std::tie (result.first, bytes_consumed) = write_one (buffer);
+ std::tie (result.first, bytes_consumed) =
+ write (boost::asio::buffer_cast (buffer),
+ boost::asio::buffer_size (buffer));
if (result.first)
break;
result.second += bytes_consumed;
@@ -137,25 +140,96 @@ public:
return result;
}
-protected:
- virtual
+ /** Called to indicate the end of file.
+ HTTP needs to know where the end of the stream is. For example,
+ sometimes servers send responses without Content-Length and
+ expect the client to consume input (for the body) until EOF.
+ Callbacks and errors will still be processed as usual.
+ @note Typically this should be called when the
+ socket indicates a closure.
+ */
error_code
- on_request (method_t method, int http_major,
- int http_minor, std::string const& url) = 0;
+ eof();
+protected:
+ /** Called once when a new message begins. */
virtual
- error_code
+ void
+ on_start() = 0;
+
+ /** Called for each header field. */
+ virtual
+ void
on_field (std::string const& field, std::string const& value) = 0;
+ /** Called for requests when all the headers have been received.
+ This will precede any content body.
+ When keep_alive is false:
+ * Server roles respond with a "Connection: close" header.
+ * Client roles close the connection.
+ When upgrade is true, no content-body is expected, and the
+ return value is ignored.
+
+ @param method The HTTP method specified in the request line
+ @param major The HTTP major version number
+ @param minor The HTTP minor version number
+ @param url The URL specified in the request line
+ @param keep_alive `false` if this is the last message.
+ @param upgrade `true` if the Upgrade header is specified
+ @return `true` If upgrade is false and a content body is expected.
+ */
+ virtual
+ bool
+ on_request (method_t method, std::string const& url,
+ int major, int minor, bool keep_alive, bool upgrade) = 0;
+
+ /** Called for responses when all the headers have been received.
+ This will precede any content body.
+ When keep_alive is `false`:
+ * Client roles close the connection.
+ * Server roles respond with a "Connection: close" header.
+ When upgrade is true, no content-body is expected, and the
+ return value is ignored.
+
+ @param status The numerical HTTP status code in the response line
+ @param text The status text in the response line
+ @param major The HTTP major version number
+ @param minor The HTTP minor version number
+ @param keep_alive `false` if this is the last message.
+ @param upgrade `true` if the Upgrade header is specified
+ @return `true` If upgrade is false and a content body is expected.
+ */
+ virtual
+ bool
+ on_response (int status, std::string const& text,
+ int major, int minor, bool keep_alive, bool upgrade) = 0;
+
+ /** Called zero or more times for the content body.
+ Any transfer encoding is already decoded in the
+ memory pointed to by data.
+
+ @param data A memory block containing the next decoded
+ chunk of the content body.
+ @param bytes The number of bytes pointed to by data.
+ */
+ virtual
+ void
+ on_body (void const* data, std::size_t bytes) = 0;
+
+ /** Called once when the message is complete. */
+ virtual
+ void
+ on_complete() = 0;
+
private:
- int check_url();
+ void check_header();
int do_message_start ();
int do_url (char const* in, std::size_t bytes);
int do_status (char const* in, std::size_t bytes);
int do_header_field (char const* in, std::size_t bytes);
int do_header_value (char const* in, std::size_t bytes);
- int do_headers_done ();
+ int do_headers_complete ();
int do_body (char const* in, std::size_t bytes);
int do_message_complete ();
@@ -164,7 +238,7 @@ private:
static int cb_status (joyent::http_parser*, char const*, std::size_t);
static int cb_header_field (joyent::http_parser*, char const*, std::size_t);
static int cb_header_value (joyent::http_parser*, char const*, std::size_t);
- static int cb_headers_done (joyent::http_parser*);
+ static int cb_headers_complete (joyent::http_parser*);
static int cb_body (joyent::http_parser*, char const*, std::size_t);
static int cb_message_complete (joyent::http_parser*);
};
diff --git a/src/beast/beast/http/rfc2616.h b/src/beast/beast/http/rfc2616.h
new file mode 100644
index 000000000..caa57acab
--- /dev/null
+++ b/src/beast/beast/http/rfc2616.h
@@ -0,0 +1,239 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_HTTP_RFC2616_H_INCLUDED
+#define BEAST_HTTP_RFC2616_H_INCLUDED
+
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+/** Routines for performing RFC2616 compliance.
+ RFC2616:
+ Hypertext Transfer Protocol -- HTTP/1.1
+ http://www.w3.org/Protocols/rfc2616/rfc2616
+*/
+namespace rfc2616 {
+
+/** Returns `true` if `c` is linear white space.
+ This excludes the CRLF sequence allowed for line continuations.
+*/
+template
+bool
+is_lws (CharT c)
+{
+ return c == ' ' || c == '\t';
+}
+
+/** Returns `true` if `c` is any whitespace character. */
+template
+bool
+is_white (CharT c)
+{
+ switch (c)
+ {
+ case ' ': case '\f': case '\n':
+ case '\r': case '\t': case '\v':
+ return true;
+ };
+ return false;
+}
+
+/** Returns `true` if `c` is a control character. */
+template
+bool
+is_ctl (CharT c)
+{
+ return c <= 31 || c >= 127;
+}
+
+/** Returns `true` if `c` is a separator. */
+template
+bool
+is_sep (CharT c)
+{
+ switch (c)
+ {
+ case '(': case ')': case '<': case '>': case '@':
+ case ',': case ';': case ':': case '\\': case '"':
+ case '{': case '}': case ' ': case '\t':
+ return true;
+ };
+ return false;
+}
+
+template
+FwdIter
+trim_left (FwdIter first, FwdIter last)
+{
+ return std::find_if_not (first, last,
+ &is_white );
+}
+
+template
+FwdIter
+trim_right (FwdIter first, FwdIter last)
+{
+ if (first == last)
+ return last;
+ do
+ {
+ --last;
+ if (! is_white (*last))
+ return ++last;
+ }
+ while (last != first);
+ return first;
+}
+
+template
+void
+trim_right_in_place (std::basic_string <
+ CharT, Traits, Allocator>& s)
+{
+ s.resize (std::distance (s.begin(),
+ trim_right (s.begin(), s.end())));
+}
+
+template
+std::pair
+trim (FwdIter first, FwdIter last)
+{
+ first = trim_left (first, last);
+ last = trim_right (first, last);
+ return std::make_pair (first, last);
+}
+
+template
+String
+trim (String const& s)
+{
+ using std::begin;
+ using std::end;
+ auto first (begin(s));
+ auto last (end(s));
+ std::tie (first, last) = trim (first, last);
+ return { first, last };
+}
+
+template
+String
+trim_right (String const& s)
+{
+ using std::begin;
+ using std::end;
+ auto first (begin(s));
+ auto last (end(s));
+ last = trim_right (first, last);
+ return { first, last };
+}
+
+inline
+std::string
+trim (std::string const& s)
+{
+ return trim (s);
+}
+
+/** Call a functor for each comma delimited element.
+ Quotes and escape sequences will be parsed and converted appropriately.
+ Excess white space, commas, double quotes, and empty elements are not
+ passed to func.
+ Format:
+ #(token|quoted-string)
+ Reference:
+ http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
+*/
+template
+void
+for_each_element (FwdIter first, FwdIter last, Function func)
+{
+ FwdIter iter (first);
+ std::string e;
+ while (iter != last)
+ {
+ if (*iter == '"')
+ {
+ // quoted-string
+ ++iter;
+ while (iter != last)
+ {
+ if (*iter == '"')
+ {
+ ++iter;
+ break;
+ }
+
+ if (*iter == '\\')
+ {
+ // quoted-pair
+ ++iter;
+ if (iter != last)
+ e.append (1, *iter++);
+ }
+ else
+ {
+ // qdtext
+ e.append (1, *iter++);
+ }
+ }
+ if (! e.empty())
+ {
+ func (e);
+ e.clear();
+ }
+ }
+ else if (*iter == ',')
+ {
+ e = trim_right (e);
+ if (! e.empty())
+ {
+ func (e);
+ e.clear();
+ }
+ ++iter;
+ }
+ else if (is_lws (*iter))
+ {
+ ++iter;
+ }
+ else
+ {
+ e.append (1, *iter++);
+ }
+ }
+
+ if (! e.empty())
+ {
+ e = trim_right (e);
+ if (! e.empty())
+ func (e);
+ }
+}
+
+} // rfc2616
+
+} // http
+} // beast
+
+#endif
+
diff --git a/src/beast/beast/http/tests/basic_message.test.cpp b/src/beast/beast/http/tests/basic_message.test.cpp
index ebc036128..07bdf5d16 100644
--- a/src/beast/beast/http/tests/basic_message.test.cpp
+++ b/src/beast/beast/http/tests/basic_message.test.cpp
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
/*
- This file is part of Beast: https://github.com/vinniefalco/Beast
- Copyright 2013, Vinnie Falco
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -17,29 +17,48 @@
*/
//==============================================================================
-#if BEAST_INCLUDE_BEASTCONFIG
-#include "../../BeastConfig.h"
-#endif
-
+#include
#include
namespace beast {
namespace http {
-class basic_message_tests : public unit_test::suite
+class basic_message_test : public beast::unit_test::suite
{
public:
- void testCreate()
+ std::pair
+ request (std::string const& text)
{
- pass();
+ basic_message m;
+ basic_message::parser p (m, true);
+ auto result (p.write (boost::asio::buffer(text)));
+ auto result2 (p.eof());
+ return std::make_pair (std::move(m), result.first);
}
- void run()
+ void
+ run()
{
- testCreate();
+ auto const result = request (
+ "GET / HTTP/1.1\r\n"
+ //"Connection: Upgrade\r\n"
+ //"Upgrade: Ripple\r\n"
+ "Field: \t Value \t \r\n"
+ "Blib: Continu\r\n"
+ " ation\r\n"
+ "Field: Hey\r\n"
+ "Content-Length: 1\r\n"
+ "\r\n"
+ "x"
+ );
+
+ log << "|" << result.first.headers["Field"] << "|";
+
+ pass();
}
};
BEAST_DEFINE_TESTSUITE(basic_message,http,beast);
-}
-}
+
+} // http
+} // beast
diff --git a/src/beast/beast/http/tests/rfc2616.test.cpp b/src/beast/beast/http/tests/rfc2616.test.cpp
new file mode 100644
index 000000000..83de441d5
--- /dev/null
+++ b/src/beast/beast/http/tests/rfc2616.test.cpp
@@ -0,0 +1,93 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#if BEAST_INCLUDE_BEASTCONFIG
+#include "../../BeastConfig.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+namespace rfc2616 {
+
+class rfc2616_test : public beast::unit_test::suite
+{
+public:
+ void
+ check (std::string const& value,
+ std::vector const& expected)
+ {
+ std::vector parsed;
+ for_each_element (value.begin(), value.end(),
+ [&](std::string const& element)
+ {
+ parsed.push_back (element);
+ });
+ expect (parsed == expected);
+ }
+
+ void
+ run()
+ {
+ check ("", {});
+ check (" ", {});
+ check (" ", {});
+ check ("\t", {});
+ check (" \t ", {});
+
+ check (",", {});
+ check (",,", {});
+ check (" ,", {});
+ check (" , ,", {});
+
+ check ("x", {"x"});
+ check (" x", {"x"});
+ check (" \t x", {"x"});
+ check ("x ", {"x"});
+ check ("x \t", {"x"});
+ check (" \t x \t ", {"x"});
+
+ check ("\"\"", {});
+ check (" \"\"", {});
+ check ("\"\" ", {});
+
+ check ("\"x\"", {"x"});
+ check ("\" \"", {" "});
+ check ("\" x\"", {" x"});
+ check ("\"x \"", {"x "});
+ check ("\" x \"", {" x "});
+ check ("\"\tx \"", {"\tx "});
+
+ check ("x,y", { "x", "y" });
+ check ("x ,\ty ", { "x", "y" });
+
+ check ("x, y, z", {"x","y","z"});
+ check ("x, \"y\", z", {"x","y","z"});
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(rfc2616,http,beast);
+
+}
+}
+}
diff --git a/src/beast/beast/utility/ci_char_traits.h b/src/beast/beast/utility/ci_char_traits.h
index d319fe059..3b3493224 100644
--- a/src/beast/beast/utility/ci_char_traits.h
+++ b/src/beast/beast/utility/ci_char_traits.h
@@ -20,11 +20,54 @@
#ifndef BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
#define BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
+#include //
#include
#include
namespace beast {
+/** Case-insensitive function object for performing less than comparisons. */
+struct ci_less
+{
+ static bool const is_transparent = true;
+
+ template
+ bool
+ operator() (String const& lhs, String const& rhs) const
+ {
+ typedef typename String::value_type char_type;
+ return std::lexicographical_compare (std::begin(lhs), std::end(lhs),
+ std::begin(rhs), std::end(rhs),
+ [] (char_type lhs, char_type rhs)
+ {
+ return std::tolower(lhs) < std::tolower(rhs);
+ }
+ );
+ }
+};
+
+/** Case-insensitive function object for performing equal to comparisons. */
+struct ci_equal_to
+{
+ static bool const is_transparent = true;
+
+ template
+ bool
+ operator() (String const& lhs, String const& rhs) const
+ {
+ typedef typename String::value_type char_type;
+ return std::equal (lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
+ [] (char_type lhs, char_type rhs)
+ {
+ return std::tolower(lhs) == std::tolower(rhs);
+ }
+ );
+ }
+};
+
+// DEPRECATED VFALCO This causes far more problems than it solves!
+//
+/** Case insensitive character traits. */
struct ci_char_traits : std::char_traits
{
static
diff --git a/src/ripple/overlay/impl/basic_message.h b/src/ripple/overlay/impl/basic_message.h
deleted file mode 100644
index 897bf1396..000000000
--- a/src/ripple/overlay/impl/basic_message.h
+++ /dev/null
@@ -1,174 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2012, 2013 Ripple Labs Inc.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-//==============================================================================
-
-#ifndef RIPPLE_OVERLAY_BASIC_MESSAGE_H_INCLUDED
-#define RIPPLE_OVERLAY_BASIC_MESSAGE_H_INCLUDED
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include