From c17c451fb516deb93dfb9e92f2edb663e62b9432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Wed, 19 Apr 2017 20:58:23 +0300 Subject: [PATCH] MXS-1220: Move header generation back to HttpResponse The actual list of headers is not known when the request is first generated. This prevents the headers from being generated in admin.cc which handles things on a lower level. The moving of the header generation is done with the OPTIONS method in mind. This header needs to be generated inside the RootResource class which manages the navigation of the resources. --- server/core/admin.cc | 39 ++++++++++++++-------------- server/core/httpresponse.cc | 28 +++++++++++++++++--- server/core/maxscale/admin.hh | 10 +++---- server/core/maxscale/httprequest.hh | 2 +- server/core/maxscale/httpresponse.hh | 33 +++++++++++++++++++++++ 5 files changed, 82 insertions(+), 30 deletions(-) diff --git a/server/core/admin.cc b/server/core/admin.cc index 692278de2..9af7373ba 100644 --- a/server/core/admin.cc +++ b/server/core/admin.cc @@ -11,7 +11,7 @@ * Public License. */ -#include +#include "maxscale/admin.hh" #include #include @@ -24,10 +24,11 @@ #include #include -#include "maxscale/admin.hh" #include "maxscale/resource.hh" #include "maxscale/http.hh" +using std::string; + static struct MHD_Daemon* http_daemon = NULL; int kv_iter(void *cls, @@ -35,7 +36,7 @@ int kv_iter(void *cls, const char *key, const char *value) { - size_t* rval = (size_t*) cls; + size_t* rval = (size_t*)cls; if (strcmp(key, "Content-Length") == 0) { @@ -46,16 +47,17 @@ int kv_iter(void *cls, return MHD_YES; } -static inline size_t request_data_length(struct MHD_Connection *connection) +static inline size_t request_data_length(MHD_Connection *connection) { size_t rval = 0; MHD_get_connection_values(connection, MHD_HEADER_KIND, kv_iter, &rval); return rval; } -static bool modifies_data(struct MHD_Connection *connection, string method) +static bool modifies_data(MHD_Connection *connection, string method) { - return (method == "POST" || method == "PUT" || method == "PATCH") && + return (method == MHD_HTTP_METHOD_POST || method == MHD_HTTP_METHOD_PUT || + method == MHD_HTTP_METHOD_PATCH || method == MHD_HTTP_METHOD_DELETE) && request_data_length(connection); } @@ -75,7 +77,7 @@ int Client::process(string url, string method, const char* upload_data, size_t * if (m_data.length() && (json = json_loadb(m_data.c_str(), m_data.size(), 0, &err)) == NULL) { - struct MHD_Response *response = + MHD_Response *response = MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_PERSISTENT); MHD_queue_response(m_connection, MHD_HTTP_BAD_REQUEST, response); MHD_destroy_response(response); @@ -95,19 +97,16 @@ int Client::process(string url, string method, const char* upload_data, size_t * data = mxs::json_dump(js, flags); } - struct MHD_Response *response = + MHD_Response *response = MHD_create_response_from_buffer(data.size(), (void*)data.c_str(), MHD_RESPMEM_MUST_COPY); - string http_date = http_get_date(); + const Headers& headers = reply.get_headers(); - MHD_add_response_header(response, "Date", http_date.c_str()); - - // TODO: calculate modification times - MHD_add_response_header(response, "Last-Modified", http_date.c_str()); - - // This ETag is the base64 encoding of `not-yet-implemented` - MHD_add_response_header(response, "ETag", "bm90LXlldC1pbXBsZW1lbnRlZAo"); + for (Headers::const_iterator it = headers.begin(); it != headers.end(); it++) + { + MHD_add_response_header(response, it->first.c_str(), it->second.c_str()); + } int rval = MHD_queue_response(m_connection, reply.get_code(), response); MHD_destroy_response(response); @@ -116,7 +115,7 @@ int Client::process(string url, string method, const char* upload_data, size_t * } void close_client(void *cls, - struct MHD_Connection *connection, + MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) { @@ -124,7 +123,7 @@ void close_client(void *cls, delete client; } -bool do_auth(struct MHD_Connection *connection) +bool do_auth(MHD_Connection *connection) { const char *admin_user = config_get_global_options()->admin_user; const char *admin_pw = config_get_global_options()->admin_password; @@ -138,7 +137,7 @@ bool do_auth(struct MHD_Connection *connection) { rval = false; static char error_resp[] = "Access denied\r\n"; - struct MHD_Response *resp = + MHD_Response *resp = MHD_create_response_from_buffer(sizeof(error_resp) - 1, error_resp, MHD_RESPMEM_PERSISTENT); @@ -150,7 +149,7 @@ bool do_auth(struct MHD_Connection *connection) } int handle_client(void *cls, - struct MHD_Connection *connection, + MHD_Connection *connection, const char *url, const char *method, const char *version, diff --git a/server/core/httpresponse.cc b/server/core/httpresponse.cc index 414a6710e..e0c6e4982 100644 --- a/server/core/httpresponse.cc +++ b/server/core/httpresponse.cc @@ -28,13 +28,18 @@ HttpResponse::HttpResponse(int code, json_t* response): m_body(response), m_code(code) { + string http_date = http_get_date(); + add_header(HTTP_RESPONSE_HEADER_DATE, http_date); + add_header(HTTP_RESPONSE_HEADER_LAST_MODIFIED, http_date); + // This ETag is the base64 encoding of `not-yet-implemented` + add_header(HTTP_RESPONSE_HEADER_ETAG, "bm90LXlldC1pbXBsZW1lbnRlZAo"); } HttpResponse::HttpResponse(const HttpResponse& response): - m_body(response.m_body), - m_code(response.m_code) + m_body(json_incref(response.m_body)), + m_code(response.m_code), + m_headers(response.m_headers) { - json_incref(m_body); } HttpResponse& HttpResponse::operator=(const HttpResponse& response) @@ -42,6 +47,7 @@ HttpResponse& HttpResponse::operator=(const HttpResponse& response) json_t* body = m_body; m_body = json_incref(response.m_body); m_code = response.m_code; + m_headers = response.m_headers; json_decref(body); return *this; } @@ -59,7 +65,23 @@ json_t* HttpResponse::get_response() const return m_body; } +void HttpResponse::drop_response() +{ + json_decref(m_body); + m_body = NULL; +} + int HttpResponse::get_code() const { return m_code; } + +void HttpResponse::add_header(const string& key, const string& value) +{ + m_headers[key] = value; +} + +const Headers& HttpResponse::get_headers() const +{ + return m_headers; +} diff --git a/server/core/maxscale/admin.hh b/server/core/maxscale/admin.hh index a31006524..d9bc3f765 100644 --- a/server/core/maxscale/admin.hh +++ b/server/core/maxscale/admin.hh @@ -19,8 +19,6 @@ #include -using std::string; - class Client { public: @@ -30,7 +28,7 @@ public: * * @param connection The connection handle for this client */ - Client(struct MHD_Connection *connection): + Client(MHD_Connection *connection): m_connection(connection) { } @@ -52,11 +50,11 @@ public: * * @return MHD_YES on success, MHD_NO on error */ - int process(string url, string method, const char* data, size_t *size); + int process(std::string url, std::string method, const char* data, size_t *size); private: - struct MHD_Connection* m_connection; /**< Connection handle */ - string m_data; /**< Uploaded data */ + MHD_Connection* m_connection; /**< Connection handle */ + std::string m_data; /**< Uploaded data */ }; /** diff --git a/server/core/maxscale/httprequest.hh b/server/core/maxscale/httprequest.hh index 9bb0fc1b6..7863dc002 100644 --- a/server/core/maxscale/httprequest.hh +++ b/server/core/maxscale/httprequest.hh @@ -119,7 +119,7 @@ public: * * @return Raw JSON body or NULL if no body is defined */ - json_t* get_json() + json_t* get_json() const { return m_json.get(); } diff --git a/server/core/maxscale/httpresponse.hh b/server/core/maxscale/httpresponse.hh index 79498f0ac..3bf96672d 100644 --- a/server/core/maxscale/httpresponse.hh +++ b/server/core/maxscale/httpresponse.hh @@ -23,6 +23,16 @@ #include "http.hh" +/** + * A list of default headers that are generated with each response + */ +#define HTTP_RESPONSE_HEADER_DATE "Date" +#define HTTP_RESPONSE_HEADER_LAST_MODIFIED "Last-Modified" +#define HTTP_RESPONSE_HEADER_ETAG "ETag" +#define HTTP_RESPONSE_HEADER_ACCEPT "Accept" + +typedef std::map Headers; + class HttpResponse { public: @@ -45,6 +55,13 @@ public: */ json_t* get_response() const; + /** + * @brief Drop response body + * + * This discards the message body. + */ + void drop_response(); + /** * @brief Get the HTTP response code * @@ -52,7 +69,23 @@ public: */ int get_code() const; + /** + * @brief Add an extra header to this response + * + * @param key Header name + * @param value Header value + */ + void add_header(const std::string& key, const std::string& value); + + /** + * @brief Get request headers + * + * @return Headers of this request + */ + const Headers& get_headers() const; + private: json_t* m_body; /**< Message body */ int m_code; /**< The HTTP code for the response */ + Headers m_headers; /**< Extra headers */ };