1
1
#pragma once
2
2
#include < boost/algorithm/string/predicate.hpp>
3
+ #include < boost/algorithm/string/split.hpp>
3
4
#include < boost/array.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,8 +63,19 @@ namespace crow
61
63
return ;
62
64
}
63
65
}
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==
66
79
// Sec-WebSocket-Version: 13
67
80
std::string magic = req.get_header_value (" Sec-WebSocket-Key" ) + " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ;
68
81
sha1::SHA1 s;
@@ -98,19 +111,35 @@ 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 ());
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
+ }
104
125
do_write ();
105
126
});
106
127
}
107
128
108
129
void send_text (const std::string& msg) override
109
130
{
110
131
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
+ }
114
143
do_write ();
115
144
});
116
145
}
@@ -167,6 +196,16 @@ namespace crow
167
196
write_buffers_.emplace_back (header);
168
197
write_buffers_.emplace_back (std::move (hello));
169
198
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
+ }
170
209
write_buffers_.emplace_back (crlf);
171
210
do_write ();
172
211
if (open_handler_)
@@ -368,6 +407,11 @@ namespace crow
368
407
return mini_header_ & 0x8000 ;
369
408
}
370
409
410
+ bool is_compressed ()
411
+ {
412
+ return mini_header_ & 0x4000 ;
413
+ }
414
+
371
415
int opcode ()
372
416
{
373
417
return (mini_header_ & 0x0f00 ) >> 8 ;
@@ -387,7 +431,7 @@ namespace crow
387
431
if (is_FIN ())
388
432
{
389
433
if (message_handler_)
390
- message_handler_ (*this , message_, is_binary_);
434
+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
391
435
message_.clear ();
392
436
}
393
437
}
@@ -398,7 +442,7 @@ namespace crow
398
442
if (is_FIN ())
399
443
{
400
444
if (message_handler_)
401
- message_handler_ (*this , message_, is_binary_);
445
+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
402
446
message_.clear ();
403
447
}
404
448
}
@@ -410,7 +454,7 @@ namespace crow
410
454
if (is_FIN ())
411
455
{
412
456
if (message_handler_)
413
- message_handler_ (*this , message_, is_binary_);
457
+ message_handler_ (*this , ( is_compressed () && decompressor_) ? decompressor_-> decompress (message_) : message_, is_binary_);
414
458
message_.clear ();
415
459
}
416
460
}
@@ -514,7 +558,12 @@ namespace crow
514
558
bool pong_received_{false };
515
559
bool is_close_handler_called_{false };
516
560
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_;
518
567
std::function<void (crow::websocket::connection&, const std::string&, bool )> message_handler_;
519
568
std::function<void (crow::websocket::connection&, const std::string&)> close_handler_;
520
569
std::function<void (crow::websocket::connection&)> error_handler_;
0 commit comments