1
1
#pragma once
2
2
#include < boost/algorithm/string/predicate.hpp>
3
3
#include < boost/array.hpp>
4
+ #include < boost/algorithm/string/split.hpp>
4
5
#include " crow/socket_adaptors.h"
5
6
#include " crow/http_request.h"
6
7
#include " crow/TinySHA1.hpp"
8
+ #include " crow/zlib.hpp"
7
9
8
10
namespace crow
9
11
{
@@ -61,7 +63,18 @@ namespace crow
61
63
return ;
62
64
}
63
65
}
64
-
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
65
78
// Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
66
79
// Sec-WebSocket-Version: 13
67
80
std::string magic = req.get_header_value (" Sec-WebSocket-Key" ) + " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ;
@@ -98,19 +111,23 @@ namespace crow
98
111
void send_binary (const std::string& msg) override
99
112
{
100
113
dispatch ([this , msg]{
101
- auto header = build_header (2 , msg.size ());
114
+ std::string msg_ = compressor_ ? compressor_->compress (msg) : msg;
115
+ auto header = build_header (2 , msg_.size ());
116
+ if (compressor_) header[0 ] += 0x40 ;
102
117
write_buffers_.emplace_back (std::move (header));
103
- write_buffers_.emplace_back (msg );
118
+ write_buffers_.emplace_back (msg_ );
104
119
do_write ();
105
120
});
106
121
}
107
122
108
123
void send_text (const std::string& msg) override
109
124
{
110
125
dispatch ([this , msg]{
111
- auto header = build_header (1 , msg.size ());
126
+ std::string msg_ = compressor_ ? compressor_->compress (msg) : msg;
127
+ auto header = build_header (1 , msg_.size ());
128
+ if (compressor_) header[0 ] += 0x40 ;
112
129
write_buffers_.emplace_back (std::move (header));
113
- write_buffers_.emplace_back (msg );
130
+ write_buffers_.emplace_back (msg_ );
114
131
do_write ();
115
132
});
116
133
}
@@ -167,6 +184,16 @@ namespace crow
167
184
write_buffers_.emplace_back (header);
168
185
write_buffers_.emplace_back (std::move (hello));
169
186
write_buffers_.emplace_back (crlf);
187
+ if (compressor_ && decompressor_) {
188
+ write_buffers_.emplace_back (
189
+ " Sec-WebSocket-Extensions: permessage-deflate"
190
+ " ; server_max_window_bits=" + std::to_string (decompressor_->window_bits ) +
191
+ " ; client_max_window_bits=" + std::to_string (compressor_->window_bits ) +
192
+ (compressor_->reset_before_compress ? " ; server_no_context_takeover" : " " ) +
193
+ (decompressor_->reset_before_decompress ? " ; client_no_context_takeover" : " " )
194
+ );
195
+ write_buffers_.emplace_back (crlf);
196
+ }
170
197
write_buffers_.emplace_back (crlf);
171
198
do_write ();
172
199
if (open_handler_)
@@ -368,6 +395,11 @@ namespace crow
368
395
return mini_header_ & 0x8000 ;
369
396
}
370
397
398
+ bool is_compressed ()
399
+ {
400
+ return mini_header_ & 0x4000 ;
401
+ }
402
+
371
403
int opcode ()
372
404
{
373
405
return (mini_header_ & 0x0f00 ) >> 8 ;
@@ -387,7 +419,7 @@ namespace crow
387
419
if (is_FIN ())
388
420
{
389
421
if (message_handler_)
390
- message_handler_ (*this , message_, is_binary_);
422
+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
391
423
message_.clear ();
392
424
}
393
425
}
@@ -398,7 +430,7 @@ namespace crow
398
430
if (is_FIN ())
399
431
{
400
432
if (message_handler_)
401
- message_handler_ (*this , message_, is_binary_);
433
+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
402
434
message_.clear ();
403
435
}
404
436
}
@@ -410,7 +442,7 @@ namespace crow
410
442
if (is_FIN ())
411
443
{
412
444
if (message_handler_)
413
- message_handler_ (*this , message_, is_binary_);
445
+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
414
446
message_.clear ();
415
447
}
416
448
}
@@ -514,6 +546,11 @@ namespace crow
514
546
bool pong_received_{false };
515
547
bool is_close_handler_called_{false };
516
548
549
+ bool reset_compressor_on_send_{false };
550
+ bool reset_decompressor_on_send_{false };
551
+ std::unique_ptr<zlib_compressor> compressor_;
552
+ std::unique_ptr<zlib_decompressor> decompressor_;
553
+
517
554
std::function<void (crow::websocket::connection&)> open_handler_;
518
555
std::function<void (crow::websocket::connection&, const std::string&, bool )> message_handler_;
519
556
std::function<void (crow::websocket::connection&, const std::string&)> close_handler_;
0 commit comments