diff --git a/include/http_client.h b/include/http_client.h index 5c39dc5f..e5c5ff5d 100644 --- a/include/http_client.h +++ b/include/http_client.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include /* @@ -17,9 +18,9 @@ private: static size_t curl_write (void *contents, size_t size, size_t nmemb, std::string *s); - static CURL* init_curl(const std::string & url, std::string & buffer); + static CURL* init_curl(const std::string& url, std::string& response); - static long perform_curl(CURL *curl); + static long perform_curl(CURL *curl, std::map& res_headers); public: static HttpClient & get_instance() { @@ -32,13 +33,17 @@ public: void init(const std::string & api_key); - static long get_response(const std::string & url, std::string & response, long timeout_ms=4000); + static long get_response(const std::string& url, std::string& response, + std::map& res_headers, long timeout_ms=4000); - static long delete_response(const std::string & url, std::string & response, long timeout_ms=120000); + static long delete_response(const std::string& url, std::string& response, + std::map& res_headers, long timeout_ms=120000); static long post_response(const std::string & url, const std::string & body, std::string & response, - long timeout_ms=4000); + std::map& res_headers, long timeout_ms=4000); static long put_response(const std::string & url, const std::string & body, std::string & response, - long timeout_ms=4000); + std::map& res_headers, long timeout_ms=4000); + + static void extract_response_headers(CURL* curl, std::map &res_headers); }; diff --git a/src/http_client.cpp b/src/http_client.cpp index 8e13c2b2..156c7965 100644 --- a/src/http_client.cpp +++ b/src/http_client.cpp @@ -7,7 +7,8 @@ std::string HttpClient::api_key = ""; std::string HttpClient::ca_cert_path = ""; -long HttpClient::post_response(const std::string &url, const std::string &body, std::string &response, long timeout_ms) { +long HttpClient::post_response(const std::string &url, const std::string &body, std::string &response, + std::map& res_headers, long timeout_ms) { CURL *curl = init_curl(url, response); if(curl == nullptr) { return 500; @@ -15,10 +16,11 @@ long HttpClient::post_response(const std::string &url, const std::string &body, curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms); - return perform_curl(curl); + return perform_curl(curl, res_headers); } -long HttpClient::put_response(const std::string &url, const std::string &body, std::string &response, long timeout_ms) { +long HttpClient::put_response(const std::string &url, const std::string &body, std::string &response, + std::map& res_headers, long timeout_ms) { CURL *curl = init_curl(url, response); if(curl == nullptr) { return 500; @@ -27,10 +29,11 @@ long HttpClient::put_response(const std::string &url, const std::string &body, s curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms); - return perform_curl(curl); + return perform_curl(curl, res_headers); } -long HttpClient::delete_response(const std::string &url, std::string &response, long timeout_ms) { +long HttpClient::delete_response(const std::string &url, std::string &response, + std::map& res_headers, long timeout_ms) { CURL *curl = init_curl(url, response); if(curl == nullptr) { return 500; @@ -38,17 +41,18 @@ long HttpClient::delete_response(const std::string &url, std::string &response, curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); - return perform_curl(curl); + return perform_curl(curl, res_headers); } -long HttpClient::get_response(const std::string &url, std::string &response, long timeout_ms) { +long HttpClient::get_response(const std::string &url, std::string &response, + std::map& res_headers, long timeout_ms) { CURL *curl = init_curl(url, response); if(curl == nullptr) { return 500; } curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms); - return perform_curl(curl); + return perform_curl(curl, res_headers); } void HttpClient::init(const std::string &api_key) { @@ -74,7 +78,7 @@ void HttpClient::init(const std::string &api_key) { } } -long HttpClient::perform_curl(CURL *curl) { +long HttpClient::perform_curl(CURL *curl, std::map& res_headers) { struct curl_slist *chunk = nullptr; std::string api_key_header = std::string("x-typesense-api-key: ") + HttpClient::api_key; chunk = curl_slist_append(chunk, api_key_header.c_str()); @@ -89,18 +93,26 @@ long HttpClient::perform_curl(CURL *curl) { long http_code = 500; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); + + extract_response_headers(curl, res_headers); curl_easy_cleanup(curl); return http_code == 0 ? 500 : http_code; } -CURL *HttpClient::init_curl(const std::string &url, std::string &buffer) { +void HttpClient::extract_response_headers(CURL* curl, std::map &res_headers) { + char* content_type; + curl_easy_getinfo (curl, CURLINFO_CONTENT_TYPE, &content_type); + res_headers.emplace("content-type", content_type); +} + +CURL *HttpClient::init_curl(const std::string& url, std::string& response) { CURL *curl = curl_easy_init(); if(curl == nullptr) { nlohmann::json res; res["message"] = "Failed to initialize HTTP client."; - buffer = res.dump(); + response = res.dump(); return nullptr; } @@ -118,7 +130,7 @@ CURL *HttpClient::init_curl(const std::string &url, std::string &buffer) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HttpClient::curl_write); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); return curl; } diff --git a/src/http_server.cpp b/src/http_server.cpp index 74a732a5..e5f7b521 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -379,7 +379,7 @@ int HttpServer::catch_all_handler(h2o_handler_t *_self, h2o_req_t *req) { } // for writes, we defer to replication_state - if(http_method != "GET") { + if(http_method == "POST" || http_method == "PUT" || http_method == "DELETE") { self->http_server->get_replication_state()->write(request, response); return 0; } diff --git a/src/raft_server.cpp b/src/raft_server.cpp index 73bd1a63..b0986752 100644 --- a/src/raft_server.cpp +++ b/src/raft_server.cpp @@ -114,17 +114,22 @@ void ReplicationState::write(http_req* request, http_res* response) { const std::string & path = std::string(raw_req->path.base, raw_req->path.len); std::string url = scheme + "://" + leader_host_port + path; + std::map res_headers; + if(request->http_method == "POST") { std::string api_res; - long status = HttpClient::post_response(url, request->body, api_res); + long status = HttpClient::post_response(url, request->body, api_res, res_headers); + response->content_type_header = res_headers["content-type"]; response->set_body(status, api_res); } else if(request->http_method == "PUT") { std::string api_res; - long status = HttpClient::put_response(url, request->body, api_res); + long status = HttpClient::put_response(url, request->body, api_res, res_headers); + response->content_type_header = res_headers["content-type"]; response->set_body(status, api_res); } else if(request->http_method == "DELETE") { std::string api_res; - long status = HttpClient::delete_response(url, api_res); + long status = HttpClient::delete_response(url, api_res, res_headers); + response->content_type_header = res_headers["content-type"]; response->set_body(status, api_res); } else { const std::string& err = "Forwarding for http method not implemented: " + request->http_method;