@@ -142,6 +142,28 @@ def _consume_exactly(self, nbytes):
142
142
yield
143
143
return (yield from self ._consume_at_most (nbytes ))
144
144
145
+ def _parse_extended_payload_length (self , opcode , payload_len ):
146
+ if opcode .iscontrol () and payload_len > 125 :
147
+ raise ParseFailed ("Control frame with payload len > 125" )
148
+ if payload_len == 126 :
149
+ data = yield from self ._consume_exactly (2 )
150
+ (payload_len ,) = struct .unpack ("!H" , data )
151
+ if payload_len <= 125 :
152
+ raise ParseFailed (
153
+ "Payload length used 2 bytes when 1 would have sufficed" )
154
+ elif payload_len == 127 :
155
+ data = yield from self ._consume_exactly (8 )
156
+ (payload_len ,) = struct .unpack ("!Q" , data )
157
+ if payload_len < 2 ** 16 :
158
+ raise ParseFailed (
159
+ "Payload length used 8 bytes when 2 would have sufficed" )
160
+ if payload_len >> 63 :
161
+ # I'm not sure why this is illegal, but that's what the RFC
162
+ # says, so...
163
+ raise ParseFailed ("8-byte payload length with non-zero MSB" )
164
+
165
+ return payload_len
166
+
145
167
def _parse_header (self ):
146
168
# returns a Header object
147
169
(fin_rsv_opcode ,) = yield from self ._consume_exactly (1 )
@@ -161,25 +183,9 @@ def _parse_header(self):
161
183
(mask_len ,) = yield from self ._consume_exactly (1 )
162
184
has_mask = bool (mask_len & 0x80 )
163
185
payload_len = mask_len & 0x7f
164
-
165
- if opcode .iscontrol () and payload_len > 125 :
166
- raise ParseFailed ("Control frame with payload len > 125" )
167
- if payload_len == 126 :
168
- data = yield from self ._consume_exactly (2 )
169
- (payload_len ,) = struct .unpack ("!H" , data )
170
- if payload_len <= 125 :
171
- raise ParseFailed (
172
- "Payload length used 2 bytes when 1 would have sufficed" )
173
- elif payload_len == 127 :
174
- data = yield from self ._consume_exactly (8 )
175
- (payload_len ,) = struct .unpack ("!Q" , data )
176
- if payload_len < 2 ** 16 :
177
- raise ParseFailed (
178
- "Payload length used 8 bytes when 2 would have sufficed" )
179
- if payload_len >> 63 :
180
- # I'm not sure why this is illegal, but that's what the RFC
181
- # says, so...
182
- raise ParseFailed ("8-byte payload length with non-zero MSB" )
186
+ payload_len = yield from self ._parse_extended_payload_length (
187
+ opcode , payload_len
188
+ )
183
189
184
190
for extension in self .extensions :
185
191
result = extension .frame_inbound_header (
@@ -247,6 +253,46 @@ def _process_CLOSE_payload(self, data):
247
253
CloseReason .INVALID_FRAME_PAYLOAD_DATA )
248
254
return (code , reason )
249
255
256
+ def _parse_frame_payload (self ,
257
+ opcode ,
258
+ remaining ,
259
+ message_decoder ,
260
+ masker ,
261
+ fin_flag ):
262
+ frame_finished = False
263
+ message_finished = False
264
+ while not frame_finished :
265
+ # For control frames, we collect all the data and return it as
266
+ # a single lump. For message frames, we stream out chunks as
267
+ # they arrive, to minimize buffering.
268
+ if opcode .iscontrol ():
269
+ data = yield from self ._consume_exactly (remaining )
270
+ else :
271
+ data = yield from self ._consume_at_most (remaining )
272
+ remaining -= len (data )
273
+ frame_finished = (remaining == 0 )
274
+ message_finished = (frame_finished and fin_flag )
275
+
276
+ data = self ._process_payload_chunk (masker , data )
277
+ if frame_finished :
278
+ data += self ._process_payload_complete (fin_flag )
279
+
280
+ if opcode is Opcode .CLOSE :
281
+ data = self ._process_CLOSE_payload (data )
282
+
283
+ if not opcode .iscontrol ():
284
+ if message_decoder is not None :
285
+ try :
286
+ data = message_decoder .decode (data , message_finished )
287
+ except UnicodeDecodeError as exc :
288
+ raise ParseFailed (
289
+ str (exc ),
290
+ CloseReason .INVALID_FRAME_PAYLOAD_DATA )
291
+
292
+ yield Frame (opcode , data , frame_finished , message_finished )
293
+
294
+ return message_finished
295
+
250
296
def parse_more_gen (self ):
251
297
# Consume as much as we can from self._buffer, yielding events, and
252
298
# then yield None when we need more data. Or raise ParseFailed.
@@ -257,7 +303,8 @@ def parse_more_gen(self):
257
303
258
304
unfinished_message_opcode = None
259
305
unfinished_message_decoder = None
260
- while True :
306
+ effective_opcode = None
307
+ while effective_opcode is not Opcode .CLOSE :
261
308
header = yield from self ._parse_header ()
262
309
263
310
if unfinished_message_opcode is None :
@@ -286,47 +333,19 @@ def parse_more_gen(self):
286
333
unfinished_message_decoder is None :
287
334
unfinished_message_decoder = getincrementaldecoder ("utf-8" )()
288
335
289
- remaining = header .payload_len
290
- frame_finished = False
291
- while not frame_finished :
292
- # For control frames, we collect all the data and return it as
293
- # a single lump. For message frames, we stream out chunks as
294
- # they arrive, to minimize buffering.
295
- if effective_opcode .iscontrol ():
296
- data = yield from self ._consume_exactly (remaining )
297
- else :
298
- data = yield from self ._consume_at_most (remaining )
299
- remaining -= len (data )
300
- frame_finished = (remaining == 0 )
301
- message_finished = (frame_finished and header .fin )
302
-
303
- data = self ._process_payload_chunk (masker , data )
304
- if frame_finished :
305
- data += self ._process_payload_complete (header .fin )
306
-
307
- if effective_opcode is Opcode .CLOSE :
308
- data = self ._process_CLOSE_payload (data )
309
-
310
- if not effective_opcode .iscontrol ():
311
- if unfinished_message_decoder is not None :
312
- try :
313
- data = unfinished_message_decoder .decode (
314
- data , message_finished )
315
- except UnicodeDecodeError as exc :
316
- raise ParseFailed (
317
- str (exc ),
318
- CloseReason .INVALID_FRAME_PAYLOAD_DATA )
319
- # This isn't a control, so if this message is finished
320
- # then the unfinished message is also finished.
321
- if message_finished :
322
- unfinished_message_opcode = None
323
- unfinished_message_decoder = None
324
-
325
- yield Frame (
326
- effective_opcode , data , frame_finished , message_finished )
327
-
328
- if effective_opcode is Opcode .CLOSE :
329
- break
336
+ message_finished = yield from self ._parse_frame_payload (
337
+ opcode = effective_opcode ,
338
+ remaining = header .payload_len ,
339
+ message_decoder = unfinished_message_decoder ,
340
+ masker = masker ,
341
+ fin_flag = header .fin
342
+ )
343
+
344
+ if message_finished and not effective_opcode .iscontrol ():
345
+ # This isn't a control, so if this message is finished
346
+ # then the unfinished message is also finished.
347
+ unfinished_message_opcode = None
348
+ unfinished_message_decoder = None
330
349
331
350
def receive_bytes (self , data ):
332
351
self ._buffer += data
0 commit comments