From 19c4016e650bdde1911df4e1a100f8bdc77ce947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Thu, 1 Jun 2017 11:58:55 +0300 Subject: [PATCH] MXS-1220: Add to_string to HttpRequest Allowing requests to be converted to raw HTTP requests allows them to be propagated to other instances of MaxScale. This should allow multiple MaxScales to perform the same action in a coherent manner. A simple clustering mechanism needs to be added to make MaxScale aware of other instances. --- server/core/admin.cc | 2 + server/core/httprequest.cc | 76 +++++++++++++++++++++++++++++ server/core/maxscale/httprequest.hh | 15 ++++++ 3 files changed, 93 insertions(+) diff --git a/server/core/admin.cc b/server/core/admin.cc index 982d63b8b..809f01343 100644 --- a/server/core/admin.cc +++ b/server/core/admin.cc @@ -105,6 +105,8 @@ int Client::process(string url, string method, const char* upload_data, size_t * HttpRequest request(m_connection, url, method, json); HttpResponse reply(MHD_HTTP_NOT_FOUND); + MXS_DEBUG("Request:\n%s", request.to_string().c_str()); + if (url == "/") { // Respond to pings with 200 OK diff --git a/server/core/httprequest.cc b/server/core/httprequest.cc index d3e8ac463..26408b858 100644 --- a/server/core/httprequest.cc +++ b/server/core/httprequest.cc @@ -16,6 +16,7 @@ #include #include +#include using std::string; using std::deque; @@ -128,3 +129,78 @@ bool HttpRequest::validate_api_version() return rval; } + +namespace +{ +struct ValueFormatter +{ + std::stringstream ss; + const char* separator; + const char* terminator; + + ValueFormatter(const char* sep, const char* term): + separator(sep), terminator(term) + { + } +}; +} + +static int value_combine_cb(void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *value) +{ + ValueFormatter& cnf = *(ValueFormatter*)cls; + + cnf.ss << key; + + if (value) + { + cnf.ss << cnf.separator << value; + } + + cnf.ss << cnf.terminator; + + return MHD_YES; +} + +std::string HttpRequest::to_string() const +{ + std::stringstream req; + req << m_verb << " " << m_resource; + + ValueFormatter opts("=", "&"); + MHD_get_connection_values(m_connection, MHD_GET_ARGUMENT_KIND, + value_combine_cb, &opts); + + std::string optstr = opts.ss.str(); + size_t len = optstr.length(); + + if (len) + { + req << "?"; + + if (optstr[len - 1] == '&') + { + optstr.erase(len - 1); + } + } + + req << optstr << " " << "HTTP/1.1" << "\r\n"; + + ValueFormatter hdr(": ", "\r\n"); + MHD_get_connection_values(m_connection, MHD_HEADER_KIND, + value_combine_cb, &hdr); + + std::string hdrstr = hdr.ss.str(); + + if (hdrstr.length()) + { + req << hdrstr; + } + + req << "\r\n"; + + req << m_json_string; + return req.str(); +} diff --git a/server/core/maxscale/httprequest.hh b/server/core/maxscale/httprequest.hh index a45f309d3..bb1b2a2a8 100644 --- a/server/core/maxscale/httprequest.hh +++ b/server/core/maxscale/httprequest.hh @@ -43,6 +43,7 @@ static int value_iterator(void *cls, return MHD_YES; } + static int value_sum_iterator(void *cls, enum MHD_ValueKind kind, const char *key, @@ -252,11 +253,25 @@ public: return m_resource_parts.size() > 0 ? m_resource_parts[m_resource_parts.size() - 1] : ""; } + /** + * @brief Return the value of the Host header + * + * @return The value of the Host header + */ const char* host() const { return m_hostname.c_str(); } + /** + * @brief Convert request to string format + * + * The returned string should be logically equivalent to the original request. + * + * @return The request in string format + */ + std::string to_string() const; + /** * @brief Drop the API version prefix *