Example #1
0
 def test_truncated_multipart_handled_gracefully(self):
     """
     If passed an incomplete multipart message, MultiPartParser does not
     attempt to read beyond the end of the stream, and simply will handle
     the part that can be parsed gracefully.
     """
     payload_str = "\r\n".join([
         '--' + client.BOUNDARY,
         'Content-Disposition: form-data; name="file"; filename="foo.txt"',
         'Content-Type: application/octet-stream',
         '',
         'file contents'
         '--' + client.BOUNDARY + '--',
         '',
     ])
     payload = client.FakePayload(payload_str[:-10])
     r = {
         'CONTENT_LENGTH': len(payload),
         'CONTENT_TYPE': client.MULTIPART_CONTENT,
         'PATH_INFO': '/echo/',
         'REQUEST_METHOD': 'POST',
         'wsgi.input': payload,
     }
     got = json.loads(self.client.request(**r).content.decode('utf-8'))
     self.assertEqual(got, {})
Example #2
0
    def test_blank_filenames(self):
        """
        Receiving file upload when filename is blank (before and after
        sanitization) should be okay.
        """
        # The second value is normalized to an empty name by
        # MultiPartParser.IE_sanitize()
        filenames = ['', 'C:\\Windows\\']

        payload = client.FakePayload()
        for i, name in enumerate(filenames):
            payload.write('\r\n'.join([
                '--' + client.BOUNDARY,
                'Content-Disposition: form-data; name="file%s"; filename="%s"'
                % (i, name), 'Content-Type: application/octet-stream', '',
                'You got pwnd.\r\n'
            ]))
        payload.write('\r\n--' + client.BOUNDARY + '--\r\n')

        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE': client.MULTIPART_CONTENT,
            'PATH_INFO': '/echo/',
            'REQUEST_METHOD': 'POST',
            'wsgi.input': payload,
        }
        response = self.client.request(**r)
        self.assertEqual(response.status_code, 200)

        # Empty filenames should be ignored
        received = json.loads(response.content.decode('utf-8'))
        for i, name in enumerate(filenames):
            self.assertIsNone(received.get('file%s' % i))
Example #3
0
    def test_filename_overflow(self):
        """File names over 256 characters (dangerous on some platforms) get fixed up."""
        long_str = 'f' * 300
        cases = [
            # field name, filename, expected
            ('long_filename', '%s.txt' % long_str, '%s.txt' % long_str[:251]),
            ('long_extension', 'foo.%s' % long_str, '.%s' % long_str[:254]),
            ('no_extension', long_str, long_str[:255]),
            ('no_filename', '.%s' % long_str, '.%s' % long_str[:254]),
            ('long_everything', '%s.%s' % (long_str, long_str),
             '.%s' % long_str[:254]),
        ]
        payload = client.FakePayload()
        for name, filename, _ in cases:
            payload.write("\r\n".join([
                '--' + client.BOUNDARY,
                'Content-Disposition: form-data; name="{}"; filename="{}"',
                'Content-Type: application/octet-stream', '', 'Oops.', ''
            ]).format(name, filename))
        payload.write('\r\n--' + client.BOUNDARY + '--\r\n')
        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE': client.MULTIPART_CONTENT,
            'PATH_INFO': "/echo/",
            'REQUEST_METHOD': 'POST',
            'wsgi.input': payload,
        }
        response = self.client.request(**r)

        result = json.loads(response.content.decode('utf-8'))
        for name, _, expected in cases:
            got = result[name]
            self.assertEqual(expected, got, 'Mismatch for {}'.format(name))
            self.assertLess(len(got), 256,
                            "Got a long file name (%s characters)." % len(got))
    def test_file_error_blocking(self):
        """
        The server should not block when there are upload errors (bug #8622).
        This can happen if something -- i.e. an exception handler -- tries to
        access POST while handling an error in parsing POST. This shouldn't
        cause an infinite loop!
        """
        class POSTAccessingHandler(client.ClientHandler):
            """A handler that'll access POST during an exception."""
            def handle_uncaught_exception(self, request, resolver, exc_info):
                ret = super(POSTAccessingHandler,
                            self).handle_uncaught_exception(
                                request, resolver, exc_info)
                p = request.POST
                return ret

        post_data = {
            'name': 'Ringo',
            'file_field': open(__file__),
        }
        # Maybe this is a little more complicated that it needs to be; but if
        # the django.test.client.FakePayload.read() implementation changes then
        # this test would fail.  So we need to know exactly what kind of error
        # it raises when there is an attempt to read more than the available bytes:
        try:
            client.FakePayload('a').read(2)
        except Exception, reference_error:
            pass
