2121#include " async_simple/Unit.h"
2222#include " async_simple/coro/FutureAwaiter.h"
2323#include " async_simple/coro/Lazy.h"
24+ #ifdef CINATRA_ENABLE_GZIP
25+ #include " gzip.hpp"
26+ #endif
2427#include " cinatra_log_wrapper.hpp"
2528#include " http_parser.hpp"
2629#include " multipart.hpp"
@@ -273,6 +276,12 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
273276 return std::move (body_);
274277 }
275278
279+ #ifdef CINATRA_ENABLE_GZIP
280+ void set_ws_deflate (bool enable_ws_deflate) {
281+ enable_ws_deflate_ = enable_ws_deflate;
282+ }
283+ #endif
284+
276285 // only make socket connet(or handshake) to the host
277286 async_simple::coro::Lazy<resp_data> connect (std::string uri) {
278287 resp_data data{};
@@ -298,10 +307,30 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
298307 }
299308 add_header (" Sec-WebSocket-Key" , ws_sec_key_);
300309 add_header (" Sec-WebSocket-Version" , " 13" );
301-
310+ #ifdef CINATRA_ENABLE_GZIP
311+ if (enable_ws_deflate_)
312+ add_header (" Sec-WebSocket-Extensions" ,
313+ " permessage-deflate; client_max_window_bits" );
314+ #endif
302315 req_context<> ctx{};
303316 data = co_await async_request (std::move (uri), http_method::GET,
304317 std::move (ctx));
318+
319+ #ifdef CINATRA_ENABLE_GZIP
320+ if (enable_ws_deflate_) {
321+ for (auto c : data.resp_headers ) {
322+ if (c.name == " Sec-WebSocket-Extensions" ) {
323+ if (c.value .find (" permessage-deflate;" ) != std::string::npos) {
324+ is_server_support_ws_deflate_ = true ;
325+ }
326+ else {
327+ is_server_support_ws_deflate_ = false ;
328+ }
329+ break ;
330+ }
331+ }
332+ }
333+ #endif
305334 co_return data;
306335 }
307336 data = co_await connect (u);
@@ -382,37 +411,91 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
382411 }
383412
384413 if constexpr (is_span_v<Source>) {
385- std::string encode_header = ws.encode_frame (source, op, true );
386- std::vector<asio::const_buffer> buffers{
387- asio::buffer (encode_header.data (), encode_header.size ()),
388- asio::buffer (source.data (), source.size ())};
389-
390- auto [ec, _] = co_await async_write (buffers);
391- if (ec) {
392- data.net_err = ec;
393- data.status = 404 ;
414+ #ifdef CINATRA_ENABLE_GZIP
415+ if (enable_ws_deflate_ && is_server_support_ws_deflate_) {
416+ std::string dest_buf;
417+ if (cinatra::gzip_codec::deflate ({source.data (), source.size ()},
418+ dest_buf)) {
419+ std::span<char > msg (dest_buf.data (), dest_buf.size ());
420+ auto header = ws.encode_frame (msg, op, true , true );
421+ std::vector<asio::const_buffer> buffers{asio::buffer (header),
422+ asio::buffer (dest_buf)};
423+
424+ auto [ec, sz] = co_await async_write (buffers);
425+ if (ec) {
426+ data.net_err = ec;
427+ data.status = 404 ;
428+ }
429+ }
430+ else {
431+ CINATRA_LOG_ERROR << " compuress data error, data: "
432+ << std::string (source.begin (), source.end ());
433+ data.net_err = std::make_error_code (std::errc::protocol_error);
434+ data.status = 404 ;
435+ }
394436 }
395- }
396- else {
397- while (true ) {
398- auto result = co_await source ();
399-
400- std::span<char > msg (result.buf .data (), result.buf .size ());
401- std::string encode_header = ws.encode_frame (msg, op, result.eof );
437+ else {
438+ #endif
439+ std::string encode_header = ws.encode_frame (source, op, true );
402440 std::vector<asio::const_buffer> buffers{
403441 asio::buffer (encode_header.data (), encode_header.size ()),
404- asio::buffer (msg .data (), msg .size ())};
442+ asio::buffer (source .data (), source .size ())};
405443
406444 auto [ec, _] = co_await async_write (buffers);
407445 if (ec) {
408446 data.net_err = ec;
409447 data.status = 404 ;
410- break ;
411448 }
449+ #ifdef CINATRA_ENABLE_GZIP
450+ }
451+ #endif
452+ }
453+ else {
454+ while (true ) {
455+ auto result = co_await source ();
456+ #ifdef CINATRA_ENABLE_GZIP
457+ if (enable_ws_deflate_ && is_server_support_ws_deflate_) {
458+ std::string dest_buf;
459+ if (cinatra::gzip_codec::deflate (
460+ {result.buf .data (), result.buf .size ()}, dest_buf)) {
461+ std::span<char > msg (dest_buf.data (), dest_buf.size ());
462+ std::string header = ws.encode_frame (msg, op, result.eof , true );
463+ std::vector<asio::const_buffer> buffers{asio::buffer (header),
464+ asio::buffer (dest_buf)};
465+ auto [ec, sz] = co_await async_write (buffers);
466+ if (ec) {
467+ data.net_err = ec;
468+ data.status = 404 ;
469+ }
470+ }
471+ else {
472+ CINATRA_LOG_ERROR << " compuress data error, data: "
473+ << std::string (result.buf .data ());
474+ data.net_err = std::make_error_code (std::errc::protocol_error);
475+ data.status = 404 ;
476+ }
477+ }
478+ else {
479+ #endif
480+ std::span<char > msg (result.buf .data (), result.buf .size ());
481+ std::string encode_header = ws.encode_frame (msg, op, result.eof );
482+ std::vector<asio::const_buffer> buffers{
483+ asio::buffer (encode_header.data (), encode_header.size ()),
484+ asio::buffer (msg.data (), msg.size ())};
412485
413- if (result.eof ) {
414- break ;
486+ auto [ec, _] = co_await async_write (buffers);
487+ if (ec) {
488+ data.net_err = ec;
489+ data.status = 404 ;
490+ break ;
491+ }
492+
493+ if (result.eof ) {
494+ break ;
495+ }
496+ #ifdef CINATRA_ENABLE_GZIP
415497 }
498+ #endif
416499 }
417500 }
418501
@@ -1839,9 +1922,28 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
18391922 }
18401923 }
18411924
1842- data.status = 200 ;
1843- data.resp_body = {data_ptr, payload_len};
1925+ #ifdef CINATRA_ENABLE_GZIP
1926+ if (!is_close_frame && is_server_support_ws_deflate_ &&
1927+ enable_ws_deflate_) {
1928+ inflate_str_.clear ();
1929+ if (!cinatra::gzip_codec::inflate ({data_ptr, payload_len},
1930+ inflate_str_)) {
1931+ CINATRA_LOG_ERROR << " uncompuress data error" ;
1932+ data.status = 404 ;
1933+ data.net_err = std::make_error_code (std::errc::protocol_error);
1934+ co_return data;
1935+ }
1936+ data.status = 200 ;
1937+ data.resp_body = {inflate_str_.data (), inflate_str_.size ()};
1938+ }
1939+ else {
1940+ #endif
18441941
1942+ data.status = 200 ;
1943+ data.resp_body = {data_ptr, payload_len};
1944+ #ifdef CINATRA_ENABLE_GZIP
1945+ }
1946+ #endif
18451947 read_buf.consume (read_buf.size ());
18461948 header_size = 2 ;
18471949
@@ -2024,6 +2126,12 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
20242126 std::string resp_chunk_str_;
20252127 std::span<char > out_buf_;
20262128
2129+ #ifdef CINATRA_ENABLE_GZIP
2130+ bool enable_ws_deflate_ = false ;
2131+ bool is_server_support_ws_deflate_ = false ;
2132+ std::string inflate_str_;
2133+ #endif
2134+
20272135#ifdef BENCHMARK_TEST
20282136 std::string req_str_;
20292137 bool stop_bench_ = false ;
0 commit comments