Limit upload file size using Django and display error page

I am using Django and want to display an error page if the file upload exceeds the allowed size without loading all the content. For this, a custom loader was used.

On the one hand, the load handler checks the total length of the content in the POST header, in addition, the downloaded fragments are tracked and their size is summed.

Unfortunately, I do not know how to initiate the creation of a page with an error.

My first idea was to return the empty POST and FILE content and detect this in the view, but this does not work.

from django.core.files.uploadhandler import FileUploadHandler, StopUpload from django.http import QueryDict from django.utils.datastructures import MultiValueDict class QuotaUploadHandler(FileUploadHandler): """ This test upload handler terminates the connection if more than a quota (5MB) is uploaded. """ QUOTA = 5 * 2**20 # 5 MB def __init__(self, request=None): super(QuotaUploadHandler, self).__init__(request) self.total_upload = 0 def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None): tmp_post = QueryDict('', mutable=True) tmp_files = MultiValueDict() if content_length > self.QUOTA: META["ERROR"] = "File is larger than maximum." return tmp_post, tmp_files def receive_data_chunk(self, raw_data, start): self.total_upload += len(raw_data) if self.total_upload >= self.QUOTA: raise StopUpload(connection_reset=True) return raw_data def file_complete(self, file_size): return None class CustomUploadError(Exception): pass 

Does anyone help?

Update:

Another solution I tested looked like this in a view:

 def main(request): request.upload_handlers.insert(0, QuotaUploadHandler()) content_length = request.META["CONTENT_LENGTH"] if content_length is not "" and int(content_length) > 5 * 1024 * 1024: print "Upload to large." raise Http404 return csrf_protected_main(request) 

I checked the result with wirehark capture: in this case, the server response is served to the client, but the Django server drops the TCP socket (presumably because it still receives the input).

 POST / HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.24) Gecko/20111107 Ubuntu/10.10 (maverick) Firefox/3.6.24 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: de,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Referer: http://localhost:8080/ Cookie: csrftoken=078fa2166ff190b148ac9045b3c408d7 Content-Type: multipart/form-data; boundary=---------------------------37071231519976700161208143859 Content-Length: 20971913 -----------------------------37071231519976700161208143859 Content-Disposition: form-data; name="testfile"; filename="test.test" Content-Type: application/octet-stream .... [36864 bytes missing in capture file] ....... HTTP/1.0 404 NOT FOUND Date: Sat, 10 Dec 2011 19:57:37 GMT Server: WSGIServer/0.1 Python/2.6.6 Content-Type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang="en"> <head> ... [ongoing] 

I also tried stopping the download with 413 HTTP Response Code (File to large), but it didn't work either.

+6
source share
2 answers

as some other commentators have described, if you find yourself checking the length of the content at the Django level, you have already finished downloading the whole file, which may not be too good. if you really want to stop it at the application level, some web servers have a directive that you can use to tell clients that they have exceeded their upload size limits.

for example, Apache LimitRequestBody can be used to indicate the maximum number of bytes allowed for a request body. I use this in my apache httpd.conf (to make it "global"), but you can also use LimitRequestBody at the level. in my http.conf:

 # limit requests to 25MB LimitRequestBody 26214400 

when this limit is disabled by the request, Apache will return the specific standard HTTP used for this purpose:

HTTP Error: 413 Request Failed Too Big

depending on how your application is configured (using JS on the client to execute this request?), then you can handle the client-side error if that particular error is returned.

NTN.

0
source

I have a field like this:

 class MyFileField(FileField): def clean(self, data): max_size = settings.MAX_SIZE_UPLOAD if data and max_size and len(data) > max_size: raise ValidationError(_('File too large. Max size restricted to %s bytes') % max_size) return super(MyFileField, self).clean(data) 

If the file is larger than MAX_SIZE_UPLOAD, there will be an error in the form

-1
source

Source: https://habr.com/ru/post/903515/


All Articles