Example #5
0
    def test_dangerous_file_names(self):
        """Uploaded file names should be sanitized before ever reaching the view."""
        # This test simulates possible directory traversal attacks by a
        # malicious uploader We have to do some monkeybusiness here to construct
        # a malicious payload with an invalid file name (containing os.sep or
        # os.pardir). This similar to what an attacker would need to do when
        # trying such an attack.
        payload = client.FakePayload()
        for i, name in enumerate(CANDIDATE_TRAVERSAL_FILE_NAMES):
            payload.write('\r\n'.join([
                '--' + client.BOUNDARY,
                'Content-Disposition: form-data; name="file%s"; filename="%s"'
                % (i, name), 'Content-Type: application/octet-stream', '',
                'You got pwnd.\r\n'
            ]))
        payload.write('\r\n--' + client.BOUNDARY + '--\r\n')

        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE': client.MULTIPART_CONTENT,
            'PATH_INFO': "/echo/",
            'REQUEST_METHOD': 'POST',
            'wsgi.input': payload,
        }
        response = self.client.request(**r)
        # The filenames should have been sanitized by the time it got to the view.
        received = response.json()
        for i, name in enumerate(CANDIDATE_TRAVERSAL_FILE_NAMES):
            got = received["file%s" % i]
            self.assertEqual(got, "hax0rd.txt")
Example #6
0
    def test_unicode_name_rfc2231(self):
        """
        Test receiving file upload when filename is encoded with RFC2231
        (#22971).
        """
        payload = client.FakePayload()
        payload.write(
            '\r\n'.join([
                '--' + client.BOUNDARY,
                'Content-Disposition: form-data; name*=UTF-8\'\'file_unicode; filename*=UTF-8\'\'%s' % urlquote(
                    UNICODE_FILENAME
                ),
                'Content-Type: application/octet-stream',
                '',
                'You got pwnd.\r\n',
                '\r\n--' + client.BOUNDARY + '--\r\n'
            ])
        )

        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE': client.MULTIPART_CONTENT,
            'PATH_INFO': "/unicode_name/",
            'REQUEST_METHOD': 'POST',
            'wsgi.input': payload,
        }
        response = self.client.request(**r)
        self.assertEqual(response.status_code, 200)
Example #7
0
 def test_empty_multipart_handled_gracefully(self):
     """
     If passed an empty multipart message, MultiPartParser will return
     an empty QueryDict.
     """
     r = {
         'CONTENT_LENGTH': 0,
         'CONTENT_TYPE': client.MULTIPART_CONTENT,
         'PATH_INFO': '/echo/',
         'REQUEST_METHOD': 'POST',
         'wsgi.input': client.FakePayload(b''),
     }
     self.assertEqual(self.client.request(**r).json(), {})
Example #8
0
 def test_empty_multipart_handled_gracefully(self):
     """
     If passed an empty multipart message, MultiPartParser will return
     an empty QueryDict.
     """
     r = {
         "CONTENT_LENGTH": 0,
         "CONTENT_TYPE": client.MULTIPART_CONTENT,
         "PATH_INFO": "/echo/",
         "REQUEST_METHOD": "POST",
         "wsgi.input": client.FakePayload(b""),
     }
     self.assertEqual(self.client.request(**r).json(), {})
