Example #1
0
def parse_headers_and_body_with_django(headers, body):
    """Parse `headers` and `body` with Django's :class:`MultiPartParser`.

    `MultiPartParser` is a curiously ugly and RFC non-compliant concoction.

    Amongst other things, it coerces all field names, field data, and
    filenames into Unicode strings using the "replace" error strategy, so be
    warned that your data may be silently mangled.

    It also, in 1.3.1 at least, does not recognise any transfer encodings at
    *all* because its header parsing code was broken.

    I'm also fairly sure that it'll fall over on headers than span more than
    one line.

    In short, it's a piece of code that inspires little confidence, yet we
    must work with it, hence we need to round-trip test multipart handling
    with it.
    """
    handler = MemoryFileUploadHandler()
    meta = {
        "HTTP_CONTENT_TYPE": headers["Content-Type"],
        "HTTP_CONTENT_LENGTH": headers["Content-Length"],
        }
    parser = MultiPartParser(
        META=meta, input_data=BytesIO(body),
        upload_handlers=[handler])
    return parser.parse()
Example #2
0
 def parse_file_upload(self, META, post_data):
     """Returns a tuple of (POST QueryDict, FILES MultiValueDict)."""
     self.upload_handlers = ImmutableList(
         self.upload_handlers, warning="You cannot alter upload handlers after the upload has been processed."
     )
     parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding)
     return parser.parse()
Example #3
0
	def wrapper(request, *args, **kwargs):

		# Update the query dicts only if it's DELETE
		if request.method == 'DELETE':
			parser = MultiPartParser(request.META, request, [], request.encoding)  # We don't need anything special here, we just want to read a couple of parameters here
			query_dict, files = parser.parse()  # And we don't need files, as files are never processed even if sent
			request.DELETE = query_dict

		return function(request, *args, **kwargs)
Example #4
0
 def parse(self, stream):
     """
     Returns a 2-tuple of `(data, files)`.
     
     `data` will be a :class:`QueryDict` containing all the form parameters.
     `files` will be a :class:`QueryDict` containing all the form files.
     """
     upload_handlers = self.view.request._get_upload_handlers()
     django_parser = DjangoMultiPartParser(self.view.request.META, stream, upload_handlers)
     return django_parser.parse()
Example #5
0
 def parse(self, stream):
     """
     Returns a 2-tuple of `(data, files)`.
     
     `data` will be a :class:`QueryDict` containing all the form parameters.
     `files` will be a :class:`QueryDict` containing all the form files.
     """
     upload_handlers = self.view.request._get_upload_handlers()
     django_parser = DjangoMultiPartParser(self.view.request.META, stream,
                                           upload_handlers)
     return django_parser.parse()
Example #6
0
 def parse_file_upload(self, META, post_data):
     """Return a tuple of (POST QueryDict, FILES MultiValueDict)."""
     self.upload_handlers = ImmutableList(
         self.upload_handlers,
         warning=(
             "You cannot alter upload handlers after the upload has been "
             "processed."),
     )
     parser = MultiPartParser(META, post_data, self.upload_handlers,
                              self.encoding)
     return parser.parse()
Example #7
0
    def parse_request_data(self):
        if self.request.method == 'POST':
            return self.request.POST, self.request.FILES

        data = self.request.raw_post_data
        if self.request.META.get('CONTENT_TYPE', '').startswith('multipart'):
            data = StringIO(data)
            parser = MultiPartParser(self.request.META, data, self.upload_handlers)
            query =  parser.parse()
            return query

        return QueryDict(data), {}
    def parse(self, stream):
        """
        Returns a 2-tuple of `(data, files)`.

        `data` will be a :class:`QueryDict` containing all the form parameters.
        `files` will be a :class:`QueryDict` containing all the form files.
        """
        upload_handlers = self.view.request._get_upload_handlers()
        try:
            django_parser = DjangoMultiPartParser(self.view.request.META, stream, upload_handlers)
            return django_parser.parse()
        except MultiPartParserError, exc:
            raise ErrorResponse(status.HTTP_400_BAD_REQUEST,
                                {'detail': 'multipart parse error - %s' % unicode(exc)})
    def parse(self, stream):
        """
        Returns a 2-tuple of `(data, files)`.

        `data` will be a :class:`QueryDict` containing all the form parameters.
        `files` will be a :class:`QueryDict` containing all the form files.
        """
        upload_handlers = self.view.request.upload_handlers
        try:
            django_parser = DjangoMultiPartParser(self.view.request.META,
                                                  stream, upload_handlers)
            return django_parser.parse()
        except MultiPartParserError as exc:
            raise ErrorResponse(
                status.HTTP_400_BAD_REQUEST,
                {'detail': 'multipart parse error - %s' % str(exc)})
