0

I'm trying to download a file from Firebase Storage via the Flask app.

The target URL works on browser and when I hardcode it.

However, when I pass the target URL from the frontend as a parameter, it says urllib.error.HTTPError: HTTP Error 403: Forbidden.

Frontend Code (JavaScript)

      async function testTriggerLocalFunction(downloadURL) {
        const response = await fetch(
        // downloadURL is a string like "https://firebasestorage.googleapis.com...."
          "http://127.0.0.1:5001?audioURL=" + downloadURL
        );
        // console.log(response);
      }

Backend Code (Flask)

@app.route('/')
def handle_request():
    result = analyze(request.args.get("audioURL"))

def analyze(audioURL):
    # Download sound file
    # url = audioURL
    input_name = "input.wav"
    input_path = get_file_path(input_name)

    # 403 error when audioURL passed from url parameter passed!
    urllib.request.urlretrieve(audioURL, input_path)
    # But it will work if I do something like "audioURL = "https://firebasestorage.googleapis.com...."

Possible error points

  1. Maybe you lack proper authorization?
  2. Maybe you lack a proper header?
  • these two seem unlikely because the code works when the URL is hardcoded.
  1. URL encoding?
  • This PHP question has some URL encoding problem but I'm not sure if this applies to me.

What else can be causing this problem?

127.0.0.1 - - [09/Dec/2021 14:08:59] "GET /?audioURL=https://firebasestorage.googleapis.com/MY_TARGET_AUDIO_URL" 500 -
Traceback (most recent call last):
  File "/Users/leochoo/.virtualenvs/py-vocal-journal/lib/python3.9/site-packages/flask/app.py", line 2091, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/leochoo/.virtualenvs/py-vocal-journal/lib/python3.9/site-packages/flask/app.py", line 2076, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/leochoo/.virtualenvs/py-vocal-journal/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/leochoo/.virtualenvs/py-vocal-journal/lib/python3.9/site-packages/flask/app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/leochoo/.virtualenvs/py-vocal-journal/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/leochoo/.virtualenvs/py-vocal-journal/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/Users/leochoo/dev/vocal-journal/backend/playground/py-vocal-journal/app.py", line 68, in handle_request
    result = analyze(request.args.get("audioURL"))
  File "/Users/leochoo/dev/vocal-journal/backend/playground/py-vocal-journal/app.py", line 98, in analyze
    urllib.request.urlretrieve(audioURL, input_path)
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 239, in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 214, in urlopen
    return opener.open(url, data, timeout)
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 523, in open
    response = meth(req, response)
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 632, in http_response
    response = self.parent.error(
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 561, in error
    return self._call_chain(*args)
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 494, in _call_chain
    result = func(*args)
  File "/Users/leochoo/.pyenv/versions/3.9.1/lib/python3.9/urllib/request.py", line 641, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

I look at similar issues, but I could not identify the solution to my situation.

Can't access FireBase Database via HTTP/REST error 403 Forbidden 403 error when passing url as a parameter requests.get returns 403 while the same url works in browser urllib.request.urlretrieve ERROR trying to download jpeg in Python

Roman Svitukha
  • 1,302
  • 1
  • 12
  • 22
Leonard
  • 2,978
  • 6
  • 21
  • 42
  • have you tried printing the value of audioUrl in the analyze function to verify the parameter value is what you expected and has not been botched by the frontend request? – Keegan Murphy Dec 09 '21 at 05:54
  • @KeeganM Oh wow. I must have overlooked this. I double-checked and indeed the `&token=TOKEN_STRING` part was missing....! – Leonard Dec 09 '21 at 06:05
  • @KeeganM What would be the recommendd approach to handle in this case? Is it okay to pass token with the parameter..? Also I wonder why token part went missing hmm. – Leonard Dec 09 '21 at 06:07
  • Can you try to change `"http://127.0.0.1:5001?audioURL=" + downloadURL` to `"http://127.0.0.1:5001/?audioURL=" + downloadURL` also use console.log() in your js function to verify the variable exists and will be transmitted – Keegan Murphy Dec 09 '21 at 06:10
  • @KeeganM hmm I get a 404 error now. `127.0.0.1 - - [09/Dec/2021 15:17:07] "GET /audioURL=https://firebasestorage.googleapis.com/v0/b/vocal-journal.appspot.com/o/audio_1639030626307?alt=media&token=251030f8-2f24-4cc1-9423-2dc9d66fc743 HTTP/1.1" 404 -` just leaving token here since this is a temporary file and will be deleted later. – Leonard Dec 09 '21 at 06:18
  • Ahhhhh I see the issue – Keegan Murphy Dec 09 '21 at 06:19
  • But I guess token got passed now? Funny thing is, this is totally accessible via browser but getting 404 on Flask. – Leonard Dec 09 '21 at 06:19
  • First off revert the previous change that i suggested so the url is back to normal. Second off, the &token is being seen as the second query param even though it should just be part of the first. An easy way to fix this is when doing `+ downloadUrl`, change it to `+ downloadUrl.replace('&', '---')`, then when the downloadUrl string is received as a parameter call `audioURL.replace("---", "&")` in python – Keegan Murphy Dec 09 '21 at 06:22
  • Let me move this to chat – Leonard Dec 09 '21 at 06:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/239972/discussion-between-leonard-and-keegan-m). – Leonard Dec 09 '21 at 06:22

1 Answers1

1

There are a few ways to do this since the ?audioURL={url} parameter is acting as two parameters since it contains a & symbol:

  1. Combine both query parameters that are being received on the python server code instead of the singular one which you have intended to pass through

  2. Encode the audioURL data variable using base64 on client-side then decode on the server-side to keep the special characters that mess up the query param formatting

Glad to have helped!

Keegan Murphy
  • 767
  • 3
  • 14