Example #9
0
    def test_dangerous_file_names(self):
        """Uploaded file names should be sanitized before ever reaching the view."""
        # This test simulates possible directory traversal attacks by a
        # malicious uploader We have to do some monkeybusiness here to construct
        # a malicious payload with an invalid file name (containing os.sep or
        # os.pardir). This similar to what an attacker would need to do when
        # trying such an attack.
        scary_file_names = [
            "/tmp/hax0rd.txt",          # Absolute path, *nix-style.
            "C:\\Windows\\hax0rd.txt",  # Absolute path, win-syle.
            "C:/Windows/hax0rd.txt",    # Absolute path, broken-style.
            "\\tmp\\hax0rd.txt",        # Absolute path, broken in a different way.
            "/tmp\\hax0rd.txt",         # Absolute path, broken by mixing.
            "subdir/hax0rd.txt",        # Descendant path, *nix-style.
            "subdir\\hax0rd.txt",       # Descendant path, win-style.
            "sub/dir\\hax0rd.txt",      # Descendant path, mixed.
            "../../hax0rd.txt",         # Relative path, *nix-style.
            "..\\..\\hax0rd.txt",       # Relative path, win-style.
            "../..\\hax0rd.txt"         # Relative path, mixed.
        ]

        payload = []
        for i, name in enumerate(scary_file_names):
            payload.extend([
                '--' + client.BOUNDARY,
                'Content-Disposition: form-data; name="file%s"; filename="%s"' % (i, name),
                'Content-Type: application/octet-stream',
                '',
                'You got pwnd.'
            ])
        payload.extend([
            '--' + client.BOUNDARY + '--',
            '',
        ])

        payload = "\r\n".join(payload).encode('utf-8')
        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE':   client.MULTIPART_CONTENT,
            'PATH_INFO':      "/file_uploads/echo/",
            'REQUEST_METHOD': 'POST',
            'wsgi.input':     client.FakePayload(payload),
        }
        response = self.client.request(**r)

        # The filenames should have been sanitized by the time it got to the view.
        recieved = json.loads(response.content.decode('utf-8'))
        for i, name in enumerate(scary_file_names):
            got = recieved["file%s" % i]
            self.assertEqual(got, "hax0rd.txt")
def test_fake_file_upload(admin_user, admin_client):
    foo_ct = ContentType.objects.get_for_model(Foo)
    clear_uploads()

    payload = client_module.FakePayload()

    def form_value_list(key, value):
        return [
            '--' + client_module.BOUNDARY,
            'Content-Disposition: form-data; name="%s"' % key, "", value
        ]

    form_vals = []
    file_data = 'foo bar foo bar.'
    file_size = str(len(file_data))
    form_vals += form_value_list("resumableChunkNumber", "1")
    form_vals += form_value_list("resumableChunkSize", file_size)
    form_vals += form_value_list("resumableType", "text/plain")
    form_vals += form_value_list("resumableIdentifier", file_size + "-foobar")
    form_vals += form_value_list("resumableFilename", "foo.bar")
    form_vals += form_value_list("resumableTotalChunks", "1")
    form_vals += form_value_list("resumableTotalSize", file_size)
    form_vals += form_value_list("content_type_id", str(foo_ct.id))
    form_vals += form_value_list("field_name", "foo")
    payload.write('\r\n'.join(form_vals + [
        '--' + client_module.BOUNDARY,
        'Content-Disposition: form-data; name="file"; filename=foo.bar',
        'Content-Type: application/octet-stream', '', file_data, '--' +
        client_module.BOUNDARY + '--\r\n'
    ]))

    r = {
        'CONTENT_LENGTH': len(payload),
        'CONTENT_TYPE': client_module.MULTIPART_CONTENT,
        'PATH_INFO': "/admin_resumable/admin_resumable/",
        'REQUEST_METHOD': 'POST',
        'wsgi.input': payload,
    }
    response = admin_client.request(**r)
    assert response.status_code == 200
    upload_filename = file_size + "_foo.bar"
    upload_path = os.path.join(settings.MEDIA_ROOT, 'admin_uploaded',
                               upload_filename)
    f = open(upload_path, 'r')
    uploaded_contents = f.read()
    assert file_data == uploaded_contents
