1
1
extern crate tokio_codec;
2
2
extern crate websocket;
3
+ extern crate base64;
3
4
4
5
use self :: websocket:: stream:: r#async:: Stream as WsStream ;
5
6
use self :: websocket:: OwnedMessage ;
@@ -37,6 +38,11 @@ pub struct WsReadWrapper<T: WsStream + 'static> {
37
38
pub debt : ReadDebt ,
38
39
pub pong_timeout : Option < ( :: tokio_timer:: Delay , :: std:: time:: Duration ) > ,
39
40
pub ping_aborter : Option < :: futures:: unsync:: oneshot:: Sender < ( ) > > ,
41
+
42
+ pub text_prefix : Option < String > ,
43
+ pub binary_prefix : Option < String > ,
44
+ pub binary_base64 : bool ,
45
+ pub text_base64 : bool ,
40
46
}
41
47
42
48
impl < T : WsStream + ' static > AsyncRead for WsReadWrapper < T > { }
@@ -54,6 +60,35 @@ impl<T: WsStream + 'static> Read for WsReadWrapper<T> {
54
60
brokenpipe( )
55
61
} } ;
56
62
}
63
+ fn process_prefixes_and_base64 < ' a > ( qbuf : & ' a mut Vec < u8 > , q : & mut & ' a [ u8 ] , prefix : & Option < String > , base64 : bool ) {
64
+ match ( prefix, base64) {
65
+ ( None , false ) => ( ) ,
66
+ ( Some ( pr) , false ) => {
67
+ debug ! ( "prepending prefix" ) ;
68
+ qbuf. reserve_exact ( pr. len ( ) + q. len ( ) ) ;
69
+ qbuf. extend_from_slice ( pr. as_bytes ( ) ) ;
70
+ qbuf. extend_from_slice ( q) ;
71
+ * q = & mut qbuf[ ..] ;
72
+ }
73
+ ( None , true ) => {
74
+ debug ! ( "encoding to base64" ) ;
75
+ qbuf. resize ( q. len ( ) * 3 / 2 + 3 , 0 ) ;
76
+ let r = base64:: encode_config_slice ( q, base64:: STANDARD , & mut qbuf[ ..] ) ;
77
+ qbuf. resize ( r, 0 ) ;
78
+ qbuf. push ( b'\n' ) ;
79
+ * q = & mut qbuf[ ..] ;
80
+ } ,
81
+ ( Some ( pr) , true ) => {
82
+ debug ! ( "prepending prefix and encoding to base64" ) ;
83
+ qbuf. extend_from_slice ( pr. as_bytes ( ) ) ;
84
+ qbuf. resize ( pr. len ( ) + q. len ( ) * 3 / 2 + 3 , 0 ) ;
85
+ let r = base64:: encode_config_slice ( q, base64:: STANDARD , & mut qbuf[ pr. len ( ) ..] ) ;
86
+ qbuf. resize ( pr. len ( ) +r, 0 ) ;
87
+ qbuf. push ( b'\n' ) ;
88
+ * q = & mut qbuf[ ..] ;
89
+ } ,
90
+ }
91
+ }
57
92
loop {
58
93
return match self . s . poll ( ) . map_err ( io_other_error) ? {
59
94
Ready ( Some ( OwnedMessage :: Close ( _) ) ) => {
@@ -97,14 +132,20 @@ impl<T: WsStream + 'static> Read for WsReadWrapper<T> {
97
132
}
98
133
Ready ( Some ( OwnedMessage :: Text ( x) ) ) => {
99
134
debug ! ( "incoming text" ) ;
100
- match self . debt . process_message ( buf, x. as_str ( ) . as_bytes ( ) ) {
135
+ let mut qbuf : Vec < u8 > = vec ! [ ] ;
136
+ let mut q : & [ u8 ] = x. as_str ( ) . as_bytes ( ) ;
137
+ process_prefixes_and_base64 ( & mut qbuf, & mut q, & self . text_prefix , self . text_base64 ) ;
138
+ match self . debt . process_message ( buf, q) {
101
139
ProcessMessageResult :: Return ( x) => x,
102
140
ProcessMessageResult :: Recurse => continue ,
103
141
}
104
142
}
105
143
Ready ( Some ( OwnedMessage :: Binary ( x) ) ) => {
106
144
debug ! ( "incoming binary" ) ;
107
- match self . debt . process_message ( buf, x. as_slice ( ) ) {
145
+ let mut qbuf : Vec < u8 > = vec ! [ ] ;
146
+ let mut q : & [ u8 ] = x. as_slice ( ) ;
147
+ process_prefixes_and_base64 ( & mut qbuf, & mut q, & self . binary_prefix , self . binary_base64 ) ;
148
+ match self . debt . process_message ( buf, q) {
108
149
ProcessMessageResult :: Return ( x) => x,
109
150
ProcessMessageResult :: Recurse => continue ,
110
151
}
@@ -135,14 +176,23 @@ pub enum Mode1 {
135
176
Binary ,
136
177
}
137
178
138
- pub struct WsWriteWrapper < T : WsStream + ' static > ( pub MultiProducerWsSink < T > , pub Mode1 , pub bool ) ;
179
+ pub struct WsWriteWrapper < T : WsStream + ' static > {
180
+ pub sink : MultiProducerWsSink < T > ,
181
+ pub mode : Mode1 ,
182
+ pub close_on_shutdown : bool ,
183
+
184
+ pub text_prefix : Option < String > ,
185
+ pub binary_prefix : Option < String > ,
186
+ pub binary_base64 : bool ,
187
+ pub text_base64 : bool ,
188
+ }
139
189
140
190
impl < T : WsStream + ' static > AsyncWrite for WsWriteWrapper < T > {
141
191
fn shutdown ( & mut self ) -> futures:: Poll < ( ) , std:: io:: Error > {
142
- if !self . 2 {
192
+ if !self . close_on_shutdown {
143
193
return Ok ( Ready ( ( ) ) ) ;
144
194
}
145
- let mut sink = self . 0 . borrow_mut ( ) ;
195
+ let mut sink = self . sink . borrow_mut ( ) ;
146
196
match sink
147
197
. start_send ( OwnedMessage :: Close ( None ) )
148
198
. map_err ( io_other_error) ?
@@ -160,16 +210,56 @@ impl<T: WsStream + 'static> AsyncWrite for WsWriteWrapper<T> {
160
210
}
161
211
162
212
impl < T : WsStream + ' static > Write for WsWriteWrapper < T > {
163
- fn write ( & mut self , buf : & [ u8 ] ) -> IoResult < usize > {
164
- let om = match self . 1 {
213
+ fn write ( & mut self , buf_ : & [ u8 ] ) -> IoResult < usize > {
214
+ let bufv;
215
+ let mut effective_mode = self . mode ;
216
+
217
+ let mut buf : & [ u8 ] = buf_;
218
+
219
+ let origlen = buf. len ( ) ;
220
+
221
+ if let Some ( pr) = & self . text_prefix {
222
+ if buf. starts_with ( pr. as_bytes ( ) ) {
223
+ effective_mode = Mode1 :: Text ;
224
+ buf = & buf[ pr. len ( ) ..] ;
225
+ }
226
+ }
227
+ if let Some ( pr) = & self . binary_prefix {
228
+ if buf. starts_with ( pr. as_bytes ( ) ) {
229
+ effective_mode = Mode1 :: Binary ;
230
+ buf = & buf[ pr. len ( ) ..] ;
231
+ }
232
+ }
233
+
234
+ let decode_base64 = match effective_mode {
235
+ Mode1 :: Binary => self . binary_base64 ,
236
+ Mode1 :: Text => self . text_base64 ,
237
+ } ;
238
+
239
+ if decode_base64 {
240
+ if buf. last ( ) == Some ( & b'\n' ) {
241
+ buf = & buf[ ..( buf. len ( ) -1 ) ] ;
242
+ }
243
+ if buf. last ( ) == Some ( & b'\r' ) {
244
+ buf = & buf[ ..( buf. len ( ) -1 ) ] ;
245
+ }
246
+ if let Ok ( v) = base64:: decode ( buf) {
247
+ bufv = v;
248
+ buf = & bufv[ ..] ;
249
+ } else {
250
+ error ! ( "Failed to decode user-supplised base64 buffer. Sending message as is." ) ;
251
+ }
252
+ }
253
+
254
+ let om = match effective_mode {
165
255
Mode1 :: Binary => OwnedMessage :: Binary ( buf. to_vec ( ) ) ,
166
256
Mode1 :: Text => {
167
257
let text_tmp;
168
258
let text = match :: std:: str:: from_utf8 ( buf) {
169
259
Ok ( x) => x,
170
260
Err ( _) => {
171
261
error ! (
172
- "Invalid UTF-8 in -- text mode . Sending lossy data. May be \
262
+ "Invalid UTF-8 in a text WebSocket message . Sending lossy data. May be \
173
263
caused by unlucky buffer splits."
174
264
) ;
175
265
text_tmp = String :: from_utf8_lossy ( buf) ;
@@ -179,14 +269,14 @@ impl<T: WsStream + 'static> Write for WsWriteWrapper<T> {
179
269
OwnedMessage :: Text ( text. to_string ( ) )
180
270
}
181
271
} ;
182
- match self . 0 . borrow_mut ( ) . start_send ( om) . map_err ( io_other_error) ? {
272
+ match self . sink . borrow_mut ( ) . start_send ( om) . map_err ( io_other_error) ? {
183
273
futures:: AsyncSink :: NotReady ( _) => wouldblock ( ) ,
184
- futures:: AsyncSink :: Ready => Ok ( buf . len ( ) ) ,
274
+ futures:: AsyncSink :: Ready => Ok ( origlen ) ,
185
275
}
186
276
}
187
277
fn flush ( & mut self ) -> IoResult < ( ) > {
188
278
match self
189
- . 0
279
+ . sink
190
280
. borrow_mut ( )
191
281
. poll_complete ( )
192
282
. map_err ( io_other_error) ?
@@ -362,8 +452,21 @@ pub fn finish_building_ws_peer<S>(opts: &super::Options, duplex: Duplex<S>, clos
362
452
debt : super :: readdebt:: ReadDebt ( Default :: default ( ) , opts. read_debt_handling , zmsgh) ,
363
453
pong_timeout,
364
454
ping_aborter,
455
+ text_prefix : opts. ws_text_prefix . clone ( ) ,
456
+ binary_prefix : opts. ws_binary_prefix . clone ( ) ,
457
+ binary_base64 : opts. ws_binary_base64 ,
458
+ text_base64 : opts. ws_text_base64 ,
459
+ } ;
460
+ let ws_sin = WsWriteWrapper {
461
+ sink : mpsink,
462
+ mode : mode1,
463
+ close_on_shutdown,
464
+
465
+ text_prefix : opts. ws_text_prefix . clone ( ) ,
466
+ binary_prefix : opts. ws_binary_prefix . clone ( ) ,
467
+ binary_base64 : opts. ws_binary_base64 ,
468
+ text_base64 : opts. ws_text_base64 ,
365
469
} ;
366
- let ws_sin = WsWriteWrapper ( mpsink, mode1, close_on_shutdown) ;
367
470
368
471
Peer :: new ( ws_str, ws_sin, hup)
369
472
}
0 commit comments