Closed aalexei closed 1 year ago
Ok, one workaround is to insert a starlette route instead of using SetRoute
:
async def servePdf(request):
...
return starlette.responses.Response(
content=data,
#headers={'Content-Disposition':'attachment; filename="name.pdf"'},
media_type='application/pdf'
)
jp.app.routes.insert(0, starlette.routing.Route('/file/{uid}', endpoint=servePdf))
The problem I now have is that session_id
is not available on the request object. Any way of getting that independent of request (I'm using it to track authentication)?
Could replicate some code from justpy:
from jpcore.justpy_config import SECRET_KEY, SESSION_COOKIE_NAME
from itsdangerous import Signer
def setSessionId(request):
'''
Set session_id when bypassing JP routing
'''
cookie_signer = Signer(str(SECRET_KEY))
session_cookie = request.cookies.get(SESSION_COOKIE_NAME)
session_id = cookie_signer.unsign(session_cookie).decode("utf-8")
request.session_id = session_id
Seems fragile though, if justpy changes its cookie handling then it will break. Is there a better way of handling responses that are not WebPage
's?
@aalexei the current state of refactoring has moved the cookie handling to justpy_app in jpcore see https://github.com/justpy-org/justpy/blob/71028167e395b036e379527ed93c74ef9f86eeb8/jpcore/justpy_app.py#L379 and the code excerpt below
i consider this as a duplicate/addition to #535
current state of justpy cookie handling
def handle_session_cookie(self,request) -> typing.Union[bool, Response]:
"""
handle the session cookie for this request
Returns:
True if a new cookie and session has been created
"""
# Handle web requests
session_cookie = request.cookies.get(SESSION_COOKIE_NAME)
new_cookie=None
if SESSIONS:
new_cookie = False
if session_cookie:
try:
session_id = cookie_signer.unsign(session_cookie).decode("utf-8")
except:
return PlainTextResponse("Bad Session")
request.state.session_id = session_id
request.session_id = session_id
else:
# Create new session_id
request.state.session_id = str(uuid.uuid4().hex)
request.session_id = request.state.session_id
new_cookie = True
logging.debug(f"New session_id created: {request.session_id}")
return new_cookie
def set_cookie(self, request, response, load_page, new_cookie: typing.Union[bool, Response]):
"""
set the cookie_value
Args:
request: the request
response: the response to be sent
load_page(WebPage): the WebPage to handle
new_cookie(bool|Response): True if there is a new cookie. Or Response if cookie was invalid
"""
if isinstance(new_cookie, Response):
return new_cookie
if SESSIONS and new_cookie:
cookie_value = cookie_signer.sign(request.state.session_id)
cookie_value = cookie_value.decode("utf-8")
response.set_cookie(
SESSION_COOKIE_NAME, cookie_value, max_age=COOKIE_MAX_AGE, httponly=True
)
for k, v in load_page.cookies.items():
response.set_cookie(k, v, max_age=COOKIE_MAX_AGE, httponly=True)
return response
This is linked to #180
you might want to try the direct FastAPI approach now see #662 and https://fastapi.tiangolo.com/advanced/custom-response/
from fastapi import FastAPI
from fastapi.responses import FileResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
async def main():
return FileResponse(some_file_path)
app=JustpyApp.app and the routing needs to be in the constructor of your JustpyApp
Hi, the following code used to work in juspy but now gives a "AssertionError: Function did not return a web page but a Response"
What is the correct way of returning a binary file like a PDF?