diff options
Diffstat (limited to 'src/web_service/web_backend.cpp')
| -rw-r--r-- | src/web_service/web_backend.cpp | 69 |
1 files changed, 32 insertions, 37 deletions
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 09d1651ac..534960d09 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp | |||
| @@ -6,13 +6,14 @@ | |||
| 6 | #include <cstdlib> | 6 | #include <cstdlib> |
| 7 | #include <mutex> | 7 | #include <mutex> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | |||
| 9 | #include <LUrlParser.h> | 10 | #include <LUrlParser.h> |
| 10 | #include <fmt/format.h> | 11 | #include <fmt/format.h> |
| 11 | #include <httplib.h> | 12 | #include <httplib.h> |
| 12 | #include "common/common_types.h" | 13 | |
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 14 | #include "common/web_result.h" | ||
| 15 | #include "web_service/web_backend.h" | 15 | #include "web_service/web_backend.h" |
| 16 | #include "web_service/web_result.h" | ||
| 16 | 17 | ||
| 17 | namespace WebService { | 18 | namespace WebService { |
| 18 | 19 | ||
| @@ -33,17 +34,16 @@ struct Client::Impl { | |||
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | /// A generic function handles POST, GET and DELETE request together | 36 | /// A generic function handles POST, GET and DELETE request together |
| 36 | Common::WebResult GenericRequest(const std::string& method, const std::string& path, | 37 | WebResult GenericRequest(const std::string& method, const std::string& path, |
| 37 | const std::string& data, bool allow_anonymous, | 38 | const std::string& data, bool allow_anonymous, |
| 38 | const std::string& accept) { | 39 | const std::string& accept) { |
| 39 | if (jwt.empty()) { | 40 | if (jwt.empty()) { |
| 40 | UpdateJWT(); | 41 | UpdateJWT(); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | if (jwt.empty() && !allow_anonymous) { | 44 | if (jwt.empty() && !allow_anonymous) { |
| 44 | LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); | 45 | LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); |
| 45 | return Common::WebResult{Common::WebResult::Code::CredentialsMissing, | 46 | return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""}; |
| 46 | "Credentials needed", ""}; | ||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | auto result = GenericRequest(method, path, data, accept, jwt); | 49 | auto result = GenericRequest(method, path, data, accept, jwt); |
| @@ -62,33 +62,30 @@ struct Client::Impl { | |||
| 62 | * username + token is used if jwt is empty but username and token are | 62 | * username + token is used if jwt is empty but username and token are |
| 63 | * not empty anonymous if all of jwt, username and token are empty | 63 | * not empty anonymous if all of jwt, username and token are empty |
| 64 | */ | 64 | */ |
| 65 | Common::WebResult GenericRequest(const std::string& method, const std::string& path, | 65 | WebResult GenericRequest(const std::string& method, const std::string& path, |
| 66 | const std::string& data, const std::string& accept, | 66 | const std::string& data, const std::string& accept, |
| 67 | const std::string& jwt = "", const std::string& username = "", | 67 | const std::string& jwt = "", const std::string& username = "", |
| 68 | const std::string& token = "") { | 68 | const std::string& token = "") { |
| 69 | if (cli == nullptr) { | 69 | if (cli == nullptr) { |
| 70 | auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); | 70 | const auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); |
| 71 | int port; | 71 | int port{}; |
| 72 | if (parsedUrl.m_Scheme == "http") { | 72 | if (parsedUrl.m_Scheme == "http") { |
| 73 | if (!parsedUrl.GetPort(&port)) { | 73 | if (!parsedUrl.GetPort(&port)) { |
| 74 | port = HTTP_PORT; | 74 | port = HTTP_PORT; |
| 75 | } | 75 | } |
| 76 | cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port); | ||
| 77 | } else if (parsedUrl.m_Scheme == "https") { | 76 | } else if (parsedUrl.m_Scheme == "https") { |
| 78 | if (!parsedUrl.GetPort(&port)) { | 77 | if (!parsedUrl.GetPort(&port)) { |
| 79 | port = HTTPS_PORT; | 78 | port = HTTPS_PORT; |
| 80 | } | 79 | } |
| 81 | cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port); | ||
| 82 | } else { | 80 | } else { |
| 83 | LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); | 81 | LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); |
| 84 | return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme", ""}; | 82 | return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""}; |
| 85 | } | 83 | } |
| 84 | cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port); | ||
| 86 | } | 85 | } |
| 87 | if (cli == nullptr) { | 86 | cli->set_connection_timeout(TIMEOUT_SECONDS); |
| 88 | LOG_ERROR(WebService, "Invalid URL {}", host + path); | 87 | cli->set_read_timeout(TIMEOUT_SECONDS); |
| 89 | return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL", ""}; | 88 | cli->set_write_timeout(TIMEOUT_SECONDS); |
| 90 | } | ||
| 91 | cli->set_timeout_sec(TIMEOUT_SECONDS); | ||
| 92 | 89 | ||
| 93 | httplib::Headers params; | 90 | httplib::Headers params; |
| 94 | if (!jwt.empty()) { | 91 | if (!jwt.empty()) { |
| @@ -106,7 +103,7 @@ struct Client::Impl { | |||
| 106 | std::string(API_VERSION.begin(), API_VERSION.end())); | 103 | std::string(API_VERSION.begin(), API_VERSION.end())); |
| 107 | if (method != "GET") { | 104 | if (method != "GET") { |
| 108 | params.emplace(std::string("Content-Type"), std::string("application/json")); | 105 | params.emplace(std::string("Content-Type"), std::string("application/json")); |
| 109 | }; | 106 | } |
| 110 | 107 | ||
| 111 | httplib::Request request; | 108 | httplib::Request request; |
| 112 | request.method = method; | 109 | request.method = method; |
| @@ -118,29 +115,28 @@ struct Client::Impl { | |||
| 118 | 115 | ||
| 119 | if (!cli->send(request, response)) { | 116 | if (!cli->send(request, response)) { |
| 120 | LOG_ERROR(WebService, "{} to {} returned null", method, host + path); | 117 | LOG_ERROR(WebService, "{} to {} returned null", method, host + path); |
| 121 | return Common::WebResult{Common::WebResult::Code::LibError, "Null response", ""}; | 118 | return WebResult{WebResult::Code::LibError, "Null response", ""}; |
| 122 | } | 119 | } |
| 123 | 120 | ||
| 124 | if (response.status >= 400) { | 121 | if (response.status >= 400) { |
| 125 | LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, | 122 | LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, |
| 126 | response.status); | 123 | response.status); |
| 127 | return Common::WebResult{Common::WebResult::Code::HttpError, | 124 | return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""}; |
| 128 | std::to_string(response.status), ""}; | ||
| 129 | } | 125 | } |
| 130 | 126 | ||
| 131 | auto content_type = response.headers.find("content-type"); | 127 | auto content_type = response.headers.find("content-type"); |
| 132 | 128 | ||
| 133 | if (content_type == response.headers.end()) { | 129 | if (content_type == response.headers.end()) { |
| 134 | LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); | 130 | LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); |
| 135 | return Common::WebResult{Common::WebResult::Code::WrongContent, "", ""}; | 131 | return WebResult{WebResult::Code::WrongContent, "", ""}; |
| 136 | } | 132 | } |
| 137 | 133 | ||
| 138 | if (content_type->second.find(accept) == std::string::npos) { | 134 | if (content_type->second.find(accept) == std::string::npos) { |
| 139 | LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, | 135 | LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, |
| 140 | content_type->second); | 136 | content_type->second); |
| 141 | return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content", ""}; | 137 | return WebResult{WebResult::Code::WrongContent, "Wrong content", ""}; |
| 142 | } | 138 | } |
| 143 | return Common::WebResult{Common::WebResult::Code::Success, "", response.body}; | 139 | return WebResult{WebResult::Code::Success, "", response.body}; |
| 144 | } | 140 | } |
| 145 | 141 | ||
| 146 | // Retrieve a new JWT from given username and token | 142 | // Retrieve a new JWT from given username and token |
| @@ -150,7 +146,7 @@ struct Client::Impl { | |||
| 150 | } | 146 | } |
| 151 | 147 | ||
| 152 | auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token); | 148 | auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token); |
| 153 | if (result.result_code != Common::WebResult::Code::Success) { | 149 | if (result.result_code != WebResult::Code::Success) { |
| 154 | LOG_ERROR(WebService, "UpdateJWT failed"); | 150 | LOG_ERROR(WebService, "UpdateJWT failed"); |
| 155 | } else { | 151 | } else { |
| 156 | std::lock_guard lock{jwt_cache.mutex}; | 152 | std::lock_guard lock{jwt_cache.mutex}; |
| @@ -180,29 +176,28 @@ Client::Client(std::string host, std::string username, std::string token) | |||
| 180 | 176 | ||
| 181 | Client::~Client() = default; | 177 | Client::~Client() = default; |
| 182 | 178 | ||
| 183 | Common::WebResult Client::PostJson(const std::string& path, const std::string& data, | 179 | WebResult Client::PostJson(const std::string& path, const std::string& data, bool allow_anonymous) { |
| 184 | bool allow_anonymous) { | ||
| 185 | return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json"); | 180 | return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json"); |
| 186 | } | 181 | } |
| 187 | 182 | ||
| 188 | Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { | 183 | WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { |
| 189 | return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json"); | 184 | return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json"); |
| 190 | } | 185 | } |
| 191 | 186 | ||
| 192 | Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data, | 187 | WebResult Client::DeleteJson(const std::string& path, const std::string& data, |
| 193 | bool allow_anonymous) { | 188 | bool allow_anonymous) { |
| 194 | return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json"); | 189 | return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json"); |
| 195 | } | 190 | } |
| 196 | 191 | ||
| 197 | Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) { | 192 | WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) { |
| 198 | return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain"); | 193 | return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain"); |
| 199 | } | 194 | } |
| 200 | 195 | ||
| 201 | Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) { | 196 | WebResult Client::GetImage(const std::string& path, bool allow_anonymous) { |
| 202 | return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png"); | 197 | return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png"); |
| 203 | } | 198 | } |
| 204 | 199 | ||
| 205 | Common::WebResult Client::GetExternalJWT(const std::string& audience) { | 200 | WebResult Client::GetExternalJWT(const std::string& audience) { |
| 206 | return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false, | 201 | return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false, |
| 207 | "text/html"); | 202 | "text/html"); |
| 208 | } | 203 | } |