|
13 | 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | 14 | # See the License for the specific language governing permissions and |
15 | 15 | # limitations under the License. |
16 | | - |
17 | 16 | import logging |
18 | 17 | import urllib |
19 | 18 | from io import BytesIO |
|
38 | 37 |
|
39 | 38 | from OpenSSL import SSL |
40 | 39 | from OpenSSL.SSL import VERIFY_NONE |
41 | | -from twisted.internet import defer, protocol, ssl |
| 40 | +from twisted.internet import defer, error as twisted_error, protocol, ssl |
42 | 41 | from twisted.internet.interfaces import ( |
43 | 42 | IReactorPluggableNameResolver, |
44 | 43 | IResolutionReceiver, |
45 | 44 | ) |
46 | 45 | from twisted.internet.task import Cooperator |
47 | 46 | from twisted.python.failure import Failure |
48 | 47 | from twisted.web._newclient import ResponseDone |
49 | | -from twisted.web.client import Agent, HTTPConnectionPool, readBody |
| 48 | +from twisted.web.client import ( |
| 49 | + Agent, |
| 50 | + HTTPConnectionPool, |
| 51 | + ResponseNeverReceived, |
| 52 | + readBody, |
| 53 | +) |
50 | 54 | from twisted.web.http import PotentialDataLoss |
51 | 55 | from twisted.web.http_headers import Headers |
52 | 56 | from twisted.web.iweb import IResponse |
53 | 57 |
|
54 | 58 | from synapse.api.errors import Codes, HttpResponseException, SynapseError |
55 | | -from synapse.http import ( |
56 | | - QuieterFileBodyProducer, |
57 | | - cancelled_to_request_timed_out_error, |
58 | | - redact_uri, |
59 | | -) |
| 59 | +from synapse.http import QuieterFileBodyProducer, RequestTimedOutError, redact_uri |
60 | 60 | from synapse.http.proxyagent import ProxyAgent |
61 | 61 | from synapse.logging.context import make_deferred_yieldable |
62 | 62 | from synapse.logging.opentracing import set_tag, start_active_span, tags |
@@ -332,8 +332,6 @@ async def request( |
332 | 332 | RequestTimedOutError if the request times out before the headers are read |
333 | 333 |
|
334 | 334 | """ |
335 | | - # A small wrapper around self.agent.request() so we can easily attach |
336 | | - # counters to it |
337 | 335 | outgoing_requests_counter.labels(method).inc() |
338 | 336 |
|
339 | 337 | # log request but strip `access_token` (AS requests for example include this) |
@@ -362,15 +360,17 @@ async def request( |
362 | 360 | data=body_producer, |
363 | 361 | headers=headers, |
364 | 362 | **self._extra_treq_args |
365 | | - ) |
| 363 | + ) # type: defer.Deferred |
| 364 | + |
366 | 365 | # we use our own timeout mechanism rather than treq's as a workaround |
367 | 366 | # for https://twistedmatrix.com/trac/ticket/9534. |
368 | 367 | request_deferred = timeout_deferred( |
369 | | - request_deferred, |
370 | | - 60, |
371 | | - self.hs.get_reactor(), |
372 | | - cancelled_to_request_timed_out_error, |
| 368 | + request_deferred, 60, self.hs.get_reactor(), |
373 | 369 | ) |
| 370 | + |
| 371 | + # turn timeouts into RequestTimedOutErrors |
| 372 | + request_deferred.addErrback(_timeout_to_request_timed_out_error) |
| 373 | + |
374 | 374 | response = await make_deferred_yieldable(request_deferred) |
375 | 375 |
|
376 | 376 | incoming_responses_counter.labels(method, response.code).inc() |
@@ -410,7 +410,7 @@ async def post_urlencoded_get_json( |
410 | 410 | parsed json |
411 | 411 |
|
412 | 412 | Raises: |
413 | | - RequestTimedOutException: if there is a timeout before the response headers |
| 413 | + RequestTimedOutError: if there is a timeout before the response headers |
414 | 414 | are received. Note there is currently no timeout on reading the response |
415 | 415 | body. |
416 | 416 |
|
@@ -461,7 +461,7 @@ async def post_json_get_json( |
461 | 461 | parsed json |
462 | 462 |
|
463 | 463 | Raises: |
464 | | - RequestTimedOutException: if there is a timeout before the response headers |
| 464 | + RequestTimedOutError: if there is a timeout before the response headers |
465 | 465 | are received. Note there is currently no timeout on reading the response |
466 | 466 | body. |
467 | 467 |
|
@@ -506,7 +506,7 @@ async def get_json( |
506 | 506 | Returns: |
507 | 507 | Succeeds when we get a 2xx HTTP response, with the HTTP body as JSON. |
508 | 508 | Raises: |
509 | | - RequestTimedOutException: if there is a timeout before the response headers |
| 509 | + RequestTimedOutError: if there is a timeout before the response headers |
510 | 510 | are received. Note there is currently no timeout on reading the response |
511 | 511 | body. |
512 | 512 |
|
@@ -538,7 +538,7 @@ async def put_json( |
538 | 538 | Returns: |
539 | 539 | Succeeds when we get a 2xx HTTP response, with the HTTP body as JSON. |
540 | 540 | Raises: |
541 | | - RequestTimedOutException: if there is a timeout before the response headers |
| 541 | + RequestTimedOutError: if there is a timeout before the response headers |
542 | 542 | are received. Note there is currently no timeout on reading the response |
543 | 543 | body. |
544 | 544 |
|
@@ -586,7 +586,7 @@ async def get_raw( |
586 | 586 | Succeeds when we get a 2xx HTTP response, with the |
587 | 587 | HTTP body as bytes. |
588 | 588 | Raises: |
589 | | - RequestTimedOutException: if there is a timeout before the response headers |
| 589 | + RequestTimedOutError: if there is a timeout before the response headers |
590 | 590 | are received. Note there is currently no timeout on reading the response |
591 | 591 | body. |
592 | 592 |
|
@@ -631,7 +631,7 @@ async def get_file( |
631 | 631 | headers, absolute URI of the response and HTTP response code. |
632 | 632 |
|
633 | 633 | Raises: |
634 | | - RequestTimedOutException: if there is a timeout before the response headers |
| 634 | + RequestTimedOutError: if there is a timeout before the response headers |
635 | 635 | are received. Note there is currently no timeout on reading the response |
636 | 636 | body. |
637 | 637 |
|
@@ -684,6 +684,18 @@ async def get_file( |
684 | 684 | ) |
685 | 685 |
|
686 | 686 |
|
| 687 | +def _timeout_to_request_timed_out_error(f: Failure): |
| 688 | + if f.check(twisted_error.TimeoutError, twisted_error.ConnectingCancelledError): |
| 689 | + # The TCP connection has its own timeout (set by the 'connectTimeout' param |
| 690 | + # on the Agent), which raises twisted_error.TimeoutError exception. |
| 691 | + raise RequestTimedOutError("Timeout connecting to remote server") |
| 692 | + elif f.check(defer.TimeoutError, ResponseNeverReceived): |
| 693 | + # this one means that we hit our overall timeout on the request |
| 694 | + raise RequestTimedOutError("Timeout waiting for response from remote server") |
| 695 | + |
| 696 | + return f |
| 697 | + |
| 698 | + |
687 | 699 | # XXX: FIXME: This is horribly copy-pasted from matrixfederationclient. |
688 | 700 | # The two should be factored out. |
689 | 701 |
|
|
0 commit comments