Example #11
0
File: tests.py Project: ximi/django
    def test_file_error_blocking(self):
        """
        The server should not block when there are upload errors (bug #8622).
        This can happen if something -- i.e. an exception handler -- tries to
        access POST while handling an error in parsing POST. This shouldn't
        cause an infinite loop!
        """
        class POSTAccessingHandler(client.ClientHandler):
            """A handler that'll access POST during an exception."""
            def handle_uncaught_exception(self, request, resolver, exc_info):
                ret = super(POSTAccessingHandler,
                            self).handle_uncaught_exception(
                                request, resolver, exc_info)
                p = request.POST
                return ret

        # Maybe this is a little more complicated that it needs to be; but if
        # the django.test.client.FakePayload.read() implementation changes then
        # this test would fail.  So we need to know exactly what kind of error
        # it raises when there is an attempt to read more than the available bytes:
        try:
            client.FakePayload(b'a').read(2)
        except Exception as reference_error:
            pass

        # install the custom handler that tries to access request.POST
        self.client.handler = POSTAccessingHandler()

        with open(__file__, 'rb') as fp:
            post_data = {
                'name': 'Ringo',
                'file_field': fp,
            }
            try:
                response = self.client.post('/file_uploads/upload_errors/',
                                            post_data)
            except reference_error.__class__ as err:
                self.assertFalse(
                    str(err) == str(reference_error),
                    "Caught a repeated exception that'll cause an infinite loop in file uploads."
                )
            except Exception as err:
                # CustomUploadError is the error that should have been raised
                self.assertEqual(err.__class__,
                                 uploadhandler.CustomUploadError)
Example #12
0
 def _test_base64_upload(self, content, encode=base64.b64encode):
     payload = client.FakePayload("\r\n".join([
         '--' + client.BOUNDARY,
         'Content-Disposition: form-data; name="file"; filename="test.txt"',
         'Content-Type: application/octet-stream',
         'Content-Transfer-Encoding: base64', ''
     ]))
     payload.write(b'\r\n' + encode(content.encode()) + b'\r\n')
     payload.write('--' + client.BOUNDARY + '--\r\n')
     r = {
         'CONTENT_LENGTH': len(payload),
         'CONTENT_TYPE': client.MULTIPART_CONTENT,
         'PATH_INFO': "/echo_content/",
         'REQUEST_METHOD': 'POST',
         'wsgi.input': payload,
     }
     response = self.client.request(**r)
     self.assertEqual(response.json()['file'], content)
Example #13
0
 def test_unicode_name_rfc2231_with_double_quotes(self):
     payload = client.FakePayload()
     payload.write('\r\n'.join([
         '--' + client.BOUNDARY,
         'Content-Disposition: form-data; name*="UTF-8\'\'file_unicode"; '
         'filename*="UTF-8\'\'%s"' % quote(UNICODE_FILENAME),
         'Content-Type: application/octet-stream', '', 'You got pwnd.\r\n',
         '\r\n--' + client.BOUNDARY + '--\r\n'
     ]))
     r = {
         'CONTENT_LENGTH': len(payload),
         'CONTENT_TYPE': client.MULTIPART_CONTENT,
         'PATH_INFO': '/unicode_name/',
         'REQUEST_METHOD': 'POST',
         'wsgi.input': payload,
     }
     response = self.client.request(**r)
     self.assertEqual(response.status_code, 200)
def requestfactory_patch(self, path, data=None, content_type=client.MULTIPART_CONTENT, **extra):
    """
    Construct a PATCH request.
    """

    data = data or {}
    patch_data = self._encode_data(data, content_type)

    parsed = urllib.parse.urlparse(path)
    request = {
        'CONTENT_LENGTH': len(patch_data),
        'CONTENT_TYPE': content_type,
        'PATH_INFO': self._get_path(parsed),
        'QUERY_STRING': parsed[4],
        'REQUEST_METHOD': 'PATCH',
        'wsgi.input': client.FakePayload(patch_data),
    }
    request.update(extra)
    return self.request(**request)
Example #15
0
 def test_base64_invalid_upload(self):
     payload = client.FakePayload("\r\n".join([
         "--" + client.BOUNDARY,
         'Content-Disposition: form-data; name="file"; filename="test.txt"',
         "Content-Type: application/octet-stream",
         "Content-Transfer-Encoding: base64",
         "",
     ]))
     payload.write(b"\r\n!\r\n")
     payload.write("--" + client.BOUNDARY + "--\r\n")
     r = {
         "CONTENT_LENGTH": len(payload),
         "CONTENT_TYPE": client.MULTIPART_CONTENT,
         "PATH_INFO": "/echo_content/",
         "REQUEST_METHOD": "POST",
         "wsgi.input": payload,
     }
     response = self.client.request(**r)
     self.assertEqual(response.json()["file"], "")
