|
7 | 7 |
|
8 | 8 | from . import base_events
|
9 | 9 | from . import compat
|
| 10 | +from . import futures |
10 | 11 | from . import protocols
|
11 | 12 | from . import transports
|
12 | 13 | from .log import logger
|
@@ -411,7 +412,7 @@ class SSLProtocol(protocols.Protocol):
|
411 | 412 |
|
412 | 413 | def __init__(self, loop, app_protocol, sslcontext, waiter,
|
413 | 414 | server_side=False, server_hostname=None,
|
414 |
| - call_connection_made=True): |
| 415 | + call_connection_made=True, shutdown_timeout=5.0): |
415 | 416 | if ssl is None:
|
416 | 417 | raise RuntimeError('stdlib ssl module not available')
|
417 | 418 |
|
@@ -442,6 +443,8 @@ def __init__(self, loop, app_protocol, sslcontext, waiter,
|
442 | 443 | self._session_established = False
|
443 | 444 | self._in_handshake = False
|
444 | 445 | self._in_shutdown = False
|
| 446 | + self._shutdown_timeout = shutdown_timeout |
| 447 | + self._shutdown_timeout_handle = None |
445 | 448 | # transport, ex: SelectorSocketTransport
|
446 | 449 | self._transport = None
|
447 | 450 | self._call_connection_made = call_connection_made
|
@@ -556,6 +559,15 @@ def _start_shutdown(self):
|
556 | 559 | self._in_shutdown = True
|
557 | 560 | self._write_appdata(b'')
|
558 | 561 |
|
| 562 | + if self._shutdown_timeout is not None: |
| 563 | + self._shutdown_timeout_handle = self._loop.call_later( |
| 564 | + self._shutdown_timeout, self._on_shutdown_timeout) |
| 565 | + |
| 566 | + def _on_shutdown_timeout(self): |
| 567 | + if self._transport is not None: |
| 568 | + self._fatal_error( |
| 569 | + futures.TimeoutError(), 'Can not complete shitdown operation') |
| 570 | + |
559 | 571 | def _write_appdata(self, data):
|
560 | 572 | self._write_backlog.append((data, 0))
|
561 | 573 | self._write_buffer_size += len(data)
|
@@ -683,12 +695,22 @@ def _fatal_error(self, exc, message='Fatal error on transport'):
|
683 | 695 | })
|
684 | 696 | if self._transport:
|
685 | 697 | self._transport._force_close(exc)
|
| 698 | + self._transport = None |
| 699 | + |
| 700 | + if self._shutdown_timeout_handle is not None: |
| 701 | + self._shutdown_timeout_handle.cancel() |
| 702 | + self._shutdown_timeout_handle = None |
686 | 703 |
|
687 | 704 | def _finalize(self):
|
688 | 705 | self._sslpipe = None
|
689 | 706 |
|
690 | 707 | if self._transport is not None:
|
691 | 708 | self._transport.close()
|
| 709 | + self._transport = None |
| 710 | + |
| 711 | + if self._shutdown_timeout_handle is not None: |
| 712 | + self._shutdown_timeout_handle.cancel() |
| 713 | + self._shutdown_timeout_handle = None |
692 | 714 |
|
693 | 715 | def _abort(self):
|
694 | 716 | try:
|
|
0 commit comments