 c447e5cf15
			
		
	
	c447e5cf15
	
	
	
		
			
			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.
		
			
				
	
	
		
			305 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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;
 | |
| };
 |