2020-11-03 10:40:41 -05:00
|
|
|
from six import ensure_str
|
2020-10-18 11:12:44 -04:00
|
|
|
|
|
|
|
__all__ = [
|
|
|
|
"do_http",
|
|
|
|
"render",
|
|
|
|
]
|
|
|
|
|
2020-09-23 16:24:40 -04:00
|
|
|
from twisted.internet.defer import (
|
|
|
|
inlineCallbacks,
|
|
|
|
returnValue,
|
|
|
|
)
|
2020-10-22 07:13:13 -04:00
|
|
|
from twisted.web.error import (
|
|
|
|
Error,
|
|
|
|
)
|
|
|
|
from twisted.python.reflect import (
|
|
|
|
fullyQualifiedName,
|
|
|
|
)
|
|
|
|
from twisted.internet.defer import (
|
|
|
|
succeed,
|
|
|
|
)
|
|
|
|
from twisted.web.test.requesthelper import (
|
|
|
|
DummyChannel,
|
|
|
|
)
|
|
|
|
from twisted.web.error import (
|
|
|
|
UnsupportedMethod,
|
|
|
|
)
|
|
|
|
from twisted.web.http import (
|
|
|
|
NOT_ALLOWED,
|
|
|
|
)
|
|
|
|
from twisted.web.server import (
|
|
|
|
NOT_DONE_YET,
|
|
|
|
)
|
2009-02-23 14:19:43 -07:00
|
|
|
|
2020-10-22 07:13:13 -04:00
|
|
|
import treq
|
|
|
|
|
|
|
|
from ..webish import (
|
|
|
|
TahoeLAFSRequest,
|
2020-10-21 08:51:25 -04:00
|
|
|
)
|
|
|
|
|
2020-11-03 10:40:41 -05:00
|
|
|
|
|
|
|
class VerboseError(Error):
|
|
|
|
"""Include the HTTP body response too."""
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return Error.__str__(self) + " " + ensure_str(self.response)
|
|
|
|
|
|
|
|
|
2020-09-23 16:24:40 -04:00
|
|
|
@inlineCallbacks
|
2017-02-21 13:15:51 -08:00
|
|
|
def do_http(method, url, **kwargs):
|
2020-12-10 10:52:07 -05:00
|
|
|
"""
|
2020-12-14 13:53:12 -05:00
|
|
|
Run HTTP query, return Deferred of body as bytes.
|
2020-12-10 10:52:07 -05:00
|
|
|
"""
|
2017-02-21 13:15:51 -08:00
|
|
|
response = yield treq.request(method, url, persistent=False, **kwargs)
|
2020-12-14 13:53:12 -05:00
|
|
|
body = yield treq.content(response)
|
2017-02-21 13:15:51 -08:00
|
|
|
# TODO: replace this with response.fail_for_status when
|
|
|
|
# https://github.com/twisted/treq/pull/159 has landed
|
|
|
|
if 400 <= response.code < 600:
|
2020-12-10 10:52:07 -05:00
|
|
|
raise VerboseError(
|
|
|
|
response.code, response="For request {} to {}, got: {}".format(
|
|
|
|
method, url, body))
|
2020-09-23 16:24:40 -04:00
|
|
|
returnValue(body)
|
2020-10-22 07:13:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
def render(resource, query_args):
|
|
|
|
"""
|
|
|
|
Render (in the manner of the Twisted Web Site) a Twisted ``Resource``
|
|
|
|
against a request with the given query arguments .
|
|
|
|
|
|
|
|
:param resource: The page or resource to render.
|
|
|
|
|
|
|
|
:param query_args: The query arguments to put into the request being
|
|
|
|
rendered. A mapping from ``bytes`` to ``list`` of ``bytes``.
|
|
|
|
|
|
|
|
:return Deferred: A Deferred that fires with the rendered response body as
|
|
|
|
``bytes``.
|
|
|
|
"""
|
|
|
|
channel = DummyChannel()
|
|
|
|
request = TahoeLAFSRequest(channel)
|
|
|
|
request.method = b"GET"
|
|
|
|
request.args = query_args
|
|
|
|
request.prepath = [b""]
|
|
|
|
request.postpath = []
|
|
|
|
try:
|
|
|
|
result = resource.render(request)
|
|
|
|
except UnsupportedMethod:
|
|
|
|
request.setResponseCode(NOT_ALLOWED)
|
|
|
|
result = b""
|
|
|
|
|
|
|
|
if isinstance(result, bytes):
|
|
|
|
request.write(result)
|
|
|
|
done = succeed(None)
|
|
|
|
elif result == NOT_DONE_YET:
|
|
|
|
if request.finished:
|
|
|
|
done = succeed(None)
|
|
|
|
else:
|
|
|
|
done = request.notifyFinish()
|
|
|
|
else:
|
|
|
|
raise ValueError(
|
|
|
|
"{!r} returned {!r}, required bytes or NOT_DONE_YET.".format(
|
|
|
|
fullyQualifiedName(resource.render),
|
|
|
|
result,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
def get_body(ignored):
|
|
|
|
complete_response = channel.transport.written.getvalue()
|
|
|
|
header, body = complete_response.split(b"\r\n\r\n", 1)
|
|
|
|
return body
|
|
|
|
done.addCallback(get_body)
|
|
|
|
return done
|