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