|
165 | 165 | # SSLStream
|
166 | 166 | ################################################################
|
167 | 167 |
|
168 |
| -# XX TODO: this number was pulled out of a hat. We should tune it with |
169 |
| -# science. |
170 |
| -DEFAULT_RECEIVE_SIZE = 65536 |
| 168 | +# Ideally, when the user calls SSLStream.receive_some() with no argument, then |
| 169 | +# we should do exactly one call to self.transport_stream.receive_some(), |
| 170 | +# decrypt everything we got, and return it. Unfortunately, the way openssl's |
| 171 | +# API works, we have to pick how much data we want to allow when we call |
| 172 | +# read(), and then it (potentially) triggers a call to |
| 173 | +# transport_stream.receive_some(). So at the time we pick the amount of data |
| 174 | +# to decrypt, we don't know how much data we've read. As a simple heuristic, |
| 175 | +# we record the max amount of data returned by previous calls to |
| 176 | +# transport_stream.receive_some(), and we use that for future calls to read(). |
| 177 | +# But what do we use for the very first call? That's what this constant sets. |
| 178 | +# |
| 179 | +# Note that the value passed to read() is a limit on the amount of |
| 180 | +# *decrypted* data, but we can only see the size of the *encrypted* data |
| 181 | +# returned by transport_stream.receive_some(). TLS adds a small amount of |
| 182 | +# framing overhead, and TLS compression is rarely used these days because it's |
| 183 | +# insecure. So the size of the encrypted data should be a slight over-estimate |
| 184 | +# of the size of the decrypted data, which is exactly what we want. |
| 185 | +# |
| 186 | +# The specific value is not really based on anything; it might be worth tuning |
| 187 | +# at some point. But, if you have an TCP connection with the typical 1500 byte |
| 188 | +# MTU and an initial window of 10 (see RFC 6928), then the initial burst of |
| 189 | +# data will be limited to ~15000 bytes (or a bit less due to IP-level framing |
| 190 | +# overhead), so this is chosen to be larger than that. |
| 191 | +STARTING_RECEIVE_SIZE = 16384 |
171 | 192 |
|
172 | 193 |
|
173 | 194 | class NeedHandshakeError(Exception):
|
@@ -342,6 +363,8 @@ def __init__(
|
342 | 363 | "another task is currently receiving data on this SSLStream"
|
343 | 364 | )
|
344 | 365 |
|
| 366 | + self._estimated_receive_size = STARTING_RECEIVE_SIZE |
| 367 | + |
345 | 368 | _forwarded = {
|
346 | 369 | "context",
|
347 | 370 | "server_side",
|
@@ -537,6 +560,9 @@ async def _retry(self, fn, *args, ignore_want_read=False):
|
537 | 560 | if not data:
|
538 | 561 | self._incoming.write_eof()
|
539 | 562 | else:
|
| 563 | + self._estimated_receive_size = max( |
| 564 | + self._estimated_receive_size, len(data) |
| 565 | + ) |
540 | 566 | self._incoming.write(data)
|
541 | 567 | self._inner_recv_count += 1
|
542 | 568 | if not yielded:
|
@@ -617,10 +643,12 @@ async def receive_some(self, max_bytes=None):
|
617 | 643 | else:
|
618 | 644 | raise
|
619 | 645 | if max_bytes is None:
|
620 |
| - # Heuristic: normally we use DEFAULT_RECEIVE_SIZE, but if |
621 |
| - # the transport gave us a bunch of data last time then we'll |
622 |
| - # try to decrypt and pass it all back at once. |
623 |
| - max_bytes = max(DEFAULT_RECEIVE_SIZE, self._incoming.pending) |
| 646 | + # If we somehow have more data already in our pending buffer |
| 647 | + # than the estimate receive size, bump up our size a bit for |
| 648 | + # this read only. |
| 649 | + max_bytes = max( |
| 650 | + self._estimated_receive_size, self._incoming.pending |
| 651 | + ) |
624 | 652 | else:
|
625 | 653 | max_bytes = _operator.index(max_bytes)
|
626 | 654 | if max_bytes < 1:
|
|
0 commit comments