| ... |
... |
@@ -50,7 +50,7 @@ HTTP_METHODS_T = Literal[ |
|
50
|
50
|
CHUNK_SIZE = 32768
|
|
51
|
51
|
DEFAULT_USER_AGENT = f'nbxmpp/{nbxmpp.__version__}'
|
|
52
|
52
|
SIGNAL_ACTIONS = GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION
|
|
53
|
|
-
|
|
|
53
|
+MIN_SOUP_3_4 = Soup.check_version(3, 4, 0)
|
|
54
|
54
|
|
|
55
|
55
|
class HTTPLogAdapter(logging.LoggerAdapter):
|
|
56
|
56
|
def process(self, msg: str, kwargs: Any) -> tuple[str, Any]:
|
| ... |
... |
@@ -278,6 +278,10 @@ class HTTPRequest(GObject.GObject): |
|
278
|
278
|
self._message.connect('got-body', self._on_got_body)
|
|
279
|
279
|
self._message.connect('restarted', self._on_restarted)
|
|
280
|
280
|
self._message.connect('finished', self._on_finished)
|
|
|
281
|
+ self._message.connect('got-headers', self._on_got_headers)
|
|
|
282
|
+
|
|
|
283
|
+ if MIN_SOUP_3_4:
|
|
|
284
|
+ self._message.connect('got-body-data', self._on_got_body_data)
|
|
281
|
285
|
|
|
282
|
286
|
soup_session = self._session.get_soup_session()
|
|
283
|
287
|
soup_session.send_async(self._message,
|
| ... |
... |
@@ -360,11 +364,9 @@ class HTTPRequest(GObject.GObject): |
|
360
|
364
|
self._finish_read()
|
|
361
|
365
|
return
|
|
362
|
366
|
|
|
363
|
|
- length = len(bytes_)
|
|
364
|
|
- self._received_size += length
|
|
365
|
|
- if self._received_size > self._response_content_length:
|
|
366
|
|
- self._finish_read(HTTPRequestError.CONTENT_OVERFLOW)
|
|
367
|
|
- return
|
|
|
367
|
+ if not MIN_SOUP_3_4:
|
|
|
368
|
+ self._received_size += len(bytes_)
|
|
|
369
|
+ self._check_content_overflow()
|
|
368
|
370
|
|
|
369
|
371
|
if self._output_stream is None:
|
|
370
|
372
|
self._response_body_data += bytes_
|
| ... |
... |
@@ -383,11 +385,8 @@ class HTTPRequest(GObject.GObject): |
|
383
|
385
|
|
|
384
|
386
|
self._read_async()
|
|
385
|
387
|
|
|
386
|
|
- if (self._emit_response_progress and
|
|
387
|
|
- self._message.get_method() == 'GET'):
|
|
388
|
|
- self.emit('response-progress',
|
|
389
|
|
- self._received_size / self._response_content_length)
|
|
390
|
|
-
|
|
|
388
|
+ if not MIN_SOUP_3_4:
|
|
|
389
|
+ self._emit_progress()
|
|
391
|
390
|
|
|
392
|
391
|
def _finish_read(self, error: Optional[HTTPRequestError] = None) -> None:
|
|
393
|
392
|
self._log.info('Finished reading')
|
| ... |
... |
@@ -404,11 +403,7 @@ class HTTPRequest(GObject.GObject): |
|
404
|
403
|
) -> None:
|
|
405
|
404
|
|
|
406
|
405
|
# Signal is only raised when there is content in the response
|
|
407
|
|
-
|
|
408
|
406
|
headers = message.get_response_headers()
|
|
409
|
|
-
|
|
410
|
|
- self._response_content_length = headers.get_content_length()
|
|
411
|
|
-
|
|
412
|
407
|
if content_type is None:
|
|
413
|
408
|
# According to the docs, content_type is None when the sniffer
|
|
414
|
409
|
# decides to trust the content-type sent by the server.
|
| ... |
... |
@@ -416,14 +411,19 @@ class HTTPRequest(GObject.GObject): |
|
416
|
411
|
|
|
417
|
412
|
self._response_content_type = content_type or ''
|
|
418
|
413
|
|
|
419
|
|
- self._log.info('Sniffed: content-type: %s, content-length: %s',
|
|
420
|
|
- self._response_content_type,
|
|
421
|
|
- self._response_content_length)
|
|
|
414
|
+ self._log.info('Sniffed: content-type: %s',
|
|
|
415
|
+ self._response_content_type)
|
|
422
|
416
|
|
|
423
|
417
|
self.emit('content-sniffed',
|
|
424
|
418
|
self._response_content_length,
|
|
425
|
419
|
self._response_content_type)
|
|
426
|
420
|
|
|
|
421
|
+ def _on_got_headers(self, message: Soup.Message) -> None:
|
|
|
422
|
+ headers = message.get_response_headers()
|
|
|
423
|
+ self._response_content_length = headers.get_content_length()
|
|
|
424
|
+ self._log.info('Got Headers: content-length: %s',
|
|
|
425
|
+ self._response_content_length)
|
|
|
426
|
+
|
|
427
|
427
|
def _on_got_body(self, _message: Soup.Message) -> None:
|
|
428
|
428
|
# This signal tells us that the full body was received.
|
|
429
|
429
|
# The `finished` signal is not a sure indicator if the message body
|
| ... |
... |
@@ -432,11 +432,38 @@ class HTTPRequest(GObject.GObject): |
|
432
|
432
|
self._log.info('Body received')
|
|
433
|
433
|
self._body_received = True
|
|
434
|
434
|
|
|
|
435
|
+ def _on_got_body_data(self,
|
|
|
436
|
+ _message: Soup.Message,
|
|
|
437
|
+ chunk_size: int
|
|
|
438
|
+ ) -> None:
|
|
|
439
|
+
|
|
|
440
|
+ self._received_size += chunk_size
|
|
|
441
|
+ self._check_content_overflow()
|
|
|
442
|
+
|
|
|
443
|
+ status = self._message.get_status()
|
|
|
444
|
+ if status in (Soup.Status.OK, Soup.Status.CREATED):
|
|
|
445
|
+ self._emit_progress()
|
|
|
446
|
+
|
|
|
447
|
+ def _emit_progress(self) -> None:
|
|
|
448
|
+ if not self._emit_response_progress:
|
|
|
449
|
+ return
|
|
|
450
|
+
|
|
|
451
|
+ if not self._message.get_method() == 'GET':
|
|
|
452
|
+ return
|
|
|
453
|
+
|
|
|
454
|
+ self.emit('response-progress',
|
|
|
455
|
+ self._received_size / self._response_content_length)
|
|
|
456
|
+
|
|
|
457
|
+ def _check_content_overflow(self) -> None:
|
|
|
458
|
+ if self._received_size > self._response_content_length:
|
|
|
459
|
+ self._finish_read(HTTPRequestError.CONTENT_OVERFLOW)
|
|
|
460
|
+
|
|
435
|
461
|
def _on_restarted(self, _message: Soup.Message) -> None:
|
|
436
|
462
|
self._log.info('Restarted')
|
|
437
|
463
|
self._body_received = False
|
|
438
|
464
|
self._response_content_type = ''
|
|
439
|
465
|
self._response_content_length = 0
|
|
|
466
|
+ self._received_size = 0
|
|
440
|
467
|
|
|
441
|
468
|
def _on_finished(self, _message: Soup.Message) -> None:
|
|
442
|
469
|
self._log.info('Message finished')
|