| |
| #include "proxy_redfishv1_impl.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "absl/status/statusor.h" |
| #include "absl/strings/ascii.h" |
| #include "absl/strings/match.h" |
| #include "redfish_query_engine/redfish_v1.pb.h" |
| #include "grpc/status.h" |
| #include "grpcpp/security/auth_context.h" |
| #include "grpcpp/support/status.h" |
| #include "proxy.h" |
| #include "proxy_config.pb.h" |
| #include "redfish_plugin.h" |
| #include "request_response.h" |
| #include "voyager/priority_queue.hpp" |
| |
| namespace milotic { |
| |
| namespace { |
| // For Ecclesia lib, contract for redfish v1. Anything out of tree is not parsed |
| // as JSON. Some implementations may set the OData-Version flag for non-JSON |
| // items, so we also check content-type if it is present. |
| bool IsResponseRedfishJson(const redfish::v1::Response &response) { |
| auto found = response.headers().find("odata-version"); |
| if (found == response.headers().end()) return false; |
| if (found->second != "4.0") return false; |
| |
| found = response.headers().find("content-type"); |
| // Default to JSON if there is an odata-version but no content type. |
| if (found == response.headers().end()) return true; |
| if (found->second != "application/json") return false; |
| return true; |
| } |
| } // namespace |
| |
| grpc::Status ProxyRedfishV1Impl::DispatchRequest( |
| RedfishPlugin::RequestVerb verb, const ::redfish::v1::Request *request, |
| redfish::v1::Response *response, const grpc::AuthContext &auth_context) { |
| absl::StatusOr<std::unique_ptr<ProxyRequest>> status_or_http_request = |
| proxy_.CreateAuthorizedRequest(verb, request->url(), auth_context); |
| if (!status_or_http_request.ok()) { |
| return ConvertStatus(status_or_http_request.status()); |
| } |
| std::unique_ptr<ProxyRequest> http_request = |
| *std::move(status_or_http_request); |
| |
| /* Copy http request headers to request */ |
| for (const auto &[key, value] : request->headers()) { |
| // Never override "Host" header. |
| if (absl::EqualsIgnoreCase(key, "host")) continue; |
| http_request->AddHeader(key, value); |
| } |
| |
| if (!request->json_str().empty()) { |
| http_request->SetBody(request->json_str()); |
| // This is declared inside the if block to ensure empty Content-Type header |
| // is not added to http_request. |
| if (http_request->GetHeader("Content-Type").empty()) { |
| http_request->AddHeader("Content-Type", "application/json"); |
| } |
| } else if (request->has_octet_stream()) { |
| http_request->SetBody(request->octet_stream()); |
| if (http_request->GetHeader("Content-Type").empty()) { |
| http_request->AddHeader("Content-Type", "application/octet-stream"); |
| } |
| } |
| |
| absl::StatusOr<std::unique_ptr<Proxy::RequestJob>> job = |
| proxy_.DispatchRequestToQueue(verb, std::move(http_request)); |
| if (!job.ok()) return ConvertStatus(job.status()); |
| |
| if (job.value()->Wait() != voyager::Job::JobState::kDone) { |
| return grpc::Status(static_cast<grpc::StatusCode>(GRPC_STATUS_INTERNAL), |
| "Job error"); |
| } |
| |
| absl::StatusOr<ProxyResponse> &result = job.value()->response(); |
| if (!result.ok()) return ConvertStatus(result.status()); |
| |
| /* Copy response headers back */ |
| for (const auto &[key, value] : result->GetHeaders()) { |
| // HTTP headers names are not case sensitive. Changing consistently to |
| // lowercase allows for easier comparisons, and is consistent with HTTP2 |
| // headers. |
| std::string key_lower = key; |
| absl::AsciiStrToLower(&key_lower); |
| (*response->mutable_headers())[std::move(key_lower)] = value; |
| } |
| |
| /* Copy back response depending on expected response version */ |
| if (IsResponseRedfishJson(*response)) { |
| response->set_json_str(result->GetBody()); |
| } else { |
| response->set_octet_stream(result->GetBody()); |
| } |
| response->set_code(result->GetCode()); |
| return grpc::Status::OK; |
| } |
| |
| static Proxy::RegisterService<milotic_grpc_proxy::RedfishV1Options, |
| ProxyRedfishV1Impl> |
| redfish_v1_service_reg; |
| |
| } // namespace milotic |