Example #16
0
    def test_blank_filenames(self):
        """
        Receiving file upload when filename is blank (before and after
        sanitization) should be okay.
        """
        filenames = [
            "",
            # Normalized by MultiPartParser.IE_sanitize().
            "C:\\Windows\\",
            # Normalized by os.path.basename().
            "/",
            "ends-with-slash/",
        ]
        payload = client.FakePayload()
        for i, name in enumerate(filenames):
            payload.write(
                "\r\n".join(
                    [
                        "--" + client.BOUNDARY,
                        'Content-Disposition: form-data; name="file%s"; filename="%s"'
                        % (i, name),
                        "Content-Type: application/octet-stream",
                        "",
                        "You got pwnd.\r\n",
                    ]
                )
            )
        payload.write("\r\n--" + client.BOUNDARY + "--\r\n")

        r = {
            "CONTENT_LENGTH": len(payload),
            "CONTENT_TYPE": client.MULTIPART_CONTENT,
            "PATH_INFO": "/echo/",
            "REQUEST_METHOD": "POST",
            "wsgi.input": payload,
        }
        response = self.client.request(**r)
        self.assertEqual(response.status_code, 200)

        # Empty filenames should be ignored
        received = response.json()
        for i, name in enumerate(filenames):
            self.assertIsNone(received.get("file%s" % i))
Example #17
0
    def _test_base64_upload(self, content):
        payload = client.FakePayload("\r\n".join([
            '--' + client.BOUNDARY,
            'Content-Disposition: form-data; name="file"; filename="test.txt"',
            'Content-Type: application/octet-stream',
            'Content-Transfer-Encoding: base64',
            '',]))
        payload.write(b"\r\n" + base64.b64encode(force_bytes(content)) + b"\r\n")
        payload.write('--' + client.BOUNDARY + '--\r\n')
        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE':   client.MULTIPART_CONTENT,
            'PATH_INFO':      "/file_uploads/echo_content/",
            'REQUEST_METHOD': 'POST',
            'wsgi.input':     payload,
        }
        response = self.client.request(**r)
        received = json.loads(response.content.decode('utf-8'))

        self.assertEqual(received['file'], content)
Example #18
0
 def test_unicode_name_rfc2231_with_double_quotes(self):
     payload = client.FakePayload()
     payload.write("\r\n".join([
         "--" + client.BOUNDARY,
         "Content-Disposition: form-data; name*=\"UTF-8''file_unicode\"; "
         "filename*=\"UTF-8''%s\"" % quote(UNICODE_FILENAME),
         "Content-Type: application/octet-stream",
         "",
         "You got pwnd.\r\n",
         "\r\n--" + client.BOUNDARY + "--\r\n",
     ]))
     r = {
         "CONTENT_LENGTH": len(payload),
         "CONTENT_TYPE": client.MULTIPART_CONTENT,
         "PATH_INFO": "/unicode_name/",
         "REQUEST_METHOD": "POST",
         "wsgi.input": payload,
     }
     response = self.client.request(**r)
     self.assertEqual(response.status_code, 200)
Example #19
0
 def test_non_printable_chars_in_file_names(self):
     file_name = 'non-\x00printable\x00\n_chars.txt\x00'
     payload = client.FakePayload()
     payload.write('\r\n'.join([
         '--' + client.BOUNDARY,
         f'Content-Disposition: form-data; name="file"; filename="{file_name}"',
         'Content-Type: application/octet-stream', '', 'You got pwnd.\r\n'
     ]))
     payload.write('\r\n--' + client.BOUNDARY + '--\r\n')
     r = {
         'CONTENT_LENGTH': len(payload),
         'CONTENT_TYPE': client.MULTIPART_CONTENT,
         'PATH_INFO': '/echo/',
         'REQUEST_METHOD': 'POST',
         'wsgi.input': payload,
     }
     response = self.client.request(**r)
     # Non-printable chars are sanitized.
     received = response.json()
     self.assertEqual(received['file'], 'non-printable_chars.txt')
