diff --git a/synapse/http/matrixfederationclient.py b/synapse/http/matrixfederationclient.py
index c3589534f8..d5970c05a8 100644
--- a/synapse/http/matrixfederationclient.py
+++ b/synapse/http/matrixfederationclient.py
@@ -33,6 +33,7 @@ from synapse.api.errors import (
from signedjson.sign import sign_json
+import cgi
import simplejson as json
import logging
import random
@@ -155,9 +156,7 @@ class MatrixFederationHttpClient(object):
time_out=timeout / 1000. if timeout else 60,
)
- response = yield preserve_context_over_fn(
- send_request,
- )
+ response = yield preserve_context_over_fn(send_request)
log_result = "%d %s" % (response.code, response.phrase,)
break
@@ -248,7 +247,7 @@ class MatrixFederationHttpClient(object):
@defer.inlineCallbacks
def put_json(self, destination, path, data={}, json_data_callback=None,
- long_retries=False):
+ long_retries=False, timeout=None):
""" Sends the specifed json data using PUT
Args:
@@ -261,6 +260,8 @@ class MatrixFederationHttpClient(object):
use as the request body.
long_retries (bool): A boolean that indicates whether we should
retry for a short or long time.
+ timeout(int): How long to try (in ms) the destination for before
+ giving up. None indicates no timeout.
Returns:
Deferred: Succeeds when we get a 2xx HTTP response. The result
@@ -287,22 +288,19 @@ class MatrixFederationHttpClient(object):
body_callback=body_callback,
headers_dict={"Content-Type": ["application/json"]},
long_retries=long_retries,
+ timeout=timeout,
)
if 200 <= response.code < 300:
# We need to update the transactions table to say it was sent?
- c_type = response.headers.getRawHeaders("Content-Type")
-
- if "application/json" not in c_type:
- raise RuntimeError(
- "Content-Type not application/json"
- )
+ check_content_type_is_json(response.headers)
body = yield preserve_context_over_fn(readBody, response)
defer.returnValue(json.loads(body))
@defer.inlineCallbacks
- def post_json(self, destination, path, data={}, long_retries=True):
+ def post_json(self, destination, path, data={}, long_retries=True,
+ timeout=None):
""" Sends the specifed json data using POST
Args:
@@ -313,6 +311,8 @@ class MatrixFederationHttpClient(object):
the request body. This will be encoded as JSON.
long_retries (bool): A boolean that indicates whether we should
retry for a short or long time.
+ timeout(int): How long to try (in ms) the destination for before
+ giving up. None indicates no timeout.
Returns:
Deferred: Succeeds when we get a 2xx HTTP response. The result
@@ -333,16 +333,12 @@ class MatrixFederationHttpClient(object):
body_callback=body_callback,
headers_dict={"Content-Type": ["application/json"]},
long_retries=True,
+ timeout=timeout,
)
if 200 <= response.code < 300:
# We need to update the transactions table to say it was sent?
- c_type = response.headers.getRawHeaders("Content-Type")
-
- if "application/json" not in c_type:
- raise RuntimeError(
- "Content-Type not application/json"
- )
+ check_content_type_is_json(response.headers)
body = yield preserve_context_over_fn(readBody, response)
@@ -395,12 +391,7 @@ class MatrixFederationHttpClient(object):
if 200 <= response.code < 300:
# We need to update the transactions table to say it was sent?
- c_type = response.headers.getRawHeaders("Content-Type")
-
- if "application/json" not in c_type:
- raise RuntimeError(
- "Content-Type not application/json"
- )
+ check_content_type_is_json(response.headers)
body = yield preserve_context_over_fn(readBody, response)
@@ -520,3 +511,29 @@ def _flatten_response_never_received(e):
)
else:
return "%s: %s" % (type(e).__name__, e.message,)
+
+
+def check_content_type_is_json(headers):
+ """
+ Check that a set of HTTP headers have a Content-Type header, and that it
+ is application/json.
+
+ Args:
+ headers (twisted.web.http_headers.Headers): headers to check
+
+ Raises:
+ RuntimeError if the
+
+ """
+ c_type = headers.getRawHeaders("Content-Type")
+ if c_type is None:
+ raise RuntimeError(
+ "No Content-Type header"
+ )
+
+ c_type = c_type[0] # only the first header
+ val, options = cgi.parse_header(c_type)
+ if val != "application/json":
+ raise RuntimeError(
+ "Content-Type not application/json: was '%s'" % c_type
+ )
|