blob: 280a1e982861aa10b9e8624ac1358c509769fdaf [file] [log] [blame]
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +01001# Copyright 2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Convenience functions for testing against Django."""
5
6from __future__ import (
7 absolute_import,
8 print_function,
9 unicode_literals,
10 )
11
12str = None
13
14__metaclass__ = type
15__all__ = []
16
17from io import BytesIO
18import os
19
20from django.core.files.uploadhandler import MemoryFileUploadHandler
21from django.http.multipartparser import MultiPartParser
22from maasserver.utils import ignore_unused
23
24
25def parse_headers_and_body_with_django(headers, body):
26 """Parse `headers` and `body` with Django's :class:`MultiPartParser`.
27
28 `MultiPartParser` is a curiously ugly and RFC non-compliant concoction.
29
30 Amongst other things, it coerces all field names, field data, and
31 filenames into Unicode strings using the "replace" error strategy, so be
32 warned that your data may be silently mangled.
33
34 It also, in 1.3.1 at least, does not recognise any transfer encodings at
35 *all* because its header parsing code was broken.
36
37 I'm also fairly sure that it'll fall over on headers than span more than
38 one line.
39
40 In short, it's a piece of code that inspires little confidence, yet we
41 must work with it, hence we need to round-trip test multipart handling
42 with it.
43 """
44 handler = MemoryFileUploadHandler()
45 meta = {
46 "HTTP_CONTENT_TYPE": headers["Content-Type"],
47 "HTTP_CONTENT_LENGTH": headers["Content-Length"],
48 }
49 parser = MultiPartParser(
50 META=meta, input_data=BytesIO(body),
51 upload_handlers=[handler])
52 return parser.parse()
53
54
55def parse_headers_and_body_with_mimer(headers, body):
56 """Use piston's Mimer functionality to handle the content.
57
58 :return: The value of 'request.data' after using Piston's translate_mime on
59 the input.
60 """
61 # JAM 2012-10-09 Importing emitters has a side effect of registering mime
62 # type handlers with utils.translate_mime. So we must import it, even
63 # though we don't use it. However, piston loads Django's QuerySet code
64 # which fails if you don't have a settings.py available. Which we don't
65 # during 'test.pserv'. So we import this late.
66 from piston import emitters
67 ignore_unused(emitters)
68 from piston.utils import translate_mime
69
70 environ = {'wsgi.input': BytesIO(body)}
71 for name, value in headers.items():
72 environ[name.upper().replace('-', '_')] = value
73 environ['REQUEST_METHOD'] = 'POST'
74 environ['SCRIPT_NAME'] = ''
75 environ['PATH_INFO'] = ''
76 # Django 1.6 needs DJANGO_SETTINGS_MODULE to be defined
77 # when importing WSGIRequest.
78 os.environ['DJANGO_SETTINGS_MODULE'] = 'maas.development'
79 from django.core.handlers.wsgi import WSGIRequest
80 request = WSGIRequest(environ)
81 translate_mime(request)
82 return request.data