11#pragma once
22#include < boost/algorithm/string/predicate.hpp>
3+ #include < boost/algorithm/string/split.hpp>
34#include < boost/array.hpp>
45#include " crow/socket_adaptors.h"
56#include " crow/http_request.h"
67#include " crow/TinySHA1.hpp"
8+ #include " crow/zlib.hpp"
79
810namespace crow
911{
@@ -61,8 +63,19 @@ namespace crow
6163 return ;
6264 }
6365 }
64-
65- // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
66+ #ifdef CROW_ENABLE_WEBSOCKET_COMPRESSION
67+ std::string extensionsHeader = req.get_header_value (" Sec-WebSocket-Extensions" );
68+ std::vector<std::string> extensions;
69+ boost::split (extensions, extensionsHeader, boost::is_any_of (" ;" ));
70+ if (std::find (extensions.begin (), extensions.end (), " permessage-deflate" ) != extensions.end ())
71+ {
72+ bool reset_compressor_on_send_ = std::find (extensions.begin (), extensions.end (), " server_no_context_takeover" ) != extensions.end ();
73+ compressor_.reset (new zlib_compressor (reset_compressor_on_send_, true , 15 , Z_BEST_COMPRESSION , 8 , Z_DEFAULT_STRATEGY ));
74+ bool reset_decompressor_on_send_ = std::find (extensions.begin (), extensions.end (), " client_no_context_takeover" ) != extensions.end ();
75+ decompressor_.reset (new zlib_decompressor (reset_decompressor_on_send_, true , 15 ));
76+ }
77+ #endif
78+ // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
6679 // Sec-WebSocket-Version: 13
6780 std::string magic = req.get_header_value (" Sec-WebSocket-Key" ) + " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ;
6881 sha1::SHA1 s;
@@ -98,19 +111,35 @@ namespace crow
98111 void send_binary (const std::string& msg) override
99112 {
100113 dispatch ([this , msg]{
101- auto header = build_header (2 , msg.size ());
102- write_buffers_.emplace_back (std::move (header));
103- write_buffers_.emplace_back (msg);
114+ if (compressor_) {
115+ std::string msg_ = compressor_->compress (msg);
116+ auto header = build_header (0x42 , msg_.size ());
117+ write_buffers_.emplace_back (std::move (header));
118+ write_buffers_.emplace_back (std::move (msg_));
119+ }
120+ else {
121+ auto header = build_header (2 , msg.size ());
122+ write_buffers_.emplace_back (std::move (header));
123+ write_buffers_.emplace_back (msg);
124+ }
104125 do_write ();
105126 });
106127 }
107128
108129 void send_text (const std::string& msg) override
109130 {
110131 dispatch ([this , msg]{
111- auto header = build_header (1 , msg.size ());
112- write_buffers_.emplace_back (std::move (header));
113- write_buffers_.emplace_back (msg);
132+ if (compressor_) {
133+ std::string msg_ = compressor_->compress (msg);
134+ auto header = build_header (0x41 , msg_.size ());
135+ write_buffers_.emplace_back (std::move (header));
136+ write_buffers_.emplace_back (std::move (msg_));
137+ }
138+ else {
139+ auto header = build_header (1 , msg.size ());
140+ write_buffers_.emplace_back (std::move (header));
141+ write_buffers_.emplace_back (msg);
142+ }
114143 do_write ();
115144 });
116145 }
@@ -167,6 +196,16 @@ namespace crow
167196 write_buffers_.emplace_back (header);
168197 write_buffers_.emplace_back (std::move (hello));
169198 write_buffers_.emplace_back (crlf);
199+ if (compressor_ && decompressor_) {
200+ write_buffers_.emplace_back (
201+ " Sec-WebSocket-Extensions: permessage-deflate"
202+ " ; server_max_window_bits=" + std::to_string (decompressor_->window_bits ) +
203+ " ; client_max_window_bits=" + std::to_string (compressor_->window_bits ) +
204+ (compressor_->reset_before_compress ? " ; server_no_context_takeover" : " " ) +
205+ (decompressor_->reset_before_decompress ? " ; client_no_context_takeover" : " " )
206+ );
207+ write_buffers_.emplace_back (crlf);
208+ }
170209 write_buffers_.emplace_back (crlf);
171210 do_write ();
172211 if (open_handler_)
@@ -368,6 +407,11 @@ namespace crow
368407 return mini_header_ & 0x8000 ;
369408 }
370409
410+ bool is_compressed ()
411+ {
412+ return mini_header_ & 0x4000 ;
413+ }
414+
371415 int opcode ()
372416 {
373417 return (mini_header_ & 0x0f00 ) >> 8 ;
@@ -387,7 +431,7 @@ namespace crow
387431 if (is_FIN ())
388432 {
389433 if (message_handler_)
390- message_handler_ (*this , message_, is_binary_);
434+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
391435 message_.clear ();
392436 }
393437 }
@@ -398,7 +442,7 @@ namespace crow
398442 if (is_FIN ())
399443 {
400444 if (message_handler_)
401- message_handler_ (*this , message_, is_binary_);
445+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
402446 message_.clear ();
403447 }
404448 }
@@ -410,7 +454,7 @@ namespace crow
410454 if (is_FIN ())
411455 {
412456 if (message_handler_)
413- message_handler_ (*this , message_, is_binary_);
457+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
414458 message_.clear ();
415459 }
416460 }
@@ -514,7 +558,12 @@ namespace crow
514558 bool pong_received_{false };
515559 bool is_close_handler_called_{false };
516560
517- std::function<void (crow::websocket::connection&)> open_handler_;
561+ bool reset_compressor_on_send_{ false };
562+ bool reset_decompressor_on_send_{ false };
563+ std::unique_ptr<zlib_compressor> compressor_;
564+ std::unique_ptr<zlib_decompressor> decompressor_;
565+
566+ std::function<void (crow::websocket::connection&)> open_handler_;
518567 std::function<void (crow::websocket::connection&, const std::string&, bool )> message_handler_;
519568 std::function<void (crow::websocket::connection&, const std::string&)> close_handler_;
520569 std::function<void (crow::websocket::connection&)> error_handler_;
0 commit comments