Example #20
0
 def test_filename_traversal_upload(self):
     os.makedirs(UPLOAD_TO, exist_ok=True)
     tests = [
         "../test.txt",
         "../test.txt",
     ]
     for file_name in tests:
         with self.subTest(file_name=file_name):
             payload = client.FakePayload()
             payload.write(
                 "\r\n".join(
                     [
                         "--" + client.BOUNDARY,
                         'Content-Disposition: form-data; name="my_file"; '
                         'filename="%s";' % file_name,
                         "Content-Type: text/plain",
                         "",
                         "file contents.\r\n",
                         "\r\n--" + client.BOUNDARY + "--\r\n",
                     ]
                 ),
             )
             r = {
                 "CONTENT_LENGTH": len(payload),
                 "CONTENT_TYPE": client.MULTIPART_CONTENT,
                 "PATH_INFO": "/upload_traversal/",
                 "REQUEST_METHOD": "POST",
                 "wsgi.input": payload,
             }
             response = self.client.request(**r)
             result = response.json()
             self.assertEqual(response.status_code, 200)
             self.assertEqual(result["file_name"], "test.txt")
             self.assertIs(
                 os.path.exists(os.path.join(MEDIA_ROOT, "test.txt")),
                 False,
             )
             self.assertIs(
                 os.path.exists(os.path.join(UPLOAD_TO, "test.txt")),
                 True,
             )
Example #21
0
 def test_filename_overflow(self):
     """File names over 256 characters (dangerous on some platforms) get fixed up."""
     long_str = "f" * 300
     cases = [
         # field name, filename, expected
         ("long_filename", "%s.txt" % long_str, "%s.txt" % long_str[:251]),
         ("long_extension", "foo.%s" % long_str, ".%s" % long_str[:254]),
         ("no_extension", long_str, long_str[:255]),
         ("no_filename", ".%s" % long_str, ".%s" % long_str[:254]),
         ("long_everything", "%s.%s" % (long_str, long_str), ".%s" % long_str[:254]),
     ]
     payload = client.FakePayload()
     for name, filename, _ in cases:
         payload.write(
             "\r\n".join(
                 [
                     "--" + client.BOUNDARY,
                     'Content-Disposition: form-data; name="{}"; filename="{}"',
                     "Content-Type: application/octet-stream",
                     "",
                     "Oops.",
                     "",
                 ]
             ).format(name, filename)
         )
     payload.write("\r\n--" + client.BOUNDARY + "--\r\n")
     r = {
         "CONTENT_LENGTH": len(payload),
         "CONTENT_TYPE": client.MULTIPART_CONTENT,
         "PATH_INFO": "/echo/",
         "REQUEST_METHOD": "POST",
         "wsgi.input": payload,
     }
     response = self.client.request(**r)
     result = response.json()
     for name, _, expected in cases:
         got = result[name]
         self.assertEqual(expected, got, "Mismatch for {}".format(name))
         self.assertLess(
             len(got), 256, "Got a long file name (%s characters)." % len(got)
         )
Example #22
0
 def test_filename_overflow(self):
     """File names over 256 characters (dangerous on some platforms) get fixed up."""
     name = "%s.txt" % ("f"*500)
     payload = "\r\n".join([
         '--' + client.BOUNDARY,
         'Content-Disposition: form-data; name="file"; filename="%s"' % name,
         'Content-Type: application/octet-stream',
         '',
         'Oops.'
         '--' + client.BOUNDARY + '--',
         '',
     ]).encode('utf-8')
     r = {
         'CONTENT_LENGTH': len(payload),
         'CONTENT_TYPE':   client.MULTIPART_CONTENT,
         'PATH_INFO':      "/file_uploads/echo/",
         'REQUEST_METHOD': 'POST',
         'wsgi.input':     client.FakePayload(payload),
     }
     got = json.loads(self.client.request(**r).content.decode('utf-8'))
     self.assertTrue(len(got['file']) < 256, "Got a long file name (%s characters)." % len(got['file']))
