0

Assuming as request.url

GET /fomantic-ui/default/semantic.min.css

for certain file extension, e.g. .css, I need to serve a pre-compressed .gz version.

From node-express I know an approach, that when applied to Starlette would be to simply manipulate the request.url.path and append a '.gz' to it. However that results in an AttributeError: Can't set attribute.

What would be the approach in the Starlette world?

Only thing I've found, is a middleware that should handle GZIP requests. But I think it's not usable here, because I need my own logic to decide what file to request from an AWS S3 bucket or a diskcache.

Here is an example of the route handler:

async def theme(request):
  try:
    file_path = request.path_params.get('file_path')
    is_asset = file_path.split('.')[-1] in ['ico', 'png']
    if is_asset:
      full_path = f'assets/{file_path}'
    else:
      if 'gzip' in request.headers['accept-encoding']:
        full_path = f'theme_build/{file_path}.gz'
        request.url.path = request.url.path + '.gz' # results in AttributeError("can't set attribute")
      else:
        full_path = f'theme_build/{file_path}'
    print(full_path, flush=True)
    s3_result = get_file(full_path)
    return StreamingResponse(s3_result['Body'], headers=s3_result['ResponseMetadata']['HTTPHeaders'])
  except ...

Obviously I can't just return the gzipped content as a response to the original request.url, as the browser won't expect gzipped content.

Wu Wei
  • 1,827
  • 1
  • 15
  • 27

1 Answers1

1

Probably the right way to do this at all is to set 'content-encoding': 'gzip' in the header of the response.

So, in the example above I basically do:

return StreamingResponse(
    s3_result['Body'],
    headers={**s3_result['ResponseMetadata']['HTTPHeaders'], 'content-encoding': 'gzip'}
)
Wu Wei
  • 1,827
  • 1
  • 15
  • 27