MaxScale/server/core/httprequest.cc
Markus Mäkelä 396b81f336 Fix in-source builds
The internal header directory conflicted with in-source builds causing a
build failure. This is fixed by renaming the internal header directory to
something other than maxscale.

The renaming pointed out a few problems in a couple of source files that
appeared to include internal headers when the headers were in fact public
headers.

Fixed maxctrl in-source builds by making the copying of the sources
optional.
2017-11-22 18:40:18 +02:00

207 lines
4.4 KiB
C++

/*
* Copyright (c) 2016 MariaDB Corporation Ab
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
*
* Change Date: 2020-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#include "internal/httprequest.hh"
#include "internal/admin.hh"
#include <ctype.h>
#include <string.h>
#include <sstream>
using std::string;
using std::deque;
#define HTTP_HOST_HEADER "Host"
#define HTTP_METHOD_OVERRIDE "X-HTTP-Method-Override"
const std::string HttpRequest::HTTP_PREFIX = "http://";
const std::string HttpRequest::HTTPS_PREFIX = "https://";
/** TODO: Move this to a C++ string utility header */
namespace maxscale
{
static inline string& trim(string& str)
{
if (str.length())
{
if (isspace(*str.begin()))
{
string::iterator it = str.begin();
while (it != str.end() && isspace(*it))
{
it++;
}
str.erase(str.begin(), it);
}
if (isspace(*str.rbegin()))
{
string::reverse_iterator it = str.rbegin();
while (it != str.rend() && isspace(*it))
{
it++;
}
str.erase(it.base(), str.end());
}
}
return str;
}
}
static void process_uri(string& uri, std::deque<string>& uri_parts)
{
/** Clean up trailing slashes in requested resource */
while (uri.length() > 1 && *uri.rbegin() == '/')
{
uri.erase(uri.find_last_of("/"));
}
string my_uri = uri;
while (my_uri.length() && *my_uri.begin() == '/')
{
my_uri.erase(my_uri.begin());
}
while (my_uri.length() > 0)
{
size_t pos = my_uri.find("/");
string part = pos == string::npos ? my_uri : my_uri.substr(0, pos);
my_uri.erase(0, pos == string::npos ? pos : pos + 1);
uri_parts.push_back(part);
}
}
HttpRequest::HttpRequest(struct MHD_Connection *connection, string url, string method, json_t* data):
m_json(data),
m_json_string(data ? mxs::json_dump(data, 0) : ""),
m_resource(url),
m_verb(method),
m_connection(connection)
{
process_uri(url, m_resource_parts);
m_hostname = mxs_admin_https_enabled() ? HttpRequest::HTTPS_PREFIX : HttpRequest::HTTP_PREFIX;
m_hostname += get_header(HTTP_HOST_HEADER);
string method_override = get_header(HTTP_METHOD_OVERRIDE);
if (method_override.length())
{
m_verb = method_override;
}
if (m_hostname[m_hostname.size() - 1] != '/')
{
m_hostname += "/";
}
m_hostname += MXS_REST_API_VERSION;
}
HttpRequest::~HttpRequest()
{
}
bool HttpRequest::validate_api_version()
{
bool rval = false;
if (m_resource_parts.size() > 0 &&
m_resource_parts[0] == MXS_REST_API_VERSION)
{
m_resource_parts.pop_front();
rval = true;
}
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();
}