Skip to content

Commit

Permalink
[k2] add http body compression (#1187)
Browse files Browse the repository at this point in the history
  • Loading branch information
apolyakov authored Dec 13, 2024
1 parent 28c7b9e commit 92f26b3
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 33 deletions.
1 change: 1 addition & 0 deletions runtime-light/server/http/http-server-state.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ inline constexpr std::string_view CONTENT_TYPE = "content-type";
inline constexpr std::string_view CONTENT_LENGTH = "content-length";
inline constexpr std::string_view AUTHORIZATION = "authorization";
inline constexpr std::string_view ACCEPT_ENCODING = "accept-encoding";
inline constexpr std::string_view CONTENT_ENCODING = "content-encoding";

} // namespace HttpHeader

Expand Down
24 changes: 21 additions & 3 deletions runtime-light/server/http/init-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <algorithm>
#include <cctype>
#include <charconv>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iterator>
Expand All @@ -25,6 +26,7 @@
#include "runtime-light/server/http/http-server-state.h"
#include "runtime-light/state/instance-state.h"
#include "runtime-light/stdlib/server/http-functions.h"
#include "runtime-light/stdlib/zlib/zlib-functions.h"
#include "runtime-light/streams/streams.h"
#include "runtime-light/tl/tl-core.h"
#include "runtime-light/tl/tl-functions.h"
Expand Down Expand Up @@ -303,10 +305,26 @@ void init_http_server(tl::K2InvokeHttp &&invoke_http) noexcept {
task_t<void> finalize_http_server(const string_buffer &output) noexcept {
auto &http_server_instance_st{HttpServerInstanceState::get()};

// TODO: compress body if needed
string body{http_server_instance_st.http_method != HttpMethod::HEAD ? output.str() : string{}};
const auto status_code{http_server_instance_st.status_code == HttpStatus::NO_STATUS ? HttpStatus::OK : http_server_instance_st.status_code};
string body{};
if (http_server_instance_st.http_method != HttpMethod::HEAD) {
body = output.str();
const bool gzip_encoded{static_cast<bool>(http_server_instance_st.encoding & HttpServerInstanceState::ENCODING_GZIP)};
const bool deflate_encoded{static_cast<bool>(http_server_instance_st.encoding & HttpServerInstanceState::ENCODING_DEFLATE)};
// compress body if needed
if (gzip_encoded || deflate_encoded) {
auto encoded_body{zlib::encode({body.c_str(), static_cast<size_t>(body.size())}, zlib::DEFAULT_COMPRESSION_LEVEL,
gzip_encoded ? zlib::ENCODING_GZIP : zlib::ENCODING_DEFLATE)};
if (encoded_body.has_value()) [[likely]] {
body = std::move(*encoded_body);

auto &static_SB{RuntimeContext::get().static_SB};
static_SB.clean() << HttpHeader::CONTENT_ENCODING.data() << ": " << (gzip_encoded ? ENCODING_GZIP.data() : ENCODING_DEFLATE.data());
header({static_SB.c_str(), static_SB.size()}, true, HttpStatus::NO_STATUS);
}
}
}

const auto status_code{http_server_instance_st.status_code == HttpStatus::NO_STATUS ? HttpStatus::OK : http_server_instance_st.status_code};
tl::httpResponse http_response{.version = tl::HttpVersion{.version = tl::HttpVersion::Version::V11},
.status_code = static_cast<int32_t>(status_code),
.headers = {},
Expand Down
27 changes: 14 additions & 13 deletions runtime-light/stdlib/zlib/zlib-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cstdint>
#include <iterator>
#include <memory>
#include <optional>
#include <span>

#include "zlib/zconf.h"
Expand Down Expand Up @@ -38,16 +39,16 @@ void zlib_static_free([[maybe_unused]] voidpf opaque, [[maybe_unused]] voidpf ad

} // namespace

namespace zlib_impl_ {
namespace zlib {

Optional<string> zlib_encode(std::span<const char> data, int64_t level, int64_t encoding) noexcept {
if (level < zlib_impl_::ZLIB_MIN_COMPRESSION_LEVEL || level > zlib_impl_::ZLIB_MAX_COMPRESSION_LEVEL) [[unlikely]] {
std::optional<string> encode(std::span<const char> data, int64_t level, int64_t encoding) noexcept {
if (level < MIN_COMPRESSION_LEVEL || level > MAX_COMPRESSION_LEVEL) [[unlikely]] {
php_warning("incorrect compression level: %" PRIi64, level);
return false;
return {};
}
if (encoding != ZLIB_ENCODING_RAW && encoding != ZLIB_ENCODING_DEFLATE && encoding != ZLIB_ENCODING_GZIP) [[unlikely]] {
if (encoding != ENCODING_RAW && encoding != ENCODING_DEFLATE && encoding != ENCODING_GZIP) [[unlikely]] {
php_warning("incorrect encoding: %" PRIi64, encoding);
return false;
return {};
}

z_stream zstrm{};
Expand All @@ -61,11 +62,11 @@ Optional<string> zlib_encode(std::span<const char> data, int64_t level, int64_t

if (deflateInit2(std::addressof(zstrm), level, Z_DEFLATED, encoding, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) [[unlikely]] {
php_warning("can't initialize zlib encode for data of length %zu", data.size());
return false;
return {};
}

auto &runtime_ctx{RuntimeContext::get()};
auto out_size_upper_bound{static_cast<size_t>(compressBound(data.size()))};
auto out_size_upper_bound{static_cast<size_t>(deflateBound(std::addressof(zstrm), data.size()))};
runtime_ctx.static_SB.clean().reserve(out_size_upper_bound);

zstrm.avail_in = data.size();
Expand All @@ -76,14 +77,14 @@ Optional<string> zlib_encode(std::span<const char> data, int64_t level, int64_t
const auto deflate_res{deflate(std::addressof(zstrm), Z_FINISH)};
if (deflate_res != Z_STREAM_END) [[unlikely]] {
php_warning("can't encode data of length %zu due to zlib error %d", data.size(), deflate_res);
return false;
return {};
}

runtime_ctx.static_SB.set_pos(static_cast<int64_t>(zstrm.total_out));
return runtime_ctx.static_SB.str();
}

Optional<string> zlib_decode(std::span<const char> data, int64_t encoding) noexcept {
std::optional<string> decode(std::span<const char> data, int64_t encoding) noexcept {
z_stream zstrm{};
// always clear zlib's state
const auto finalizer{vk::finally([&zstrm]() noexcept { inflateEnd(std::addressof(zstrm)); })};
Expand All @@ -97,7 +98,7 @@ Optional<string> zlib_decode(std::span<const char> data, int64_t encoding) noexc

if (inflateInit2(std::addressof(zstrm), encoding) != Z_OK) [[unlikely]] {
php_warning("can't initialize zlib decode for data of length %zu", data.size());
return false;
return {};
}

auto &runtime_ctx{RuntimeContext::get()};
Expand All @@ -108,10 +109,10 @@ Optional<string> zlib_decode(std::span<const char> data, int64_t encoding) noexc

if (inflate_res != Z_STREAM_END) [[unlikely]] {
php_warning("can't decode data of length %zu due to zlib error %d", data.size(), inflate_res);
return false;
return {};
}

return string{runtime_ctx.static_SB.buffer(), StringInstanceState::STATIC_BUFFER_LENGTH - zstrm.avail_out};
}

} // namespace zlib_impl_
} // namespace zlib
32 changes: 15 additions & 17 deletions runtime-light/stdlib/zlib/zlib-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,32 @@

#include <cstddef>
#include <cstdint>
#include <optional>
#include <span>

#include "runtime-common/core/runtime-core.h"

inline constexpr int64_t ZLIB_ENCODING_RAW = -0x0f;
inline constexpr int64_t ZLIB_ENCODING_DEFLATE = 0x0f;
inline constexpr int64_t ZLIB_ENCODING_GZIP = 0x1f;
namespace zlib {

namespace zlib_impl_ {
inline constexpr int64_t ENCODING_RAW = -0x0f;
inline constexpr int64_t ENCODING_DEFLATE = 0x0f;
inline constexpr int64_t ENCODING_GZIP = 0x1f;

inline constexpr int64_t ZLIB_MIN_COMPRESSION_LEVEL = -1;
inline constexpr int64_t ZLIB_MAX_COMPRESSION_LEVEL = 9;
inline constexpr int64_t ZLIB_DEFAULT_COMPRESSION_LEVEL = 6;
inline constexpr int64_t MIN_COMPRESSION_LEVEL = -1;
inline constexpr int64_t MAX_COMPRESSION_LEVEL = 9;
inline constexpr int64_t DEFAULT_COMPRESSION_LEVEL = 6;

Optional<string> zlib_encode(std::span<const char> data, int64_t level, int64_t encoding) noexcept;
std::optional<string> encode(std::span<const char> data, int64_t level, int64_t encoding) noexcept;

Optional<string> zlib_decode(std::span<const char> data, int64_t encoding) noexcept;
std::optional<string> decode(std::span<const char> data, int64_t encoding) noexcept;

} // namespace zlib_impl_
} // namespace zlib

inline string f$gzcompress(const string &data, int64_t level = zlib_impl_::ZLIB_MIN_COMPRESSION_LEVEL) noexcept {
Optional<string> result{zlib_impl_::zlib_encode({data.c_str(), static_cast<size_t>(data.size())},
level == zlib_impl_::ZLIB_MIN_COMPRESSION_LEVEL ? zlib_impl_::ZLIB_DEFAULT_COMPRESSION_LEVEL : level,
ZLIB_ENCODING_DEFLATE)};
return result.has_value() ? result.val() : string{};
inline string f$gzcompress(const string &data, int64_t level = zlib::MIN_COMPRESSION_LEVEL) noexcept {
level = level == zlib::MIN_COMPRESSION_LEVEL ? zlib::DEFAULT_COMPRESSION_LEVEL : level;
return zlib::encode({data.c_str(), static_cast<size_t>(data.size())}, level, zlib::ENCODING_DEFLATE).value_or(string{});
}

inline string f$gzuncompress(const string &data) noexcept {
Optional<string> result{zlib_impl_::zlib_decode({data.c_str(), static_cast<size_t>(data.size())}, ZLIB_ENCODING_DEFLATE)};
return result.has_value() ? result.val() : string{};
return zlib::decode({data.c_str(), static_cast<size_t>(data.size())}, zlib::ENCODING_DEFLATE).value_or(string{});
}

0 comments on commit 92f26b3

Please sign in to comment.