Hi, I’m trying to build a web app that proxies Reddit hosted video for easier sharing/downloading. However, I’m running into some issues with browser requests that ask for a certain range of the video, which is done through the Range header.
Here is a snippet of code that displays the problem
@app.route("/test.mp4")
async def test_vid(request):
url = "https://v.redd.it/nki3zh3yvbv31/DASH_480?source=fallback"
headers = dict(request.headers)
headers.pop("referer", None)
headers.pop("Referer", None)
headers.pop("cookie")
headers["host"] = "v.redd.it"
headers["origin"] = "https://www.reddit.com"
headers['TE'] = "Trailers"
headers['accept'] = "*/*"
pprint(headers)
async def proxy_vid(response):
res: aiohttp.ClientResponse = await session.get(url, headers=headers)
while True:
data = await res.content.read(4096)
if not data:
res.close()
break
await response.write(data)
async with session.get(url, headers=headers) as resp:
resp_headers = dict(resp.headers)
status = resp.status
print(status)
pprint(resp_headers)
resp_headers.pop('Access-Control-Allow-Origin', False)
resp_headers.pop('Access-Control-Expose-Headers', False)
return stream(proxy_vid, status=status, headers=resp_headers, content_type="video/mp4")
Most of this is header formatting which isn’t as important. But as you can see, I’m just relaying data and headers, nothing too complicated.
If the host does not request a range, then the request works out fine. If it does however, a couple things can happen.
A request from Firefox will send Reddit the following headers
{'TE': 'Trailers',
'accept': '*/*',
'accept-language': 'en-US,en;q=0.5',
'cache-control': 'no-cache',
'connection': 'keep-alive',
'host': 'v.redd.it',
'origin': 'https://www.reddit.com',
'pragma': 'no-cache',
'range': 'bytes=2239259-',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) '
'Gecko/20100101 Firefox/72.0'}
and get back a 416 because it’s asking for out-of-range bytes in the Range header. I’m not sure how it pulls that number. The video also plays even though it only received 416 responses so I’m not sure where or how the data got to it or how to stop it from caching.
A request from Chrome will send these headers
{'TE': 'Trailers',
'accept': '*/*',
'accept-encoding': 'identity;q=1, *;q=0',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'no-cache',
'connection': 'keep-alive',
'host': 'v.redd.it',
'origin': 'https://www.reddit.com',
'pragma': 'no-cache',
'range': 'bytes=0-',
'sec-fetch-mode': 'no-cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/78.0.3886.0 Safari/537.36'}
which results in requests getting mysterious cancellation errors
socket.send() raised exception.
socket.send() raised exception.
[2019-12-26 20:45:37 -0500] [13784] [ERROR] Transport closed @ ('127.0.0.1', 60112) and exception experienced during error handling
[2019-12-26 20:45:37 -0500] [13784] [DEBUG] Exception:
Traceback (most recent call last):
File "C:\Users\pmdevita\Documents\Developer\Python\Experiments\VredditProxy\venv\lib\site-packages\sanic\server.py", line 498, in stream_response
self.request.version, keep_alive, self.keep_alive_timeout
File "C:\Users\pmdevita\Documents\Developer\Python\Experiments\VredditProxy\venv\lib\site-packages\sanic\response.py", line 110, in stream
await self.streaming_fn(self)
File "C:/Users/pmdevita/Documents/Developer/Python/Experiments/VredditProxy/main.py", line 398, in proxy_vid
data = await res.content.read(4096)
File "C:\Users\pmdevita\Documents\Developer\Python\Experiments\VredditProxy\venv\lib\site-packages\aiohttp\streams.py", line 368, in read
await self._wait('read')
File "C:\Users\pmdevita\Documents\Developer\Python\Experiments\VredditProxy\venv\lib\site-packages\aiohttp\streams.py", line 296, in _wait
await waiter
concurrent.futures._base.CancelledError
[2019-12-26 20:45:41 -0500] [13784] [DEBUG] KeepAlive Timeout. Closing connection.
[2019-12-26 20:45:42 -0500] [13784] [DEBUG] KeepAlive Timeout. Closing connection.
When embedding the mp4 in a <video>
tag in a webpage, Firefox sends requests that also get this error.
I’ve been working on this for at least a week now and I’m absolutely stumped. I have no idea how or why this error is happening. I just need to send the data from Reddit to the browser just as it would normally appear to the browser.