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