from __future__ import unicode_literals import contextlib import hashlib import json import os from django.core.files.uploadedfile import UploadedFile from django.http import HttpResponse, HttpResponseServerError from django.utils import six from django.utils.encoding import force_bytes, smart_str from .models import FileModel from .tests import UNICODE_FILENAME, UPLOAD_TO from .uploadhandler import ErroringUploadHandler, QuotaUploadHandler def file_upload_view(request): """ Check that a file upload can be updated into the POST dictionary without going pear-shaped. """ form_data = request.POST.copy() form_data.update(request.FILES) if isinstance(form_data.get('file_field'), UploadedFile) and isinstance(form_data['name'], six.text_type): # If a file is posted, the dummy client should only post the file name, # not the full path. if os.path.dirname(form_data['file_field'].name) != '': return HttpResponseServerError() return HttpResponse('') else: return HttpResponseServerError() def file_upload_view_verify(request): """ Use the sha digest hash to verify the uploaded contents. """ form_data = request.POST.copy() form_data.update(request.FILES) for key, value in form_data.items(): if key.endswith('_hash'): continue if key + '_hash' not in form_data: continue submitted_hash = form_data[key + '_hash'] if isinstance(value, UploadedFile): new_hash = hashlib.sha1(value.read()).hexdigest() else: new_hash = hashlib.sha1(force_bytes(value)).hexdigest() if new_hash != submitted_hash: return HttpResponseServerError() # Adding large file to the database should succeed largefile = request.FILES['file_field2'] obj = FileModel() obj.testfile.save(largefile.name, largefile) return HttpResponse('') def file_upload_unicode_name(request): # Check to see if unicode name came through properly. if not request.FILES['file_unicode'].name.endswith(UNICODE_FILENAME): return HttpResponseServerError() response = None # Check to make sure the exotic characters are preserved even # through file save. uni_named_file = request.FILES['file_unicode'] obj = FileModel.objects.create(testfile=uni_named_file) full_name = '%s/%s' % (UPLOAD_TO, uni_named_file.name) if not os.path.exists(full_name): response = HttpResponseServerError() # Cleanup the object with its exotic file name immediately. # (shutil.rmtree used elsewhere in the tests to clean up the # upload directory has been seen to choke on unicode # filenames on Windows.) obj.delete() os.unlink(full_name) if response: return response else: return HttpResponse('') def file_upload_echo(request): """ Simple view to echo back info about uploaded files for tests. """ r = {k: f.name for k, f in request.FILES.items()} return HttpResponse(json.dumps(r)) def file_upload_echo_content(request): """ Simple view to echo back the content of uploaded files for tests. """ def read_and_close(f): with contextlib.closing(f): return f.read().decode('utf-8') r = {k: read_and_close(f) for k, f in request.FILES.items()} return HttpResponse(json.dumps(r)) def file_upload_quota(request): """ Dynamically add in an upload handler. """ request.upload_handlers.insert(0, QuotaUploadHandler()) return file_upload_echo(request) def file_upload_quota_broken(request): """ You can't change handlers after reading FILES; this view shouldn't work. """ response = file_upload_echo(request) request.upload_handlers.insert(0, QuotaUploadHandler()) return response def file_upload_getlist_count(request): """ Check the .getlist() function to ensure we receive the correct number of files. """ file_counts = {} for key in request.FILES.keys(): file_counts[key] = len(request.FILES.getlist(key)) return HttpResponse(json.dumps(file_counts)) def file_upload_errors(request): request.upload_handlers.insert(0, ErroringUploadHandler()) return file_upload_echo(request) def file_upload_filename_case_view(request): """ Check adding the file to the database will preserve the filename case. """ file = request.FILES['file_field'] obj = FileModel() obj.testfile.save(file.name, file) return HttpResponse('%d' % obj.pk) def file_upload_content_type_extra(request): """ Simple view to echo back extra content-type parameters. """ params = {} for file_name, uploadedfile in request.FILES.items(): params[file_name] = { k: smart_str(v) for k, v in uploadedfile.content_type_extra.items() } return HttpResponse(json.dumps(params)) def file_upload_fd_closing(request, access): if access == 't': request.FILES # Trigger file parsing. return HttpResponse('')