Serving a file: Difference between revisions

From XPUB & Lens-Based wiki
(New page: Example of a Python script to serve a file as a "download" link. <source lang="python"> #!/usr/bin/env python import os filepath = "/path/to/the/file" filelen = os.path.getsize(filepath)...)
 
No edit summary
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Example of a Python script to serve a file as a "download" link.
In many cases, a direct link to a file on a server will be sufficient to allow someone to get at a particular file, and download it to their local machine. In some situations, however, it is necessary or useful to have python act as an inbetween, and to "serve" the file from a script. For instance, an image serving CGI might create images on-the-fly when necessary, but have an option to serve any pre-made "cached" file as an optimization. Or you may want to serve files that are outside of the webserver's public document tree (perhaps using python to require a password or other kind of authentication to get at a file's contents).
 
== File download link ==
 
In this example, python is used to serve a file as a "download link". The particular headers used should force a web browser to prompt the user to save a file (using the original filename), and should override any attempt the browser might make to display the file in the browser.
 
{{danger}} Note that in this case the filepath is hardcoded in, but would of course more likely be based on some cgi.FieldStorage input. Make sure in that case though that you are ''very careful'' with whatever value you get from the cgi. For instance, you would want to ensure that your filepath falls within some expected directory to avoid inadvertantly exposing the contents of files you didn't intend to serve up. Files with passwords for instance could be happily served up if someone simply makes the right request if you aren't careful.


<source lang="python">
<source lang="python">
Line 5: Line 11:
import os
import os


filepath = "/path/to/the/file"
filepath = "/path/to/the/file.extension"
filelen = os.path.getsize(filepath)
filelen = os.path.getsize(filepath)


Line 24: Line 30:
f.close()
f.close()
</source>
</source>
[[Category:Cookbook]]

Latest revision as of 09:55, 31 January 2023

In many cases, a direct link to a file on a server will be sufficient to allow someone to get at a particular file, and download it to their local machine. In some situations, however, it is necessary or useful to have python act as an inbetween, and to "serve" the file from a script. For instance, an image serving CGI might create images on-the-fly when necessary, but have an option to serve any pre-made "cached" file as an optimization. Or you may want to serve files that are outside of the webserver's public document tree (perhaps using python to require a password or other kind of authentication to get at a file's contents).

File download link

In this example, python is used to serve a file as a "download link". The particular headers used should force a web browser to prompt the user to save a file (using the original filename), and should override any attempt the browser might make to display the file in the browser.

Note that in this case the filepath is hardcoded in, but would of course more likely be based on some cgi.FieldStorage input. Make sure in that case though that you are very careful with whatever value you get from the cgi. For instance, you would want to ensure that your filepath falls within some expected directory to avoid inadvertantly exposing the contents of files you didn't intend to serve up. Files with passwords for instance could be happily served up if someone simply makes the right request if you aren't careful.

#!/usr/bin/env python
import os

filepath = "/path/to/the/file.extension"
filelen = os.path.getsize(filepath)

print "Content-type: application/download"
print "Content-length: %d" % filelen
print "Content-transfer-encoding: binary"
print "Content-disposition: attachment; filename=%s" % os.path.basename(filepath)
print

f = open(filepath, "rb")
bytesserved = 0
while True:
	data = f.read(1024)
	if not data:
		break
	bytesserved += len(data)
	sys.stdout.write(data)
f.close()