MaxScale/server/core/internal/httprequest.hh
Niclas Antti c447e5cf15 Uncrustify maxscale
See script directory for method. The script to run in the top level
MaxScale directory is called maxscale-uncrustify.sh, which uses
another script, list-src, from the same directory (so you need to set
your PATH). The uncrustify version was 0.66.
2018-09-09 22:26:19 +03:00

305 lines
7.6 KiB
C++

/*
* Copyright (c) 2018 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: 2022-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.
*/
#pragma once
#include <maxscale/ccdefs.hh>
#include <deque>
#include <map>
#include <string>
#include <memory>
#include <cstdint>
#include <microhttpd.h>
#include <maxscale/jansson.hh>
#include <maxscale/utils.hh>
#include <maxscale/http.hh>
// The API version part of the URL
#define MXS_REST_API_VERSION "v1"
static int value_iterator(void* cls,
enum MHD_ValueKind kind,
const char* key,
const char* value)
{
std::pair<std::string, std::string>* cmp = (std::pair<std::string, std::string>*)cls;
if (strcasecmp(cmp->first.c_str(), key) == 0 && value)
{
cmp->second = value;
return MHD_NO;
}
return MHD_YES;
}
static int value_sum_iterator(void* cls,
enum MHD_ValueKind kind,
const char* key,
const char* value)
{
size_t& count = *(size_t*)cls;
count++;
return MHD_YES;
}
static int value_copy_iterator(void* cls,
enum MHD_ValueKind kind,
const char* key,
const char* value)
{
std::string k = key;
if (value)
{
k += "=";
k += value;
}
char**& dest = *(char***) cls;
*dest = MXS_STRDUP_A(k.c_str());
dest++;
return MHD_YES;
}
class HttpRequest
{
HttpRequest(const HttpRequest&);
HttpRequest& operator=(const HttpRequest);
public:
/**
* @brief Parse a request
*
* @param request Request to parse
*
* @return Parsed statement or NULL if request is not valid
*/
HttpRequest(struct MHD_Connection* connection, std::string url, std::string method, json_t* data);
~HttpRequest();
/**
* @brief Return request verb type
*
* @return One of the HTTP verb values
*/
const std::string& get_verb() const
{
return m_verb;
}
/**
* @brief Get header value
*
* @param header Header to get
*
* @return Header value or empty string if the header was not found
*/
std::string get_header(const std::string& header) const
{
std::pair<std::string, std::string> p;
p.first = header;
MHD_get_connection_values(m_connection,
MHD_HEADER_KIND,
value_iterator,
&p);
return p.second;
}
/**
* @brief Get option value
*
* @param header Option to get
*
* @return Option value or empty string if the option was not found
*/
std::string get_option(const std::string& option) const
{
std::pair<std::string, std::string> p;
p.first = option;
MHD_get_connection_values(m_connection,
MHD_GET_ARGUMENT_KIND,
value_iterator,
&p);
return p.second;
}
/**
* @brief Get request option count
*
* @return Number of options in the request
*/
size_t get_option_count() const
{
size_t rval = 0;
MHD_get_connection_values(m_connection,
MHD_GET_ARGUMENT_KIND,
value_sum_iterator,
&rval);
return rval;
}
/**
* @brief Copy options to an array
*
* The @c dest parameter must be able to hold at least get_option_count()
* pointers. The values stored need to be freed by the caller.
*
* @param dest Destination where options are copied
*/
void copy_options(char** dest) const
{
MHD_get_connection_values(m_connection,
MHD_GET_ARGUMENT_KIND,
value_copy_iterator,
&dest);
}
/**
* @brief Return request body
*
* @return Request body or empty string if no body is defined
*/
const std::string& get_json_str() const
{
return m_json_string;
}
/**
* @brief Return raw JSON body
*
* @return Raw JSON body or NULL if no body is defined
*/
json_t* get_json() const
{
return m_json.get();
}
/**
* @brief Get complete request URI
*
* @return The complete request URI
*/
std::string get_uri() const
{
return m_resource;
}
/**
* @brief Get URI part
*
* @param idx Zero indexed part number in URI
*
* @return The request URI part or empty string if no part was found
*/
std::string uri_part(uint32_t idx) const
{
return m_resource_parts.size() > idx ? m_resource_parts[idx] : "";
}
/**
* @brief Return a segment of the URI
*
* Combines a range of parts into a segment of the URI. Each part is
* separated by a forward slash.
*
* @param start Start of range
* @param end End of range, not inclusive
*
* @return The URI segment that matches this range
*/
std::string uri_segment(uint32_t start, uint32_t end) const
{
std::string rval;
for (uint32_t i = start; i < end && i < m_resource_parts.size(); i++)
{
if (i > start)
{
rval += "/";
}
rval += m_resource_parts[i];
}
return rval;
}
/**
* @brief Return how many parts are in the URI
*
* @return Number of URI parts
*/
size_t uri_part_count() const
{
return m_resource_parts.size();
}
/**
* @brief Return the last part of the URI
*
* @return The last URI part
*/
std::string last_uri_part() const
{
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
*
* @return True if prefix is present and was successfully removed
*/
bool validate_api_version();
private:
/** Constants */
static const std::string HTTP_PREFIX;
static const std::string HTTPS_PREFIX;
std::map<std::string, std::string> m_options; /**< Request options */
std::unique_ptr<json_t> m_json; /**< Request body */
std::string m_json_string; /**< String version of @c m_json */
std::string m_resource; /**< Requested resource */
std::deque<std::string> m_resource_parts;/**< @c m_resource split into parts */
std::string m_verb; /**< Request method */
std::string m_hostname; /**< The value of the Host header */
struct MHD_Connection* m_connection;
};