blob: 960e70f2d716c63321438d4e5b36059e12ceb860 [file] [log] [blame] [edit]
#ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_REQUEST_RESPONSE_H_
#define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_REQUEST_RESPONSE_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "redfish_query_engine/http/client.h"
#include "nlohmann/json_fwd.hpp"
#include "proxy_config.pb.h"
namespace milotic {
using HttpHeaders = absl::flat_hash_map<std::string, std::string>;
constexpr absl::string_view SchemeToString(
milotic_grpc_proxy::TargetScheme scheme) {
switch (scheme) {
case milotic_grpc_proxy::TargetScheme::TARGET_SCHEME_HTTPS:
return "https://";
case milotic_grpc_proxy::TargetScheme::TARGET_SCHEME_HTTP:
return "http://";
case milotic_grpc_proxy::TargetScheme::TARGET_SCHEME_GRPC:
return "dns:///";
default:
return "";
}
}
class Host {
public:
explicit Host(milotic_grpc_proxy::TargetScheme scheme =
milotic_grpc_proxy::TargetScheme::TARGET_SCHEME_UNSPECIFIED,
std::string hostname = "", uint16_t port = 0)
: scheme_(scheme), hostname_(std::move(hostname)), port_(port) {
endpoint_ = absl::StrCat(SchemeToString(scheme_), hostname_);
if (port_ != 0) {
absl::StrAppend(&endpoint_, ":", port_);
}
}
explicit Host(const milotic_grpc_proxy::Target& target) {
scheme_ = target.scheme();
if (target.has_hostname()) {
hostname_ = target.hostname();
} else if (target.has_nea_host()) {
// TODO(jainrish): Implement NEA host support.
LOG(DFATAL) << "NEA host support is not implemented yet";
hostname_ = "";
}
port_ = static_cast<uint16_t>(target.port());
endpoint_ = absl::StrCat(SchemeToString(scheme_), hostname_);
if (port_ != 0) {
absl::StrAppend(&endpoint_, ":", port_);
}
}
static std::vector<Host> CreateTestHosts(std::string hostname) {
return {Host(milotic_grpc_proxy::TargetScheme::TARGET_SCHEME_UNSPECIFIED,
std::move(hostname), 0)};
}
absl::string_view GetEndpoint() const { return endpoint_; }
absl::string_view GetHostname() const { return hostname_; }
uint16_t GetPort() const { return port_; }
std::string GetHostHeader() const {
if (port_ == 0) {
return hostname_;
}
return absl::StrCat(hostname_, ":", port_);
}
private:
milotic_grpc_proxy::TargetScheme scheme_ =
milotic_grpc_proxy::TargetScheme::TARGET_SCHEME_UNSPECIFIED;
std::string hostname_;
uint16_t port_ = 0;
std::string endpoint_;
};
class ProxyRequest {
public:
ProxyRequest() = default;
ProxyRequest(std::vector<Host> hosts, std::string path, std::string body = "",
HttpHeaders headers = {}, std::string unix_socket_path = "")
: hosts_(std::move(hosts)),
path_(std::move(path)),
unix_socket_path_(std::move(unix_socket_path)),
body_(std::move(body)),
headers_(std::move(headers)) {}
void SetPath(absl::string_view path) { path_ = path; }
absl::string_view GetPath() const { return path_; }
void AddHeader(absl::string_view key, absl::string_view value) {
headers_[key] = value;
}
void SetBody(std::string body) { body_ = std::move(body); }
absl::string_view GetBody() const { return body_; }
nlohmann::json GetBodyJson() const {
return nlohmann::json::parse(body_, nullptr, /*allow_exceptions=*/false);
}
const HttpHeaders& GetHeaders() const { return headers_; }
absl::string_view GetHeader(absl::string_view key) const {
auto it = headers_.find(key);
if (it == headers_.end()) {
return "";
}
return it->second;
}
std::string GetHostUri(int host_index) const {
if (host_index < 0 || static_cast<size_t>(host_index) >= hosts_.size()) {
LOG(ERROR) << "Host index is out of range: " << host_index;
return "";
}
return absl::StrCat(hosts_[host_index].GetEndpoint(), path_);
}
Host GetHost(int host_index = 0) {
if (host_index < 0 || static_cast<size_t>(host_index) >= hosts_.size()) {
LOG(ERROR) << "Host index is out of range" << host_index;
return Host();
}
return hosts_[host_index];
}
absl::string_view GetUnixSocketPath() { return unix_socket_path_; }
std::unique_ptr<ecclesia::HttpClient::HttpRequest> ToHttpClientRequest(
int host_index = 0) {
if (host_index < 0 || static_cast<size_t>(host_index) >= hosts_.size()) {
LOG(ERROR) << "Host index is out of range" << host_index;
return nullptr;
}
auto request = std::make_unique<ecclesia::HttpClient::HttpRequest>();
request->headers = headers_;
request->body = body_;
request->uri = absl::StrCat(hosts_[host_index].GetEndpoint(), path_);
return request;
}
private:
// The list of hosts to try in order.
std::vector<Host> hosts_;
std::string path_;
std::string unix_socket_path_;
std::string body_;
HttpHeaders headers_;
};
class ProxyResponse {
public:
explicit ProxyResponse(int code = 0, std::string body = "",
HttpHeaders headers = {})
: code_(code), body_(std::move(body)), headers_(std::move(headers)) {}
explicit ProxyResponse(ecclesia::HttpClient::HttpResponse response)
: code_(response.code),
body_(std::move(response.body)),
headers_(std::move(response.headers)) {}
nlohmann::json GetBodyJson() const {
return nlohmann::json::parse(body_, nullptr, /*allow_exceptions=*/false);
}
void SetCode(int code) { code_ = code; }
int GetCode() const { return code_; }
const HttpHeaders& GetHeaders() const { return headers_; }
void AddHeader(absl::string_view key, absl::string_view value) {
headers_[key] = value;
}
void RemoveHeader(absl::string_view key) { headers_.erase(key); }
void SetBody(absl::string_view body) { body_ = body; }
absl::string_view GetBody() const { return body_; }
private:
int code_;
std::string body_;
HttpHeaders headers_;
};
} // namespace milotic
#endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_REQUEST_RESPONSE_H_