1

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.

Cherif KAOUA
  • 834
  • 12
  • 21

2 Answers2

0

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

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
  • Will it use Cherokee to serve the file this way? i would like to protect media directory using the login_required but files should be served trough Cherokee, as it's more efficient and recommended for production, have done this for static and media directorioes with no protection right now – Cherif KAOUA Oct 06 '14 at 10:38
  • Cherokee cannot know if the HTTP request comes from a valid logged in user or not. – Mikko Ohtamaa Oct 06 '14 at 10:44
  • 1
    If you want to further optimize the output you can use X-Send-File` HTTP Response header. However this needs special support from the web server. https://github.com/johnsensible/django-sendfile - I suggest do the easiest solution and then something else if you are not happy with the performance. – Mikko Ohtamaa Oct 06 '14 at 10:46
0

I will answer my own question

As you are using Cherokee

  1. Remove direct access to media folder with the media URL as localhost/media/.. for exemple by removing the virtuelhost serving it

  2. Activate (check) Allow X-Sendfile under Handler tab in Common CGI Options in the virtuelserver page that handle Django request.

  3. 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

Cherif KAOUA
  • 834
  • 12
  • 21