redirect and force download - django

this is my problem: I have some pdf files on a server, my Django web-application
is hosted on another server (not the same of the pdf files).
On my appplication i know the pdf files link on the other server. I want to download that pdf files through my application without read them on web server application.
I try to explane. If i click on download link, my browser shows the pdf into his internal pdf viewer. I don't want this, i want that on click on a button the user will download the file without open it on internal browser.
I looked here: http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment
but this is not a good way for me, cause it requires that I read the file inside my web-application and after return it to the user.
Is it possible??

Hmm, sounds like the wrong tool for the job. You can't really "redirect" and modify the response header, which means using django just to set the Content-Disposition header would require you to stream the file through django, then have django stream it to the client.
Let a lighter weight web server handle that. If you happen to be using nginx, here's an awesome solution that fits your scenario 99% (the 1% being it's rails setting the header that nginx is waiting for).
If all you want is to set the header and the file doesn't need django processing, it would be even easier to proxy!
If you are not using nginx, I would change the title to a web server specific question about proxying a file & setting headers.

I had a similar problem recently. I have solved it downloading the file to my server and then writing it to the HttpResponse
Here is my code:
import requests
from wsgiref.util import FileWrapper
from django.http import Http404, HttpResponse
def startDownload():
url, filename, ext = someFancyLogic()
request = requests.get(url, stream=True)
# Was the request OK?
if request.status_code != requests.codes.ok:
return HttpResponse(status=400)
wrapper = FileWrapper(request.raw)
content_type = request.headers['content-type']
content_len = request.headers['content-length']
response = HttpResponse(wrapper, content_type=content_type)
response['Content-Length'] = content_len
response['Content-Disposition']
= "attachment; filename={0}.{1}".format(filename, ext)
return response

Related

Files are being downloaded at pythonanywhere server and user laptop/pc too. How to restrict to write at pythonanywhere server

Problem is i have hosted at pythonanywhere using django.Video is downloaded at pythonanywhere server and user/client system too.Thats why i used os. remove(path).After downloading it removes from server.
Is there any ways files donot write on pyhtonanywhere server. so that i donot use os.remove(path).
How to restrict to write at pythonanywhere server. Only to download at user system.
def fb_download(request):
link = request.GET.get('url')
html= requests.get(link)
try:
url= re.search('hd_src:"(.+?)"',html.text)[1]
except:
url= re.search('sd_src:"(.+?)"',html.text)[1]
path=wget.download(url, 'Video.mp4')
response=FileResponse(open(path, 'rb'), as_attachment=True)
os.remove(path)
return response
If I understand correctly, you're trying to get a request from a browser, which contains a URL. You then access the page at that URL and extract a further URL from it, and then you want to present the contents of that second URL -- a video -- to the browser.
The way you are doing that is to download the file to the server, and then to serve that up as a file attachment to the browser.
If you do it that way, then there is no way to avoid writing the file on the server; indeed, the way you are doing it right now might have problems because you are deleting the file before you've returned the response to the browser, so there may (depending on how the file deletion is processed and whether the FileResponse caches the file's contents) be cases where there is no file to send back to the browser.
But an alternative way to do it that might work would be to send a redirect response to the URL -- the one in your variable url -- like this, without downloading it at all:
def fb_download(request):
link = request.GET.get('url')
html= requests.get(link)
try:
url= re.search('hd_src:"(.+?)"',html.text)[1]
except:
url= re.search('sd_src:"(.+?)"',html.text)[1]
return redirect(url)
By doing that, the download happens on the browser instead of on the server.
I don’t understand javascript really good,
But i think if you download the file to the server
And then you can download the file to the use using JS
And i think you can use

Django HttpResponse - open file object in default editor

Take the following code snippet of a Django view
def serve_file(request)
path = 'C:/path_to_file/test.html'
file_name = os.path.basename(path)
response = HttpResponse(path)
response['Content-Disposition'] = 'attachment; filename={0}'.format(file_name)
return response
The file is served in the response and the browser asks do I want to open, but when it opens in the default editor, it opens from 'Temporary INternet Files'. How can I have this open from its original location at 'C:/path_to_file/'?
There's a fundamental disconnect here. When Django serves the file, even if it's on your own computer, the browser has to download it before it can be accessed. So the actual file that would be opened is not at the original C:/... location, but in whatever directory the file was downloaded to.
If you need users of your website to be able to edit files that persist on your server, that will require much more work than this. Downloading a file creates a copy of it on the user's computer.