Example #23
0
 def test_filename_traversal_upload(self):
     os.makedirs(UPLOAD_TO, exist_ok=True)
     tests = [
         '..&#x2F;test.txt',
         '..&sol;test.txt',
     ]
     for file_name in tests:
         with self.subTest(file_name=file_name):
             payload = client.FakePayload()
             payload.write(
                 '\r\n'.join([
                     '--' + client.BOUNDARY,
                     'Content-Disposition: form-data; name="my_file"; '
                     'filename="%s";' % file_name,
                     'Content-Type: text/plain',
                     '',
                     'file contents.\r\n',
                     '\r\n--' + client.BOUNDARY + '--\r\n',
                 ]),
             )
             r = {
                 'CONTENT_LENGTH': len(payload),
                 'CONTENT_TYPE': client.MULTIPART_CONTENT,
                 'PATH_INFO': '/upload_traversal/',
                 'REQUEST_METHOD': 'POST',
                 'wsgi.input': payload,
             }
             response = self.client.request(**r)
             result = response.json()
             self.assertEqual(response.status_code, 200)
             self.assertEqual(result['file_name'], 'test.txt')
             self.assertIs(
                 os.path.exists(os.path.join(MEDIA_ROOT, 'test.txt')),
                 False,
             )
             self.assertIs(
                 os.path.exists(os.path.join(UPLOAD_TO, 'test.txt')),
                 True,
             )
Example #24
0
    def request(self, **request):
        # Figure out parameters from request['QUERY_STRING'] and FakePayload
        params = {}
        if request['REQUEST_METHOD'] in ('POST', 'PUT'):
            if request['CONTENT_TYPE'] == URLENCODED_FORM_CONTENT:
                payload = request['wsgi.input'].read()
                request['wsgi.input'] = client.FakePayload(payload)
                params = cgi.parse_qs(payload)

        url = "http://testserver" + request['PATH_INFO']

        req = oauth.OAuthRequest.from_consumer_and_token(
            self.consumer, token=self.token, 
            http_method=request['REQUEST_METHOD'], http_url=url, 
            parameters=params
        )

        req.sign_request(self.signature, self.consumer, self.token)
        headers = req.to_header()
        request['HTTP_AUTHORIZATION'] = headers['Authorization']

        return super(OAuthClient, self).request(**request)
Example #25
0
    def put(self,
            path,
            data={},
            content_type=client.MULTIPART_CONTENT,
            **extra):
        """
        Requests a response from the server using PUT.
        """
        if content_type is client.MULTIPART_CONTENT:
            put_data = client.encode_multipart(BOUNDARY, data)
        else:
            put_data = data

        r = {
            'CONTENT_LENGTH': len(put_data),
            'CONTENT_TYPE': content_type,
            'PATH_INFO': urllib.unquote(path),
            'REQUEST_METHOD': 'PUT',
            'wsgi.input': client.FakePayload(put_data),
        }
        r.update(extra)

        return self.request(**r)
Example #26
0
File: tests.py Project: ximi/django
    def test_base64_upload(self):
        test_string = "This data will be transmitted base64-encoded."
        payload = "\r\n".join([
            '--' + client.BOUNDARY,
            'Content-Disposition: form-data; name="file"; filename="test.txt"',
            'Content-Type: application/octet-stream',
            'Content-Transfer-Encoding: base64',
            '',
            base64.b64encode(test_string),
            '--' + client.BOUNDARY + '--',
            '',
        ]).encode('utf-8')
        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE': client.MULTIPART_CONTENT,
            'PATH_INFO': "/file_uploads/echo_content/",
            'REQUEST_METHOD': 'POST',
            'wsgi.input': client.FakePayload(payload),
        }
        response = self.client.request(**r)
        received = json.loads(response.content)

        self.assertEqual(received['file'], test_string)
