1

I have a basic FastAPI website with an endpoint to download an Excel template. The url's scheme is HTTPS. Until recently, this worked fine on Chrome and Safari. As people upgraded, Chrome has been blocking the download. This seems to be consistent with Google's insecure content policy implemented for 'mixed content downloads' described here:

https://blog.chromium.org/2020/02/protecting-users-from-insecure.html

My endpoint is pretty straightforward:

@router.get('/download_data_template')
def download_data_template(request: Request):
    '''Returns data template from library
    '''
    # ### auth
    # page access is authorized here
    # end auth

    file_name = 'TEMPLATE schedule_input.xlsx'

    return FileResponse(
        path=db.get_library_path(file_name),
        filename=file_name,
        media_type='application/octet-stream',
        )

The endpoint is called from a Jinja2 templated html page with this:

<a class="btn btn-primary" href="{{ url_for('upload_schedule')}}" data-toggle="tooltip" data-delay='{"show":750, "hide":250}' data-placement="top" data-toggle="tooltip" data-delay='{"show":750, "hide":250}' data-placement="top" title="click to select and upload file. The file must be in property format.">upload schedule input workbook</a>

On Chrome, the developer panel shows the following error:

"Mixed Content: The site at 'https://<my_url>.com/' was loaded over a secure connection, but the file at 'https://<my_url>.com/download_data_template' was redirected through an insecure connection. This file should be served over HTTPS. This download has been blocked. See https://blog.chromium.org/2020/02/protecting-users-from-insecure.html for more details."

The file is nothing unique, it is a basic Excel .xlsx file, a template for people to fill out.

This continues to work fine in Safari and Edge but is blocked by Chrome.

The article in the chromium blog is informative but I do not see how I can make my download secure. I have searched with no success as well.

Any thoughts on how I can make a basic file download, specifically an .xlsx file, from disc using FastAPI that will conform with Google's new policy?

Thank you for any help on this.

Chris
  • 18,724
  • 6
  • 46
  • 80
Brad Allen
  • 245
  • 3
  • 9
  • You say you're hosting this via https - insecure content blocking is activated when the download is performed over http, not http_s_. What is the actual error in your browser's development console? – MatsLindh Feb 28 '22 at 22:42
  • I added the error from the developer panel and how I call the endpoint from a url_for. I found this post that discusses url_for and https: https://stackoverflow.com/questions/70521784/fastapi-links-created-by-url-for-in-jinja2-template-use-http-instead-of-https. Is there not a less hacky-way to fix this? – Brad Allen Mar 01 '22 at 05:06

2 Answers2

4

Option 1

You could use HTTPSRedirectMiddleware to enforce all incoming requests to http being redirected to the secure scheme instead.

from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
app.add_middleware(HTTPSRedirectMiddleware)

Option 2

In addition to the above, you could use relative URLs instead of using url_for() in your Jinja2 template; for instance:

<a href="/upload_schedule">Link text</a>

In this way, the scheme of the URL will remain https.

Option 3

You could have your own url_for custom function to replace the scheme of the URL, similar to the approach demonstrated in Option 2 of this answer.


If you are behind a proxy server, such as Nginx, you may also try passing --proxy-headers parameter to Uvicorn, as described here.

Chris
  • 18,724
  • 6
  • 46
  • 80
  • Thank you for this. I am going to have to do some work with the Middleware a bit because it causes a problem with some of my other code but the relative URL at least got this working so I am functional. – Brad Allen Mar 01 '22 at 22:46
  • Option 2, using a relative URL, worked to solve my problem. I was not able to get Option 1 to work. – Brad Allen Mar 15 '23 at 13:31
1

I am developing React App over FastAPI backend and had similar issue. I am not sure what {{ url_for('upload_schedule')}} evaluates for in your rendering engine, however in my case the problem was in inaccurate URL and its handling by FastAPI.

Referring to your example, I placed in my UI code /download_data_template/, so FastAPI engine sent 307, because it redirected to /download_data_template. Replacing /download_data_template/ with /download_data_template in UI code solved that for me.

This is probably rather problem of Chrome than FastAPI, but this is a simple workaround that fixes that instantly.

pt12lol
  • 2,332
  • 1
  • 22
  • 48