Example #10
0
def _document_PUT(request, document_slug, document_locale):
    """Handle PUT requests as document write API"""

    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get('CONTENT_TYPE', '')

        if content_type.startswith('application/json'):
            data = json.loads(request.body)

        elif content_type.startswith('multipart/form-data'):
            parser = MultiPartParser(request.META,
                                     StringIO(request.body),
                                     request.upload_handlers,
                                     request.encoding)
            data, files = parser.parse()

        elif content_type.startswith('text/html'):
            # TODO: Refactor this into wiki.content ?
            # First pass: Just assume the request body is an HTML fragment.
            html = request.body
            data = dict(content=html)

            # Second pass: Try parsing the body as a fuller HTML document,
            # and scrape out some of the interesting parts.
            try:
                doc = pq(html)
                head_title = doc.find('head title')
                if head_title.length > 0:
                    data['title'] = head_title.text()
                body_content = doc.find('body')
                if body_content.length > 0:
                    data['content'] = body_content.html()
            except:
                pass

        else:
            resp = HttpResponse()
            resp.status_code = 400
            resp.content = _("Unsupported content-type: %s") % content_type
            return resp

    except Exception, e:
        resp = HttpResponse()
        resp.status_code = 400
        resp.content = _("Request parsing error: %s") % e
        return resp
Example #11
0
    def __call__(self, request):
        if request.method in self.METHODS:
            try:
                parser = MultiPartParser(request.META, request._stream,
                                         request.upload_handlers,
                                         request.encoding)
                request._post, request._files = parser.parse()
            except MultiPartParserError as e:
                return JsonResponse({
                    'status': 400,
                    'result': str(e)
                },
                                    status=400)

        response = self.get_response(request)

        return response
Example #12
0
 def parse(self, stream, media_type=None, parser_context=None):
     parser_context = parser_context or {}
     request = parser_context['request']
     encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
     meta = request.META.copy()
     meta['CONTENT_TYPE'] = media_type
     upload_handlers = request.upload_handlers
     parsed = []
     try:
         parser = DjangoMultiPartParser(meta, stream, upload_handlers,
                                        encoding)
         _, files = parser.parse()
         for file in files.values():
             parsed.append({'image': file})
         return parsed
     except MultiPartParserError as e:
         raise ParseError(str(e))
Example #13
0
def _document_PUT(request, document_slug, document_locale):
    """Handle PUT requests as document write API"""

    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get('CONTENT_TYPE', '')

        if content_type.startswith('application/json'):
            data = json.loads(request.body)

        elif content_type.startswith('multipart/form-data'):
            parser = MultiPartParser(request.META, StringIO(request.body),
                                     request.upload_handlers, request.encoding)
            data, files = parser.parse()

        elif content_type.startswith('text/html'):
            # TODO: Refactor this into wiki.content ?
            # First pass: Just assume the request body is an HTML fragment.
            html = request.body
            data = dict(content=html)

            # Second pass: Try parsing the body as a fuller HTML document,
            # and scrape out some of the interesting parts.
            try:
                doc = pq(html)
                head_title = doc.find('head title')
                if head_title.length > 0:
                    data['title'] = head_title.text()
                body_content = doc.find('body')
                if body_content.length > 0:
                    data['content'] = body_content.html()
            except:
                pass

        else:
            resp = HttpResponse()
            resp.status_code = 400
            resp.content = _("Unsupported content-type: %s") % content_type
            return resp

    except Exception, e:
        resp = HttpResponse()
        resp.status_code = 400
        resp.content = _("Request parsing error: %s") % e
        return resp