Example #27
0
 def test_non_printable_chars_in_file_names(self):
     file_name = "non-\x00printable\x00\n_chars.txt\x00"
     payload = client.FakePayload()
     payload.write("\r\n".join([
         "--" + client.BOUNDARY,
         f'Content-Disposition: form-data; name="file"; '
         f'filename="{file_name}"',
         "Content-Type: application/octet-stream",
         "",
         "You got pwnd.\r\n",
     ]))
     payload.write("\r\n--" + client.BOUNDARY + "--\r\n")
     r = {
         "CONTENT_LENGTH": len(payload),
         "CONTENT_TYPE": client.MULTIPART_CONTENT,
         "PATH_INFO": "/echo/",
         "REQUEST_METHOD": "POST",
         "wsgi.input": payload,
     }
     response = self.client.request(**r)
     # Non-printable chars are sanitized.
     received = response.json()
     self.assertEqual(received["file"], "non-printable_chars.txt")
Example #28
0
 def test_truncated_multipart_handled_gracefully(self):
     """
     If passed an incomplete multipart message, MultiPartParser does not
     attempt to read beyond the end of the stream, and simply will handle
     the part that can be parsed gracefully.
     """
     payload_str = "\r\n".join([
         "--" + client.BOUNDARY,
         'Content-Disposition: form-data; name="file"; filename="foo.txt"',
         "Content-Type: application/octet-stream",
         "",
         "file contents"
         "--" + client.BOUNDARY + "--",
         "",
     ])
     payload = client.FakePayload(payload_str[:-10])
     r = {
         "CONTENT_LENGTH": len(payload),
         "CONTENT_TYPE": client.MULTIPART_CONTENT,
         "PATH_INFO": "/echo/",
         "REQUEST_METHOD": "POST",
         "wsgi.input": payload,
     }
     self.assertEqual(self.client.request(**r).json(), {})
def test_fake_file_upload_incomplete_chunk(admin_user, admin_client):
    foo_ct = ContentType.objects.get_for_model(Foo)
    clear_uploads()

    payload = client_module.FakePayload()

    def form_value_list(key, value):
        return [
            '--' + client_module.BOUNDARY,
            'Content-Disposition: form-data; name="%s"' % key, "", value
        ]

    form_vals = []
    file_data = 'foo bar foo bar.'
    file_size = str(len(file_data))
    form_vals += form_value_list("resumableChunkNumber", "1")
    form_vals += form_value_list("resumableChunkSize", "3")
    form_vals += form_value_list("resumableType", "text/plain")
    form_vals += form_value_list("resumableIdentifier", file_size + "-foobar")
    form_vals += form_value_list("resumableFilename", "foo.bar")
    form_vals += form_value_list("resumableTotalChunks", "6")
    form_vals += form_value_list("resumableTotalSize", file_size)
    form_vals += form_value_list("content_type_id", str(foo_ct.id))
    form_vals += form_value_list("field_name", "foo")
    payload.write('\r\n'.join(form_vals + [
        '--' + client_module.BOUNDARY,
        'Content-Disposition: form-data; name="file"; filename=foo.bar',
        'Content-Type: application/octet-stream',
        '',
        file_data[0:1],
        # missing final boundary to simulate failure
    ]))

    r = {
        'CONTENT_LENGTH': len(payload),
        'CONTENT_TYPE': client_module.MULTIPART_CONTENT,
        'PATH_INFO': "/admin_resumable/admin_resumable/",
        'REQUEST_METHOD': 'POST',
        'wsgi.input': payload,
    }
    try:
        admin_client.request(**r)
    except AttributeError:
        pass  # we're not worried that this would 500

    get_url = "/admin_resumable/admin_resumable/?"
    get_args = {
        'resumableChunkNumber': '1',
        'resumableChunkSize': '3',
        'resumableCurrentChunkSize': '3',
        'resumableTotalSize': file_size,
        'resumableType': "text/plain",
        'resumableIdentifier': file_size + "-foobar",
        'resumableFilename': "foo.bar",
        'resumableRelativePath': "foo.bar",
        'content_type_id': str(foo_ct.id),
        'field_name': "foo",
    }

    # we need a fresh client because client.request breaks things
    fresh_client = client_module.Client()
    fresh_client.login(username=admin_user.username, password='******')
    get_response = fresh_client.get(get_url, get_args)
    # should be a 404 because we uploaded an incomplete chunk
    assert get_response.status_code == 404