Browsers close socket before response is fully loaded

I have a simple Python server that uses http.server . The goal is not to display the video on an html page, or to upload a video file, but directly display the video in a browser. This is what I have so far:

 import http.server class SuperHandler(http.server.SimpleHTTPRequestHandler): def do_GET(self): path = self.path encodedFilePath = 'file.mp4' with open(encodedFilePath, 'rb') as videoFile: self.send_response(200) self.send_header('Content-type', 'video/mp4') self.end_headers() self.wfile.write(videoFile.read()) print('File sent: ' + videoFile.name) server_address = ('', 8000) handler_class = SuperHandler httpd = http.server.HTTPServer(server_address, handler_class) httpd.serve_forever() 

The problem is that the answer does not contain the full video. file.mp4 is 50 MB, but when I look at the Chrome or Firefox network tab, it says that the response is only 1 MB. Is there a reason the full file is not migrated? Do I need to add some kind of HTTP header to do this?

EDIT:

Now this is my code:

 server_address = ('', 8000) handler_class = http.server.SimpleHTTPRequestHandler httpd = http.server.HTTPServer(server_address, handler_class) httpd.serve_forever() 

Now I use the default SimpleHTTPRequestHandler do_GET , but it still does not work (although the answer now is 40 MB / 30 MB, not 1 MB).

When I request file.mp4 in Chrome, the socket connection closes after ~ 7 seconds (~ 5 seconds in Firefox), which makes the script throw a BrokenPipeError: [Errno 32] Broken pipe , because the server is still trying to write the rest of the video file in a private socket .

So my question is: how can I get the browser to load the full answer before it closes the socket?

Additional Information

HTTP response headers sent to the client:

 HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.5.0 Date: Mon, 28 Dec 2015 02:36:39 GMT Content-type: video/mp4 Content-Length: 53038876 Last-Modified: Fri, 25 Dec 2015 02:09:52 GMT 
+5
source share
3 answers

It turns out that the video file I used was corrupted (maybe it had dropped frames or something like that). I tested several other .mp4 and it worked like a charm.

All you really need to play a video file (or rather a streaming video file, as indicated by @hrunting), as the HTTP headers for the response are related to this:

 HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.5.0 Date: Sat, 02 Jan 2016 02:45:34 GMT Content-type: video/mp4 Content-Length: 33455269 Last-Modified: Sat, 02 Jan 2016 02:45:27 GMT 

I think even the Server , Date and Last-Modified headers are optional (they are automatically sent by SimpleHTTPRequestHandler ).

As pointed out by @qarma and @hrunting, if you want the user to be able to go to a specific time in the video, you must support the Range header. It is simply recommended that you maintain the Range header, as it is sent by default to Chrome.

+1
source

For streaming video, you must support at least a range of requests and transfer- encoding: chunked

As far as I can see, http.server does not support this directly. You can, of course, implement this from above.

Alternatively, use a simple structure, for example. bottle (single file, already supports both) or cherrypy (harder, multi-threaded, etc.)

You can also do without Python code, for example. if you use nginx

+1
source

Basically, @qarma is right. For video streaming, you need to use a library or framework that supports at least Range: headers.

But you are not trying / trying to transfer the video. The browser does this for you. When you return the video/mp4 content type, a browser that knows how to stream video itself immediately switches to streaming mode. It stops the file download (the source of your channel errors) and restarts with the Range: header. To do this, it uses the existing media player code in the browser. Since the SimpleHTTPServer class SimpleHTTPServer not support the Range: header, it does not handle the response properly.

If you want to prevent this streaming behavior and force the browser to download the file without playing it, return the Content-Disposition header, forcing it to process the video file as a downloaded file, and not as part of the content that should be rendered.

Here is some code based on your initial question that does what you want:

 import http.server class SuperHandler(http.server.SimpleHTTPRequestHandler): def do_GET(self): path = self.path encodedFilePath = 'file.mp4' with open(encodedFilePath, 'rb') as videoFile: self.send_response(200) self.send_header('Content-type', 'video/mp4') self.send_header('Content-Disposition', 'attachment; filename=' + encodedFilePath) self.end_headers() self.copyfile(videoFile, self.wfile) server_address = ('', 8000) handler_class = SuperHandler httpd = http.server.HTTPServer(server_address, handler_class) httpd.serve_forever() 

Theoretically, you are also sending back Accept-Ranges: none , but Chrome, at least, seems to ignore this.

+1
source

Source: https://habr.com/ru/post/1239179/


All Articles