Example #14
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Returns a DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        """
        parser_context = parser_context or {}
        request = parser_context['request']
        meta = request.META
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers)
            data, files = parser.parse()
            return DataAndFiles(data, files)
        except MultiPartParserError, exc:
            raise ParseError('Multipart form parse error - %s' % unicode(exc))
Example #15
0
def _parse_request_data(request):
    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get("CONTENT_TYPE", "")

        if content_type.startswith("application/json"):
            return (json.loads(request.body), None, None)

        elif content_type.startswith("multipart/form-data"):
            parser = MultiPartParser(request.META, StringIO(request.body), request.upload_handlers, request.encoding)
            data, files = parser.parse()
            return (data, files, None)

        else:
            return (None, None, _bad_request(_("Unsupported content-type: %s") % content_type))

    except Exception, e:
        return (None, None, _bad_request(_("Request parsing error: %s") % e))
Example #16
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Returns a DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        """
        parser_context = parser_context or {}
        request = parser_context['request']
        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
        meta = request.META
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding)
            data, files = parser.parse()
            return DataAndFiles(data, files)
        except MultiPartParserError as exc:
            raise ParseError('Multipart form parse error - %s' % six.u(exc))
Example #17
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Returns a DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        """
        parser_context = parser_context or {}
        request = parser_context['request']
        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
        meta = request.META
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers,
                                           encoding)
            data, files = parser.parse()
            return DataAndFiles(data, files)
        except MultiPartParserError as exc:
            raise ParseError('Multipart form parse error - %s' % six.u(exc))
Example #18
0
def _parse_request_data(request):
    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get('CONTENT_TYPE', '')

        if content_type.startswith('application/json'):
            return (json.loads(request.body), None, None)

        elif content_type.startswith('multipart/form-data'):
            parser = MultiPartParser(request.META, StringIO(request.body),
                                     request.upload_handlers, request.encoding)
            data, files = parser.parse()
            return (data, files, None)

        else:
            return (None, None,
                    _bad_request(
                        _("Unsupported content-type: %s") % content_type))

    except Exception, e:
        return (None, None, _bad_request(_("Request parsing error: %s") % e))
    def parse(self, stream, media_type=None, parser_context=None):
        '''
        Parses the incoming bytestream as a multipart encoded form,
        and returns a DataAndFiles object.
        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        '''
        parser_context = parser_context or {}
        request = parser_context['request']
        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
        meta = request.META.copy()
        meta['CONTENT_TYPE'] = media_type
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding)
            data, files = parser.parse()

            return DataAndFiles(decamelize(data), decamelize(files), )
        except MultiPartParserError as err:
            raise ParseError(f'Multipart form parse error - {err}')
Example #20
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Parses the incoming bytestream as a multipart encoded form,
        and returns a DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        """
        parser_context = parser_context or {}
        request = parser_context["request"]
        encoding = parser_context.get("encoding", settings.DEFAULT_CHARSET)
        meta = request.META.copy()
        meta["CONTENT_TYPE"] = media_type
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding)
            data, files = parser.parse()
            return DataAndFiles(data, files)
        except MultiPartParserError as exc:
            raise ParseError("Multipart form parse error - %s" % str(exc))
