threading(depending on what level of parallelism you need) to spawn one or more consumers when the WSGI app starts, and signal/join the consumer when the app stops.
resp.set_header('content-disposition', 'inline; filename="some-filename.pdf"')
downloadable_assets the disposition to
inline, causing the browser to either save immediately or open a Save As dialog.
downloadable_as should probably stay as-is, since its name does imply download.
Maybe we could add a new
resp method to set the
Content-Disposition header? Documentation is a good starting point, but I've made
downloadable_as slightly more complex to follow best practices for non-ASCII filename encoding (and IIRC @CaselIT has fixed a bug there since).
I need some small help, somehow I cannot find an easy solution to forwarding a stream from one request to other.
I request one service using aiohttp like
async with aiohttp.ClientSession() as session:
async with session.get(request, params=param_dict) as response:
body = await response.read()
if response.status == 200:
And then I would like to just attach the same body as a stream to response from falcon app. But when I use resp.data = body it does not work. If I manually create an IOBytestream then it complains that you cannot use byte object in await.
Any help ?
Hi @kamraj:matrix.org !
return body is no different from just
return, as Falcon does not use the return value when calling a responder. Falcon responders are expected to operate on
resp.data = await response.read() should work, although it would buffer the whole response in a bytestring first.
I'm no expert of
aiohttp, but you should also be able to simply set
async with session.get(request, params=param_dict) as response: resp.stream = response
resp.stream to response seems problematic wrt
aiohttp's lifetime management. Furthermore, constructing a new session every time is considered an antipattern.
All that said, using
response.read() works for me:
import aiohttp import falcon.asgi class Proxy(object): UPSTREAM = 'https://falconframework.org' async def handle(self, req, resp): headers = dict(req.headers, Via='Falcon') for name in ('host', 'connection', 'referer'): headers.pop(name, None) async with aiohttp.ClientSession() as session: async with session.get( self.UPSTREAM + req.path, headers=headers) as response: resp.data = await response.read() resp.content_type = response.headers.get( 'Content-Type', falcon.MEDIA_HTML) resp.status = response.status app = falcon.asgi.App() app.add_sink(Proxy().handle)
Save the above as
test.py, and run with
uvicorn test:app, then navigate to http://127.0.0.1:8000.
requests(the library), then yes,
requestsare sync-only. I'm not opinionated on
httpxseems to be getting more and more traction. Furthermore, I've heard the upcoming version of
urllib3will also support
async(or maybe it already does?).
@kamraj:matrix.org This is how you can stream responses with
import falcon.asgi import httpx class Proxy(object): UPSTREAM = 'https://falconframework.org' def __init__(self): self._client = httpx.AsyncClient() async def handle(self, req, resp): headers = dict(req.headers, Via='Falcon') for name in ('host', 'connection', 'referer'): headers.pop(name, None) request = httpx.Request( req.method, self.UPSTREAM + req.path, headers=headers) response = await self._client.send(request, stream=True) resp.stream = response.aiter_bytes() resp.content_type = response.headers.get( 'Content-Type', falcon.MEDIA_HTML) resp.status = response.status_code # See also: # https://www.python-httpx.org/async/#streaming-responses resp.schedule(response.aclose) app = falcon.asgi.App() app.add_sink(Proxy().handle)
Note that there is a caveat re manually streaming responses without a context manager & closing the response object, see also: https://www.python-httpx.org/async/#streaming-responses. I've adapted the provided example (using another framework) to Falcon.