21
21
#include " async_simple/Unit.h"
22
22
#include " async_simple/coro/FutureAwaiter.h"
23
23
#include " async_simple/coro/Lazy.h"
24
+ #ifdef CINATRA_ENABLE_GZIP
25
+ #include " gzip.hpp"
26
+ #endif
24
27
#include " cinatra_log_wrapper.hpp"
25
28
#include " http_parser.hpp"
26
29
#include " multipart.hpp"
@@ -273,6 +276,12 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
273
276
return std::move (body_);
274
277
}
275
278
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
+
276
285
// only make socket connet(or handshake) to the host
277
286
async_simple::coro::Lazy<resp_data> connect (std::string uri) {
278
287
resp_data data{};
@@ -298,10 +307,30 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
298
307
}
299
308
add_header (" Sec-WebSocket-Key" , ws_sec_key_);
300
309
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
302
315
req_context<> ctx{};
303
316
data = co_await async_request (std::move (uri), http_method::GET,
304
317
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
305
334
co_return data;
306
335
}
307
336
data = co_await connect (u);
@@ -382,37 +411,91 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
382
411
}
383
412
384
413
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
+ }
394
436
}
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 );
402
440
std::vector<asio::const_buffer> buffers{
403
441
asio::buffer (encode_header.data (), encode_header.size ()),
404
- asio::buffer (msg .data (), msg .size ())};
442
+ asio::buffer (source .data (), source .size ())};
405
443
406
444
auto [ec, _] = co_await async_write (buffers);
407
445
if (ec) {
408
446
data.net_err = ec;
409
447
data.status = 404 ;
410
- break ;
411
448
}
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 ())};
412
485
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
415
497
}
498
+ #endif
416
499
}
417
500
}
418
501
@@ -1839,9 +1922,28 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
1839
1922
}
1840
1923
}
1841
1924
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
1844
1941
1942
+ data.status = 200 ;
1943
+ data.resp_body = {data_ptr, payload_len};
1944
+ #ifdef CINATRA_ENABLE_GZIP
1945
+ }
1946
+ #endif
1845
1947
read_buf.consume (read_buf.size ());
1846
1948
header_size = 2 ;
1847
1949
@@ -2024,6 +2126,12 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
2024
2126
std::string resp_chunk_str_;
2025
2127
std::span<char > out_buf_;
2026
2128
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
+
2027
2135
#ifdef BENCHMARK_TEST
2028
2136
std::string req_str_;
2029
2137
bool stop_bench_ = false ;
0 commit comments