How to Serve Django media user uploaded files using Cherokee with restriction to logged users

How to configure Django and Cherokee to serve media (user uploaded) files from Cherokee but to logged in users only as with #login_required on production.
Create a Django view which servers the file
Use #login_required on this view to restrict the access
Read the file from the disk using standard Python io operations
Use StreamingHttpResponse so there is no latency or memory overhead writing the response
Set response mimetype correctly
I will answer my own question
As you are using Cherokee
Remove direct access to media folder with the media URL as localhost/media/.. for exemple by removing the virtuelhost serving it
Activate (check) Allow X-Sendfile under Handler tab in Common CGI Options in the virtuelserver page that handle Django request.
Let's say you have users pictures under media/pictures to protect that will be visible to all users only. (can be modified as you want just an exemple)
Every user picture is stored in media/pictures/pk.jpg (1.jpg, 2.jpg ..)
Create a view :
#login_required(redirect_field_name=None)
def media_pictures(request,pk):
response = HttpResponse()
path=os.path.join (settings.MEDIA_ROOT,'pictures',pk+'.jpg')
if os.path.isfile(path):
#response['Content-Type']="" # add it if it's not working without ^^
response['X-Accel-Redirect'] = path
#response['X-Sendfile'] = path # same as previous line,
# X-Accel-Redirect is for NGINX and X-Sendfile is for apache , in our case cherokee is compatible with two , use one of them.
return response
return HttpResponseForbidden()
Cherokee now take care of serving the file , it's why we checked the Allow X-Sendfile , this will not work without
path variable here is the full path to the file, can be anywhere , just read accsible by cherokee user or group
4. Url conf
As we disable direct access of Media folder, we need to provide an url to access with from Django using the previous view
for exemple , To make image of user with id 17 accessible
localhost/media/pictures/17.jpg
url(r"^media/pictures/(?P<pk>\d+)\.jpg$", views.media_pictures,name="media_pictures"),
This will also work for Apache, Nginx etc , just configure your server to use X-Sendfile (or X-Accel-Redirect for Nginx), this can be easily found on docs
Using this, every logged user can view all users' pictures , feel free to add additional verifications before serving the file , per user check etc
Hope it will help someone

Django and/or Apache: serve (static) files with a different name

I store a lot of files, using a hash as file name, but when a user wants to download it, I would like to be able to give the file a new name.
Let's say the user navigates to www.myurl.com/userxy/files/some.pdf. In the Django View for that url, I can now look up the correspondig file, which might be on the server on .../files/46dfa12bbf32d523fbb3642dfee45bb4.
So how can I now get this file to be served as some.pdf to the client? Do I have to copy the file first, and giving it a different name on the disc or can I somehow serve the original file? Is what I'm trying at all good practice?
I also don't know on what level (Apache or Django) this type of operation is best handled. But since I didn't find anything about this for Apache or Django, I would be interested in solutions for either of them.
Quoting django docs Telling the browser to treat the response as a file attachmen, you should inform it in response:
>>> response = HttpResponse(my_data, content_type='application/vnd.ms-excel')
>>> response['Content-Disposition'] = 'attachment; filename="some.pdf"'

Why am I getting different mime types on my flask app on localhost and openshift?

I have a dynamic css file which loads fonts using font-face which is generated by a request and I am setting the content headers explicitly. It's all working well as far as mime types are concerned at localhost(text/css in network tab) except that the fonts are not loaded in chrome but works in firefox. But that's a different issue, so now I put the code on openshift and by magic response has a text/html header. What am I missing here ?
resp = make_response(render_template('webfonts.css', fonts=fonts))
resp.headers.add('content-type', 'text/css')
return resp
heres the flask code.
and heres the url
http://flaskexample-diadara.rhcloud.com/api/webfonts?font=LohitGujarati
I had the same issue (with the Flask built-in server) and also came across your question, I found the following:
While adding the header can be found elsewhere as the recommended solution it actually doesn't set one of the properties in the Response object (which actually makes sense if you think about it) making the server still send out a default text/html header.
The way that I found it to work is this:
response = Response(render_template('css/' + filename), mimetype='text/css')
return response
You should also do
from flask import Response