summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/src/examples/cpp03/http/server4/request_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/src/examples/cpp03/http/server4/request_parser.cpp')
-rw-r--r--3rdparty/asio/src/examples/cpp03/http/server4/request_parser.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/3rdparty/asio/src/examples/cpp03/http/server4/request_parser.cpp b/3rdparty/asio/src/examples/cpp03/http/server4/request_parser.cpp
new file mode 100644
index 00000000000..30dad0327fe
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp03/http/server4/request_parser.cpp
@@ -0,0 +1,226 @@
+//
+// request_parser.cpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff 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)
+//
+
+#include "request_parser.hpp"
+#include <algorithm>
+#include <cctype>
+#include <boost/lexical_cast.hpp>
+#include "request.hpp"
+
+namespace http {
+namespace server4 {
+
+// Enable the pseudo-keywords reenter, yield and fork.
+#include <asio/yield.hpp>
+
+std::string request_parser::content_length_name_ = "Content-Length";
+
+boost::tribool request_parser::consume(request& req, char c)
+{
+ reenter (this)
+ {
+ req.method.clear();
+ req.uri.clear();
+ req.http_version_major = 0;
+ req.http_version_minor = 0;
+ req.headers.clear();
+ req.content.clear();
+ content_length_ = 0;
+
+ // Request method.
+ while (is_char(c) && !is_ctl(c) && !is_tspecial(c) && c != ' ')
+ {
+ req.method.push_back(c);
+ yield return boost::indeterminate;
+ }
+ if (req.method.empty())
+ return false;
+
+ // Space.
+ if (c != ' ') return false;
+ yield return boost::indeterminate;
+
+ // URI.
+ while (!is_ctl(c) && c != ' ')
+ {
+ req.uri.push_back(c);
+ yield return boost::indeterminate;
+ }
+ if (req.uri.empty()) return false;
+
+ // Space.
+ if (c != ' ') return false;
+ yield return boost::indeterminate;
+
+ // HTTP protocol identifier.
+ if (c != 'H') return false;
+ yield return boost::indeterminate;
+ if (c != 'T') return false;
+ yield return boost::indeterminate;
+ if (c != 'T') return false;
+ yield return boost::indeterminate;
+ if (c != 'P') return false;
+ yield return boost::indeterminate;
+
+ // Slash.
+ if (c != '/') return false;
+ yield return boost::indeterminate;
+
+ // Major version number.
+ if (!is_digit(c)) return false;
+ while (is_digit(c))
+ {
+ req.http_version_major = req.http_version_major * 10 + c - '0';
+ yield return boost::indeterminate;
+ }
+
+ // Dot.
+ if (c != '.') return false;
+ yield return boost::indeterminate;
+
+ // Minor version number.
+ if (!is_digit(c)) return false;
+ while (is_digit(c))
+ {
+ req.http_version_minor = req.http_version_minor * 10 + c - '0';
+ yield return boost::indeterminate;
+ }
+
+ // CRLF.
+ if (c != '\r') return false;
+ yield return boost::indeterminate;
+ if (c != '\n') return false;
+ yield return boost::indeterminate;
+
+ // Headers.
+ while ((is_char(c) && !is_ctl(c) && !is_tspecial(c) && c != '\r')
+ || (c == ' ' || c == '\t'))
+ {
+ if (c == ' ' || c == '\t')
+ {
+ // Leading whitespace. Must be continuation of previous header's value.
+ if (req.headers.empty()) return false;
+ while (c == ' ' || c == '\t')
+ yield return boost::indeterminate;
+ }
+ else
+ {
+ // Start the next header.
+ req.headers.push_back(header());
+
+ // Header name.
+ while (is_char(c) && !is_ctl(c) && !is_tspecial(c) && c != ':')
+ {
+ req.headers.back().name.push_back(c);
+ yield return boost::indeterminate;
+ }
+
+ // Colon and space separates the header name from the header value.
+ if (c != ':') return false;
+ yield return boost::indeterminate;
+ if (c != ' ') return false;
+ yield return boost::indeterminate;
+ }
+
+ // Header value.
+ while (is_char(c) && !is_ctl(c) && c != '\r')
+ {
+ req.headers.back().value.push_back(c);
+ yield return boost::indeterminate;
+ }
+
+ // CRLF.
+ if (c != '\r') return false;
+ yield return boost::indeterminate;
+ if (c != '\n') return false;
+ yield return boost::indeterminate;
+ }
+
+ // CRLF.
+ if (c != '\r') return false;
+ yield return boost::indeterminate;
+ if (c != '\n') return false;
+
+ // Check for optional Content-Length header.
+ for (std::size_t i = 0; i < req.headers.size(); ++i)
+ {
+ if (headers_equal(req.headers[i].name, content_length_name_))
+ {
+ try
+ {
+ content_length_ =
+ boost::lexical_cast<std::size_t>(req.headers[i].value);
+ }
+ catch (boost::bad_lexical_cast&)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Content.
+ while (req.content.size() < content_length_)
+ {
+ yield return boost::indeterminate;
+ req.content.push_back(c);
+ }
+ }
+
+ return true;
+}
+
+// Disable the pseudo-keywords reenter, yield and fork.
+#include <asio/unyield.hpp>
+
+bool request_parser::is_char(int c)
+{
+ return c >= 0 && c <= 127;
+}
+
+bool request_parser::is_ctl(int c)
+{
+ return (c >= 0 && c <= 31) || (c == 127);
+}
+
+bool request_parser::is_tspecial(int c)
+{
+ switch (c)
+ {
+ case '(': case ')': case '<': case '>': case '@':
+ case ',': case ';': case ':': case '\\': case '"':
+ case '/': case '[': case ']': case '?': case '=':
+ case '{': case '}': case ' ': case '\t':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool request_parser::is_digit(int c)
+{
+ return c >= '0' && c <= '9';
+}
+
+bool request_parser::tolower_compare(char a, char b)
+{
+ return std::tolower(a) == std::tolower(b);
+}
+
+bool request_parser::headers_equal(const std::string& a, const std::string& b)
+{
+ if (a.length() != b.length())
+ return false;
+
+ return std::equal(a.begin(), a.end(), b.begin(),
+ &request_parser::tolower_compare);
+}
+
+} // namespace server4
+} // namespace http