A. H.
A. H.

Reputation: 952

django binary file download corrupted in browsers

I have a view that after authentication/permissions serves a file as saved in a FileField.

from django.http import StreamingHttpResponse
from rest_framework import viewsets
from rest_framework.decorators import detail_route
from wsgiref.util import FileWrapper
import mimetypes
from myapp.models import MyModel

class ExampleViewSet(viewsets.ViewSet):
   # Normal crud (retrive, list, etc.)
   @detail_route(methods=['GET'])
   def download(self, *args, **kwargs):
        pk = self.request.parser_context['kwargs'].get('pk', None)
        if pk is None:
            raise exceptions.ParseError('no pk')
        instance = MyModel.objects.get(pk=pk)
        filename = instance.file_field.name.split('/')[-1]
        mime = mimetypes.guess_type(filename)[0]
        file = instance.file_field.file
        response = StreamingHttpResponse(
            FileWrapper(open(file, 'rb'), 10240))
        response['Content-Type'] = "{0}; charset=utf-8".format(mime)
        response['Content-Length'] = file.size
        response[
            'Content-Disposition'] = 'attachment; filename={0}'.format(filename)
        return response

The file itself is a 3.7MB file jpeg that was previously uploaded by the user. Under the upload directory the file is 3.7MB and opens correctly. when downloaded via the browser (Firefox or Chrome) the file is 7.0MB and corrupted (does not have the correct header for jpegs which should start with two specific bytes) when downloaded from curl or wget the file is 3.7MB and opens correctly

The following is curl's output of the response fields using curl -v

curl -v http://localhost:3000/api/school_admin/posters/7/download?token=ZXlKaGJHY2lPaUpJVXpVeE1pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SndhR0Z6YUNJNkltSmpjbmx3ZEY5emFHRXlOVFlrSkRKaUpERXlKR2hzVlUxd2QyOWpTM1pMTnk1VlRuSXZPR1ZNVWs5aFJEVjBVbmR2V21FeVVGVlZiWGhxTTJWb1UzZFhla1JNU3k5RmFqZFRJaXdpY0hKdlptbHNaVjl3YXlJNk15d2laWGh3SWpveE5EY3lOalUyTWpFMGZRLmV6OGg5SWVwLUozYjdQcHJLVGJCZWlSSjJPN1JRdnItaFVuLVg0dmdLZGdtRGdQV0s2ZzkzdktialN2Uy1EVTVkM1hRc2hRZ3YxeVZmQlJhUDBBVlhB -o test.jpeg
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /api/school_admin/posters/7/download?token=ZXlKaGJHY2lPaUpJVXpVeE1pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SndhR0Z6YUNJNkltSmpjbmx3ZEY5emFHRXlOVFlrSkRKaUpERXlKR2hzVlUxd2QyOWpTM1pMTnk1VlRuSXZPR1ZNVWs5aFJEVjBVbmR2V21FeVVGVlZiWGhxTTJWb1UzZFhla1JNU3k5RmFqZFRJaXdpY0hKdlptbHNaVjl3YXlJNk15d2laWGh3SWpveE5EY3lOalUyTWpFMGZRLmV6OGg5SWVwLUozYjdQcHJLVGJCZWlSSjJPN1JRdnItaFVuLVg0dmdLZGdtRGdQV0s2ZzkzdktialN2Uy1EVTVkM1hRc2hRZ3YxeVZmQlJhUDBBVlhB HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< date: Mon, 29 Aug 2016 18:31:30 GMT
< server: WSGIServer/0.2 CPython/3.4.3
< allow: GET, DELETE, HEAD, OPTIONS
< content-type: image/jpeg; charset=utf-8
< vary: Accept
< content-length: 3947925
< content-disposition: attachment; filename=poster_28F7bdD4caAbCc583831c9E7C9baDaEC88Ecbde6FBAA6aE71cAdC09fd8EFCF7BD515155bec1C3FC6f01c6FEf5Ba76e41952E_Colosseum_in_Rome_Italy_-_April_2007.jpg
< x-frame-options: SAMEORIGIN
< via: 1.1 fedora
< Connection: keep-alive
< 
{ [15913 bytes data]
100 3855k  100 3855k    0     0   141M      0 --:--:-- --:--:-- --:--:--  144M
* Connection #0 to host localhost left intact

Upvotes: 4

Views: 935

Answers (2)

A. H.
A. H.

Reputation: 952

The problem was solved when I used nginx + uwsgi. I think it has to do with some of the 'Hop-by-hop' headers that django's runserver refuses to add and errors out if I add them manually. Which are generally related to reverse proxies.

Upvotes: 2

rkoots
rkoots

Reputation: 213

This is typically caused while uploading files/data through FTP as ASCII file transfer type. The "ASCII transfer type" will transfer the files as regular text files and so no problem. but, the "Binary transfer type" will transfer the data in binary mode which handles the files as binary data instead of text data. Setting your FTP client to Binary will prevent your files from becoming corrupted through ftp transit. Please see the following on how to switch your FTP program to Binary.

Here you should be trying the Binary data as in terms of ASCII.

Upvotes: 0

Related Questions