1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 #pragma once 4 5 #include "boost_formatters.hpp" 6 #include "http_body.hpp" 7 #include "http_response.hpp" 8 #include "http_utility.hpp" 9 #include "json_html_serializer.hpp" 10 #include "logging.hpp" 11 #include "security_headers.hpp" 12 13 #include <boost/beast/http/field.hpp> 14 #include <nlohmann/json.hpp> 15 16 #include <array> 17 #include <string> 18 #include <string_view> 19 #include <utility> 20 21 namespace crow 22 { 23 24 inline void handleEncoding(std::string_view acceptEncoding, Response& res) 25 { 26 using bmcweb::CompressionType; 27 using enum bmcweb::CompressionType; 28 using http_helpers::Encoding; 29 using enum http_helpers::Encoding; 30 // If the payload is currently compressed, see if we can avoid 31 // decompressing it by sending it to the client directly 32 switch (res.response.body().compressionType) 33 { 34 case Zstd: 35 { 36 std::array<Encoding, 1> allowedEnc{ZSTD}; 37 Encoding encoding = 38 http_helpers::getPreferredEncoding(acceptEncoding, allowedEnc); 39 40 if (encoding == ZSTD) 41 { 42 // If the client supports returning zstd directly, allow that. 43 res.response.body().clientCompressionType = Zstd; 44 } 45 } 46 break; 47 case Gzip: 48 { 49 std::array<Encoding, 1> allowedEnc{GZIP}; 50 Encoding encoding = 51 http_helpers::getPreferredEncoding(acceptEncoding, allowedEnc); 52 if (encoding != GZIP) 53 { 54 BMCWEB_LOG_WARNING( 55 "Unimplemented: Returning gzip payload to client that did not explicitly allow it."); 56 } 57 } 58 break; 59 default: 60 break; 61 } 62 } 63 64 inline void completeResponseFields( 65 std::string_view accepts, std::string_view acceptEncoding, Response& res) 66 { 67 BMCWEB_LOG_INFO("Response: {}", res.resultInt()); 68 addSecurityHeaders(res); 69 70 res.setResponseEtagAndHandleNotModified(); 71 if (res.jsonValue.is_structured()) 72 { 73 using http_helpers::ContentType; 74 std::array<ContentType, 3> allowed{ContentType::CBOR, ContentType::JSON, 75 ContentType::HTML}; 76 ContentType preferred = getPreferredContentType(accepts, allowed); 77 78 if (preferred == ContentType::HTML) 79 { 80 json_html_util::prettyPrintJson(res); 81 } 82 else if (preferred == ContentType::CBOR) 83 { 84 res.addHeader(boost::beast::http::field::content_type, 85 "application/cbor"); 86 std::string cbor; 87 nlohmann::json::to_cbor(res.jsonValue, cbor); 88 res.write(std::move(cbor)); 89 } 90 else 91 { 92 // Technically preferred could also be NoMatch here, but we'd 93 // like to default to something rather than return 400 for 94 // backward compatibility. 95 res.addHeader(boost::beast::http::field::content_type, 96 "application/json"); 97 res.write(res.jsonValue.dump( 98 2, ' ', true, nlohmann::json::error_handler_t::replace)); 99 } 100 } 101 102 handleEncoding(acceptEncoding, res); 103 } 104 } // namespace crow 105