'Python download request fails when file name has a plus (+) sign

I'm writing an application in Python to download files from a server (actually a NAS) of a friend of mine that we use for file sharing. I use its official API combined with the requests module.

Application has a bug that when the file requested has a plus (+) sign in the name the request response is "Bad gateway" (502) instead of OK (200) and download fails because it can't find the file.

If I remove the plus sign from the file name, it works.

If the name has any other special characters like underscores, dots, parenthesis, brackets, etc. it works.

Error only happens when a plus sign.

I know it has something to do with url encode skipping the plus sign for some reason and not converting it into a "%2B" which I think would be the expected behaviour if I'm not wrong.

I've seen here many questions talking about the urllib module but not sure if that's what I need and how I would use it to encode the. After many days of heavy researching I can't figure out how to fix this.

The line of code that sets the download request URL is:

download_request = requests.get(url+DOWNLOAD_API.format(path, file, sid), stream=True)

DOWNLOAD_API is:

DOWNLOAD_API = 'webapi/entry.cgi?api=SYNO.FileStation.Download&version=2&method=download&path=/{}/{}&mode=open&_sid={}'

Example of final URL causing the error:

'https://mynas.quickconnect.to:65375/webapi/entry.cgi?api=SYNO.FileStation.Download&version=2&method=download&path=/video/Example%20file+.txt&mode=open&_sid=qoHtK6Lu2TChqMJzMov65_yOg3c4e9hXKG8BTq-z3zUrbOQd2AFoEJNhSuN3uFfWFAQNh-Hf53E3nZ1v6ggX7A'

I've been looking for how to ask a good question in Stackoverflow because I'm not very used to it. Hopefully I did well.

Thanks in advance.



Solution 1:[1]

@JonClements answer was correct.

If you format the URL like I was doing:

download_request = requests.get(url+DOWNLOAD_API.format(path, file, sid), stream=True)

then you have to manually encode plus signs as %2B. Instead, you want to set all the parameters within the requests.get method, like this:

download_request = requests.get(url, 
                                params={'api':'SYNO.FileStation.Download', 'version': 2, 'method':'download', 'path':"/"+path+"/"+file, 'mode':'open', '_sid':sid},
                                stream=True)

Now it works. Bug is fixed.

Thank you so much!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AlexMnrs