How to serve a temporary file (non-static) via HTTP request? - python

I have a Python REST server, that is able to download and write a temporary file using Python TempFile.
That is, at request time I have a a file in the filesystem of the server, but it is not permanent so the client cannot access it statically (I.e. via http://myserver/path-to-my-file ). I need a way to access an endpoint, and then get a file returned based on the request. (I.e. http://myserver/myendpoint/myrequestparameters)
How does that work over HTTP? Is it possible?
(For context, right now I am serving the file encoded as string using base64 encoding and utf-8 decoding, but my frontend application needs a direct download link)

I believe there's a dedicated response type for such stuff in django. Assuming send_file is your endpoint:
from django.http import FileResponse
def send_file(response):
img = open('my_image_file.jpg', 'rb')
response = FileResponse(img)
return response

Related

Stream PDF file from http response directly to client with Python requests library using client certificate

I'm making a request to an endpoint that returns a PDF as streamable binary. This endpoint uses mutual TLS authentication so when I hit the endpoint I must send a client certificate. To achieve this I am using https://pypi.org/project/requests-pkcs12/ which supports the Python requests library.
I would like to download this PDF from the client.
Ideally when the end user clicks 'download' it hits the endpoint and directly streams the data and downloads it.
I am struggling to do this in one single step.
Currently what I'm doing is downloading the PDF to a file, then sending this file back to the client. Writing to the file is slow and I'd like to avoid the download-to-file step and simply send a streaming response back somehow.
Is there a way to stream this directly using Python's Request?
#hit the mutual tls authenticated endpoint
response = post(f'{url}, stream=True, pkcs12_filename=client_certificate_path,
pkcs12_password=client_certificate_passphrase)
#Write the returned data to a file
with open('/tmp/newfile.pdf', 'wb') as f:
f.write(response.content)
#Send the file back to client with Django's FileResponse
return FileResponse(open('/tmp/newfile.pdf', 'rb'))
While I am using Django which seems to handle this problem nicely with StreamingHttpResponse, I was unable to get this working as it doesn't allow me to send a client certificate and password protected client certificate key.

Flask redirect to external file and provide filename instead of original

I use Flask to serve application. Until recently, Flask was serving files for download using response stream.
Because of increased number of worker errors, I now need to redirect request to external location, where files are stores in 7249ed01-9c3d-45fe-895c-5a27db785d2d.tar.gz filename format. Redirect itself works, but filename displayed in save dialog in browser is still 7249ed01-9c3d-45fe-895c-5a27db785d2d.
Code example is below.
#app.route("/download/<filename>")
def view_file_download(filename):
# filename can be ignored, used to retrieve info from db
url = "https://example.com/7249ed01-9c3d-45fe-895c-5a27db785d2d.tar.gz"
filename_orig = "example.tar.gz"
filesize = 123456
res = flask.redirect(url, code=303)
res.headers.set("Location", url)
res.headers.set("Content-Disposition", "attachment", filename=filename_orig)
res.headers.set("Content-Length", filesize)
return res
It is not possible to provide content-disposition header for redirect response.
Major browsers do not support this feature any longer. It is required that server serving files contain content-disposition in own response and it will tell browser to use that instead of hashed filename.

Write to a file on a server using python

I want to write some data, e.g. "hello" on a file that is located on a remote server, not a local server. This is the code that I used to read from server:
import urllib2
var = "hello"
url = "http://url:port/log/log.txt"
response = urllib2.urlopen(url)
txt = response.read();
print txt
As an output I was able to get the data from the log file.
Now I want to write some data, e.g. "hello" onto the same file. How to achieve that?
What your code is doing is actually not "reading a file" but sending an HTTP get request to a given url and print the HTTP response's body. What you get as content for this url is up to the HTTP server serving this url, and the fact it actually comes from a file stored on this server is totally irrelevant - it might as well come from a database, from another web server, or be typed in real time by a monkey FWIW.
If you want to use the HTTP protocol to modify the content of a given file on this server, the server must provide this service (as a given url where you're supposed to send a POST or PUT http request with the new content).

python, Django related to sendinf pdf using urrlib2

I am working on Django, python and app engine, Can anyone please tell me hoe to send a pdf file to a url using urllib2,(file is InMemoryUploadedFile). I know there is a question in SOF for sending data using urllib2 with the data being in JSON format..But here I want to send a InMemoryUploadedFile which is a pdf uploaded file from html page. Thanks in advance...
You might want to look at Python: HTTP Post a large file with streaming.
You will need to use mmap for streaming the file in memory, then set it to the request and set the headers to appropriate mime type i.e application/pdf before opening the url.
import urllib2
import mmap
# Open the file as a memory mapped string. Looks like a string, but
# actually accesses the file behind the scenes.
f = open('somelargefile.pdf','rb')
mmapped_file_as_string = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
# Do the request
request = urllib2.Request(url, mmapped_file_as_string)
request.add_header("Content-Type", "application/pdf")
response = urllib2.urlopen(request)
#close everything
mmapped_file_as_string.close()
f.close()
Since Google app engine doesn't have mmap, you might want to write the file in request.FILES to the disk temporarily
#f is the file from request.FILES
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
And then read the file from there directly using standard file operations.
Another option is to use StringIO to write your file to in-memory as a string and then pass it to urlib2.request. This can be inefficient in a multi-user environment compared to using a stream.

python: download file and send it to online storage in realtime

I want to download file to my server and automatically send it to online storage(minus or dropbox) via minus or dropbox API, without saving the downloaded file in my server. So, its like streaming or pipe the HTTP connection. Right now im using minus.com API, but its require file object or local file as parameter. I can't figure out how to convert http response to file object.
It is possible to do this? if possible, how?
concept :
FILE_ON_ANOTHER_SERVER ----(http)---> MY_SERVER ----(http)----> ONLINE_STORAGE
thanks
You can get the data from a response via the read() method
response = urllib2.urlopen(request)
data = response.read()
The variable data has the binary data from the response.
Now you can create a StringIO Object which handles the data as a file like object.
import StringIO
datastream = StringIO.StringIO()
datastream.write(data)
datastream.seek(0)
#create dropbox client
client.put_file('/test', datastream)
urllib2.urlopen(url) will return a file-like object. Can you pass that directly to your minus api? See the urllib2 docs at
http://docs.python.org/library/urllib2

Categories

Resources