Example #21
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Parses the incoming bytestream as a multipart encoded form,
        and returns a DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        """
        parser_context = parser_context or {}
        request = parser_context["request"]
        encoding = parser_context.get("encoding", settings.DEFAULT_CHARSET)
        meta = request.META.copy()
        meta["CONTENT_TYPE"] = media_type
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding)
            data, files = parser.parse()
            return DataAndFiles(data, files)
        except MultiPartParserError as exc:
            raise ParseError("Multipart form parse error - %s" % str(exc))
Example #22
0
    def parse(self, stream, media_type=None, parser_context=None):
        parser_context = parser_context or {}
        request = parser_context['request']
        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
        meta = request.META.copy()
        meta['CONTENT_TYPE'] = media_type
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers,
                                           encoding)
            data, files = parser.parse()
            result = parsers.DataAndFiles(data, files)
            data = {}
            data = json.loads(result.data["data"])
            for key, value in result.files.items():
                data = compile_payload(data, key.split("."), value)
            return data
        except MultiPartParserError as exc:
            raise ParseError('Multipart form parse error - %s' %
                             six.text_type(exc))
Example #23
0
    def parse_file_upload(self, META, post_data):
        """Return a tuple of (POST QueryDict, FILES MultiValueDict)."""
        # self 是「请求对象」
        self.upload_handlers = ImmutableList(
            self.upload_handlers,
            warning=
            "You cannot alter upload handlers after the upload has been processed."
        )
        print('【django.http.request.HttpRequest.parse_file_upload】'
              '「请求对象」创建「请求表单解析对象」并调用其 parse 方法')

        # 此类定义在 django.http.multipartparser 模块中,其实例被称为「请求表单解析对象」
        # META 是包含请求头信息的字典对象
        # post_data 是 self ,也就是「请求对象」
        # self.upload_handlers 是元组,里面是一些文件上传相关的对象
        # self.encoding 是字符串或 None TODO
        parser = MultiPartParser(META, post_data, self.upload_handlers,
                                 self.encoding)
        # 调用「请求表单解析对象」的 parse 方法
        # 处理请求体中的表单数据和文件数据,生成两个类字典对象并返回
        return parser.parse()
def parse_body(r, request):
    if request.method == 'POST' or request.method == 'PUT':
        # Parse out profiles/states if the POST dict is not empty
        if 'multipart/form-data' in request.META['CONTENT_TYPE']:
            if request.POST.dict().keys():
                r['params'].update(request.POST.dict())
                parser = MultiPartParser(request.META, StringIO.StringIO(request.raw_post_data),request.upload_handlers)
                post, files = parser.parse()
                r['files'] = files
        # If it is multipart/mixed, parse out all data
        elif 'multipart/mixed' in request.META['CONTENT_TYPE']: 
            parse_attachment(r, request)
        # Normal POST/PUT data
        else:
            if request.body:
                # profile uses the request body
                r['raw_body'] = request.body
                # Body will be some type of string, not necessarily JSON
                r['body'] = convert_to_dict(request.body)
            else:
                raise BadRequest("No body in request")
    return r
 def process_request(self,req):
     """Interpret POST variables that indicate fake file uploads."""
     #  Bail out if any real files were uploaded
     if len(req.FILES) > 0:
         return None
     #  Find any post variables named like "fakefile_*".
     #  These contain the fake files that are to be uploaded.
     fakefiles = []
     for (k,v) in req.POST.iteritems():
         if k.startswith(self.field_name):
             if v == "": continue
             fakefiles.append((k[len(self.field_name):],self.file_spec[v]))
     if not fakefiles:
         return None
     #  Remove the fakefile keys from POST
     for f in fakefiles:
         del req.POST[self.field_name + f[0]]
     #  Construct a fake request body and META object
     fake_data = FakeFilesData(fakefiles)
     fake_meta = MergeDict(fake_data.META,req.META)
     #  Re-parse the fake data, triggering upload handlers etc.
     parser = MultiPartParser(fake_meta,fake_data,req.upload_handlers,req.encoding)
     (_, req._files) = parser.parse()
Example #26
0
    def parse(self, stream, media_type=None, parser_context=None):
        """Parse the incoming bytestream.

        Parses the incoming bytestream as a multipart encoded form and returns a
        DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters,
        and JSON decoded where available.
        `.files` will be a `QueryDict` containing all the form files.

        :param (bytes) stream: Incoming byte stream.
        :param (str) media_type: Media Type.
        :param (dict) parser_context: Context.
        """
        parser_context = parser_context or {}
        request = parser_context["request"]
        encoding = parser_context.get("encoding", settings.DEFAULT_CHARSET)
        meta = request.META.copy()
        meta["CONTENT_TYPE"] = media_type
        upload_handlers = request.upload_handlers

        try:
            parser = DjangoMultiPartParser(meta, stream, upload_handlers,
                                           encoding)
            data, files = parser.parse()
            # get a dict of data to make it mutable
            _data = data.dict()
            for key in _data:
                if _data[key]:
                    try:
                        _data[key] = json.loads(_data[key])
                    except ValueError:
                        pass
            return DataAndFiles(_data, files)
        except MultiPartParserError as exc:
            raise ParseError("Multipart form parse error - %s" % str(exc))
Example #27
0
 def process_request(self, req):
     """Interpret POST variables that indicate fake file uploads."""
     #  Bail out if any real files were uploaded
     if len(req.FILES) > 0:
         return None
     #  Find any post variables named like "fakefile_*".
     #  These contain the fake files that are to be uploaded.
     fakefiles = []
     for (k, v) in req.POST.iteritems():
         if k.startswith(self.field_name):
             if v == "": continue
             fakefiles.append((k[len(self.field_name):], self.file_spec[v]))
     if not fakefiles:
         return None
     #  Remove the fakefile keys from POST
     for f in fakefiles:
         del req.POST[self.field_name + f[0]]
     #  Construct a fake request body and META object
     fake_data = FakeFilesData(fakefiles)
     fake_meta = MergeDict(fake_data.META, req.META)
     #  Re-parse the fake data, triggering upload handlers etc.
     parser = MultiPartParser(fake_meta, fake_data, req.upload_handlers,
                              req.encoding)
     (_, req._files) = parser.parse()
Example #28
0
def parse_body(r, request):
    if request.method == 'POST' or request.method == 'PUT':
        # Parse out profiles/states if the POST dict is not empty
        if 'multipart/form-data' in request.META['CONTENT_TYPE']:
            if request.POST.dict().keys():
                r['params'].update(request.POST.dict())
                parser = MultiPartParser(
                    request.META, StringIO.StringIO(request.raw_post_data),
                    request.upload_handlers)
                post, files = parser.parse()
                r['files'] = files
        # If it is multipart/mixed, parse out all data
        elif 'multipart/mixed' in request.META['CONTENT_TYPE']:
            parse_attachment(r, request)
        # Normal POST/PUT data
        else:
            if request.body:
                # profile uses the request body
                r['raw_body'] = request.body
                # Body will be some type of string, not necessarily JSON
                r['body'] = convert_to_dict(request.body)
            else:
                raise BadRequest("No body in request")
    return r
Example #29
0
def _document_api_PUT(request, document_slug, document_locale):
    """
    Handle PUT requests for the document_api view.
    """

    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get('CONTENT_TYPE', '')

        if content_type.startswith('application/json'):
            data = json.loads(request.body)

        elif content_type.startswith('multipart/form-data'):
            parser = MultiPartParser(request.META, StringIO(request.body),
                                     request.upload_handlers, request.encoding)
            data, files = parser.parse()

        elif content_type.startswith('text/html'):
            # TODO: Refactor this into wiki.content ?
            # First pass: Just assume the request body is an HTML fragment.
            html = request.body
            data = dict(content=html)

            # Second pass: Try parsing the body as a fuller HTML document,
            # and scrape out some of the interesting parts.
            try:
                doc = pq(html)
                head_title = doc.find('head title')
                if head_title.length > 0:
                    data['title'] = head_title.text()
                body_content = doc.find('body')
                if body_content.length > 0:
                    data['content'] = to_html(body_content)
            except Exception:
                pass

        else:
            resp = HttpResponse()
            resp.status_code = 400
            resp.content = ugettext(
                "Unsupported content-type: %s") % content_type
            return resp

    except Exception as e:
        resp = HttpResponse()
        resp.status_code = 400
        resp.content = ugettext("Request parsing error: %s") % e
        return resp

    try:
        # Look for existing document to edit:
        doc = Document.objects.get(locale=document_locale, slug=document_slug)
        section_id = request.GET.get('section', None)
        is_new = False

        # Use ETags to detect mid-air edit collision
        # see: http://www.w3.org/1999/04/Editing/
        if_match = request.META.get('HTTP_IF_MATCH')
        if if_match:
            try:
                expected_etags = parse_etags(if_match)
            except ValueError:
                expected_etags = []
            # Django's parse_etags returns a list of quoted rather than
            # un-quoted ETags starting with version 1.11.
            current_etag = quote_etag(calculate_etag(doc.get_html(section_id)))
            if current_etag not in expected_etags:
                resp = HttpResponse()
                resp.status_code = 412
                resp.content = ugettext('ETag precondition failed')
                return resp

    except Document.DoesNotExist:
        # TODO: There should be a model utility for creating a doc...

        # Let's see if this slug path implies a parent...
        slug_parts = split_slug(document_slug)
        if not slug_parts['parent']:
            # Apparently, this is a root page!
            parent_doc = None
        else:
            # There's a parent implied, so make sure we can find it.
            parent_doc = get_object_or_404(Document,
                                           locale=document_locale,
                                           slug=slug_parts['parent'])

        # Create and save the new document; we'll revise it immediately.
        doc = Document(slug=document_slug,
                       locale=document_locale,
                       title=data.get('title', document_slug),
                       parent_topic=parent_doc)
        doc.save()
        section_id = None  # No section editing for new document!
        is_new = True

    new_rev = doc.revise(request.user, data, section_id)
    doc.schedule_rendering('max-age=0')

    request.authkey.log('created' if is_new else 'updated', new_rev,
                        data.get('summary', None))

    resp = HttpResponse()
    if is_new:
        resp['Location'] = request.build_absolute_uri(doc.get_absolute_url())
        resp.status_code = 201
    else:
        resp.status_code = 205

    return resp
Example #30
0
from __future__ import unicode_literals
Example #31
0
def _document_PUT(request, document_slug, document_locale):
    """Handle PUT requests as document write API"""

    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get('CONTENT_TYPE', '')

        if content_type.startswith('application/json'):
            data = json.loads(request.body)

        elif content_type.startswith('multipart/form-data'):
            parser = MultiPartParser(request.META, StringIO(request.body),
                                     request.upload_handlers, request.encoding)
            data, files = parser.parse()

        elif content_type.startswith('text/html'):
            # TODO: Refactor this into wiki.content ?
            # First pass: Just assume the request body is an HTML fragment.
            html = request.body
            data = dict(content=html)

            # Second pass: Try parsing the body as a fuller HTML document,
            # and scrape out some of the interesting parts.
            try:
                doc = pq(html)
                head_title = doc.find('head title')
                if head_title.length > 0:
                    data['title'] = head_title.text()
                body_content = doc.find('body')
                if body_content.length > 0:
                    data['content'] = body_content.html()
            except Exception:
                pass

        else:
            resp = HttpResponse()
            resp.status_code = 400
            resp.content = _("Unsupported content-type: %s") % content_type
            return resp

    except Exception as e:
        resp = HttpResponse()
        resp.status_code = 400
        resp.content = _("Request parsing error: %s") % e
        return resp

    try:
        # Look for existing document to edit:
        doc = Document.objects.get(locale=document_locale, slug=document_slug)
        if not doc.allows_revision_by(request.user):
            raise PermissionDenied
        section_id = request.GET.get('section', None)
        is_new = False

        # Use ETags to detect mid-air edit collision
        # see: http://www.w3.org/1999/04/Editing/
        expected_etag = request.META.get('HTTP_IF_MATCH', False)
        if expected_etag:
            curr_etag = doc.calculate_etag(section_id)
            if curr_etag != expected_etag:
                resp = HttpResponse()
                resp.status_code = 412
                resp.content = _('ETag precondition failed')
                return resp

    except Document.DoesNotExist:
        # No existing document, so this is an attempt to create a new one...
        if not Document.objects.allows_add_by(request.user, document_slug):
            raise PermissionDenied

        # TODO: There should be a model utility for creating a doc...

        # Let's see if this slug path implies a parent...
        slug_parts = split_slug(document_slug)
        if not slug_parts['parent']:
            # Apparently, this is a root page!
            parent_doc = None
        else:
            # There's a parent implied, so make sure we can find it.
            parent_doc = get_object_or_404(Document,
                                           locale=document_locale,
                                           slug=slug_parts['parent'])

        # Create and save the new document; we'll revise it immediately.
        doc = Document(slug=document_slug,
                       locale=document_locale,
                       title=data.get('title', document_slug),
                       parent_topic=parent_doc,
                       category=Document.CATEGORIES[0][0])
        doc.save()
        section_id = None  # No section editing for new document!
        is_new = True

    new_rev = doc.revise(request.user, data, section_id)
    doc.schedule_rendering('max-age=0')

    request.authkey.log(is_new and 'created' or 'updated', new_rev,
                        data.get('summary', None))

    resp = HttpResponse()
    if not is_new:
        resp.content = 'RESET'
        resp.status_code = 205
    else:
        resp.content = 'CREATED'
        new_loc = request.build_absolute_uri(doc.get_absolute_url())
        resp['Location'] = new_loc
        resp.status_code = 201

    return resp
Example #32
0
def _document_PUT(request, document_slug, document_locale):
    """Handle PUT requests as document write API"""

    # Try parsing one of the supported content types from the request
    try:
        content_type = request.META.get('CONTENT_TYPE', '')

        if content_type.startswith('application/json'):
            data = json.loads(request.body)

        elif content_type.startswith('multipart/form-data'):
            parser = MultiPartParser(request.META,
                                     StringIO(request.body),
                                     request.upload_handlers,
                                     request.encoding)
            data, files = parser.parse()

        elif content_type.startswith('text/html'):
            # TODO: Refactor this into wiki.content ?
            # First pass: Just assume the request body is an HTML fragment.
            html = request.body
            data = dict(content=html)

            # Second pass: Try parsing the body as a fuller HTML document,
            # and scrape out some of the interesting parts.
            try:
                doc = pq(html)
                head_title = doc.find('head title')
                if head_title.length > 0:
                    data['title'] = head_title.text()
                body_content = doc.find('body')
                if body_content.length > 0:
                    data['content'] = body_content.html()
            except Exception:
                pass

        else:
            resp = HttpResponse()
            resp.status_code = 400
            resp.content = ugettext(
                "Unsupported content-type: %s") % content_type
            return resp

    except Exception as e:
        resp = HttpResponse()
        resp.status_code = 400
        resp.content = ugettext("Request parsing error: %s") % e
        return resp

    try:
        # Look for existing document to edit:
        doc = Document.objects.get(locale=document_locale,
                                   slug=document_slug)
        if not doc.allows_revision_by(request.user):
            raise PermissionDenied
        section_id = request.GET.get('section', None)
        is_new = False

        # Use ETags to detect mid-air edit collision
        # see: http://www.w3.org/1999/04/Editing/
        expected_etag = request.META.get('HTTP_IF_MATCH', False)
        if expected_etag:
            curr_etag = doc.calculate_etag(section_id)
            if curr_etag != expected_etag:
                resp = HttpResponse()
                resp.status_code = 412
                resp.content = ugettext('ETag precondition failed')
                return resp

    except Document.DoesNotExist:
        # No existing document, so this is an attempt to create a new one...
        if not Document.objects.allows_add_by(request.user, document_slug):
            raise PermissionDenied

        # TODO: There should be a model utility for creating a doc...

        # Let's see if this slug path implies a parent...
        slug_parts = split_slug(document_slug)
        if not slug_parts['parent']:
            # Apparently, this is a root page!
            parent_doc = None
        else:
            # There's a parent implied, so make sure we can find it.
            parent_doc = get_object_or_404(Document, locale=document_locale,
                                           slug=slug_parts['parent'])

        # Create and save the new document; we'll revise it immediately.
        doc = Document(slug=document_slug, locale=document_locale,
                       title=data.get('title', document_slug),
                       parent_topic=parent_doc)
        doc.save()
        section_id = None  # No section editing for new document!
        is_new = True

    new_rev = doc.revise(request.user, data, section_id)
    doc.schedule_rendering('max-age=0')

    request.authkey.log(is_new and 'created' or 'updated',
                        new_rev, data.get('summary', None))

    resp = HttpResponse()
    if not is_new:
        resp.content = 'RESET'
        resp.status_code = 205
    else:
        resp.content = 'CREATED'
        new_loc = request.build_absolute_uri(doc.get_absolute_url())
        resp['Location'] = new_loc
        resp.status_code = 201

    return resp