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