Beispiel #1
0
 def test_get_requested_mimetype_with_unsupported_mimetype(self):
     """Testing djblets.http.get_requested_mimetype with unsupported
     mimetype
     """
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['text/plain']), None)
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['foo/bar']), None)
Beispiel #2
0
 def test_get_requested_mimetype_with_unsupported_mimetype(self):
     """Testing djblets.http.get_requested_mimetype with unsupported mimetype"""
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['text/plain']),
         None)
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['foo/bar']),
         None)
Beispiel #3
0
 def test_get_requested_mimetype_with_supported_mimetype(self):
     """Testing djblets.http.get_requested_mimetype with supported
     mimetype
     """
     self.assertEqual(get_http_requested_mimetype(self.request, ["foo/bar", "application/json"]), "application/json")
     self.assertEqual(get_http_requested_mimetype(self.request, ["application/xml"]), "application/xml")
     self.assertEqual(
         get_http_requested_mimetype(self.request, ["application/json", "application/xml"]), "application/xml"
     )
Beispiel #4
0
 def test_get_requested_mimetype_with_supported_mimetype(self):
     """Testing djblets.http.get_requested_mimetype with supported mimetype"""
     self.assertEqual(
         get_http_requested_mimetype(self.request,
                                     ['foo/bar', 'application/json']),
         'application/json')
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['application/xml']),
         'application/xml')
     self.assertEqual(
         get_http_requested_mimetype(
             self.request, ['application/json', 'application/xml']),
         'application/xml')
Beispiel #5
0
 def test_get_requested_mimetype_with_supported_mimetype(self):
     """Testing djblets.http.get_requested_mimetype with supported mimetype"""
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['foo/bar',
                                                    'application/json']),
         'application/json')
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['application/xml']),
         'application/xml')
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['application/json',
                                                    'application/xml']),
         'application/xml')
Beispiel #6
0
    def get(self, request, *args, **kwargs):
        """Returns the information or contents on a particular diff.

        The output varies by mimetype.

        If :mimetype:`application/json` or :mimetype:`application/xml` is
        used, then the fields for the diff are returned, like with any other
        resource.

        If :mimetype:`text/x-patch` is used, then the actual diff file itself
        is returned. This diff should be as it was when uploaded originally,
        with potentially some extra SCM-specific headers stripped. The
        contents will contain that of all per-file diffs that make up this
        diff.
        """
        mimetype = get_http_requested_mimetype(
            request,
            [
                mimetype['item']
                for mimetype in self.allowed_mimetypes
            ])

        if mimetype == 'text/x-patch':
            return self._get_patch(request, *args, **kwargs)
        else:
            return super(DiffResource, self).get(request, *args, **kwargs)
Beispiel #7
0
 def test_get_requested_mimetype_with_wildcard_supported_mimetype(self):
     """Testing get_requested_mimetype with supported */* mimetype"""
     self.request.META['HTTP_ACCEPT'] = '*/*'
     self.assertEqual(
         get_http_requested_mimetype(
             self.request, ['application/json', 'application/xml']),
         'application/json')
Beispiel #8
0
 def test_get_requested_mimetype_with_wildcard_supported_mimetype(self):
     """Testing get_requested_mimetype with supported */* mimetype"""
     self.request.META['HTTP_ACCEPT'] = '*/*'
     self.assertEqual(
         get_http_requested_mimetype(self.request, ['application/json',
                                                    'application/xml']),
         'application/json')
Beispiel #9
0
    def get(self, request, *args, **kwargs):
        """Return information about a commit.

        If the :mimetype:`text/x-patch` mimetype is requested, the contents of
        the patch will be returned.

        Otherwise, metadata about the commit (such as author name, author date,
        etc.) will be returned.
        """
        mimetype = get_http_requested_mimetype(
            request, [mimetype['item'] for mimetype in self.allowed_mimetypes])

        if mimetype != 'text/x-patch':
            return super(DiffCommitResource, self).get(request, *args,
                                                       **kwargs)

        try:
            review_request = resources.review_request.get_object(
                request, *args, **kwargs)
            commit = self.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_access_permissions(request, commit, *args, **kwargs):
            return self.get_no_access_error(request)

        tool = review_request.repository.get_scmtool()
        data = tool.get_parser('').raw_diff(commit)

        rsp = HttpResponse(data, content_type=mimetype)
        rsp['Content-Disposition'] = ('inline; filename=%s.patch' %
                                      commit.commit_id)

        set_last_modified(rsp, commit.last_modified)
        return rsp
Beispiel #10
0
    def get(self, request, *args, **kwargs):
        """Returns the information or contents on a particular diff.

        The output varies by mimetype.

        If :mimetype:`application/json` or :mimetype:`application/xml` is
        used, then the fields for the diff are returned, like with any other
        resource.

        If :mimetype:`text/x-patch` is used, then the actual diff file itself
        is returned. This diff should be as it was when uploaded originally,
        with potentially some extra SCM-specific headers stripped. The
        contents will contain that of all per-file diffs that make up this
        diff.
        """
        mimetype = get_http_requested_mimetype(
            request,
            [
                mimetype['item']
                for mimetype in self.allowed_mimetypes
            ])

        if mimetype == 'text/x-patch':
            return self._get_patch(request, *args, **kwargs)
        else:
            return super(DiffResource, self).get(request, *args, **kwargs)
Beispiel #11
0
    def _build_error_mimetype(self, request):
        mimetype = get_http_requested_mimetype(
            request, WebAPIResponse.supported_mimetypes)

        if self.mimetype_vendor:
            mimetype = self._build_vendor_mimetype(mimetype, 'error')

        return mimetype
Beispiel #12
0
    def _build_error_mimetype(self, request):
        mimetype = get_http_requested_mimetype(
            request, WebAPIResponse.supported_mimetypes)

        if self.mimetype_vendor:
            mimetype = self._build_vendor_mimetype(mimetype, 'error')

        return mimetype
Beispiel #13
0
 def test_get_requested_mimetype_with_wildcard_supported_mimetype(self):
     """Testing djblets.http.get_requested_mimetype with supported */*
     mimetype
     """
     self.request = HttpRequest()
     self.request.META["HTTP_ACCEPT"] = "*/*"
     self.assertEqual(
         get_http_requested_mimetype(self.request, ["application/json", "application/xml"]), "application/json"
     )
Beispiel #14
0
    def test_get_requested_mimetype_with_no_consensus(self):
        """Testing djblets.http.get_requested_mimetype with no consensus between client and server"""
        self.request = HttpRequest()
        self.request.META['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'

        self.assertEqual(
            get_http_requested_mimetype(self.request, ['application/json',
                                                       'application/x-foo']),
            'application/json')
Beispiel #15
0
    def test_get_requested_mimetype_with_no_consensus(self):
        """Testing djblets.http.get_requested_mimetype with no consensus between client and server"""
        self.request = HttpRequest()
        self.request.META['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'

        self.assertEqual(
            get_http_requested_mimetype(self.request, ['application/json',
                                                       'application/x-foo']),
            'application/json')
Beispiel #16
0
    def __init__(self,
                 request,
                 obj={},
                 stat='ok',
                 api_format=None,
                 status=200,
                 headers={},
                 encoders=[],
                 mimetype=None,
                 supported_mimetypes=None):
        if not api_format:
            if request.method == 'GET':
                api_format = request.GET.get('api_format', None)
            else:
                api_format = request.POST.get('api_format', None)

        if not supported_mimetypes:
            supported_mimetypes = self.supported_mimetypes

        if not mimetype:
            if not api_format:
                mimetype = get_http_requested_mimetype(request,
                                                       supported_mimetypes)
            elif api_format == "json":
                mimetype = 'application/json'
            elif api_format == "xml":
                mimetype = 'application/xml'

        if not mimetype:
            self.status_code = 400
            self.content_set = True
            return

        if not request.is_ajax() and request.FILES:
            # When uploading a file using AJAX to a webapi view,
            # we must set the mimetype to text/plain. If we use
            # application/json instead, the browser will ask the user
            # to save the file. It's not great, but it's what we must do.
            mimetype = 'text/plain'

        super(WebAPIResponse, self).__init__(content_type=mimetype,
                                             status=status)
        self.request = request
        self.callback = request.GET.get('callback', None)
        self.api_data = {'stat': stat}
        self.api_data.update(obj)
        self.content_set = False
        self.mimetype = mimetype
        self.encoders = encoders or get_registered_encoders()

        for header, value in six.iteritems(headers):
            self[header] = value

        # Prevent IE8 from trying to download some AJAX responses as if they
        # were files.
        self['X-Content-Type-Options'] = 'nosniff'
Beispiel #17
0
    def __init__(self, request, obj={}, stat='ok', api_format=None,
                 status=200, headers={}, encoders=[],
                 encoder_kwargs={}, mimetype=None, supported_mimetypes=None):
        if not api_format:
            if request.method == 'GET':
                api_format = request.GET.get('api_format', None)
            else:
                api_format = request.POST.get('api_format', None)

        if not supported_mimetypes:
            supported_mimetypes = self.supported_mimetypes

        if not mimetype:
            if not api_format:
                mimetype = get_http_requested_mimetype(request,
                                                       supported_mimetypes)
            elif api_format == "json":
                mimetype = 'application/json'
            elif api_format == "xml":
                mimetype = 'application/xml'

        if not mimetype:
            self.status_code = 400
            self.content_set = True
            return

        if not request.is_ajax() and request.FILES:
            # When uploading a file using AJAX to a webapi view,
            # we must set the mimetype to text/plain. If we use
            # application/json instead, the browser will ask the user
            # to save the file. It's not great, but it's what we must do.
            mimetype = 'text/plain'

        super(WebAPIResponse, self).__init__(content_type=mimetype,
                                             status=status)
        self.request = request
        self.callback = request.GET.get('callback', None)
        self.api_data = {'stat': stat}
        self.api_data.update(obj)
        self.content_set = False
        self.mimetype = mimetype
        self.encoders = encoders or get_registered_encoders()
        self.encoder_kwargs = encoder_kwargs

        for header, value in six.iteritems(headers):
            self[header] = value

        # Prevent IE8 from trying to download some AJAX responses as if they
        # were files.
        self['X-Content-Type-Options'] = 'nosniff'
Beispiel #18
0
    def __init__(self,
                 request,
                 obj={},
                 stat='ok',
                 api_format=None,
                 status=200,
                 headers={},
                 encoders=[]):
        if not api_format:
            if request.method == 'GET':
                api_format = request.GET.get('api_format', None)
            else:
                api_format = request.POST.get('api_format', None)

        if not api_format:
            mimetype = get_http_requested_mimetype(request,
                                                   self.supported_mimetypes)
        elif api_format == "json":
            mimetype = 'application/json'
        elif api_format == "xml":
            mimetype = 'application/xml'
        else:
            mimetype = None

        if not mimetype:
            self.status_code = 400
            self.content_set = True
            return

        if mimetype == 'application/json' and request.FILES:
            # When uploading a file using AJAX to a webapi view,
            # we must set the mimetype to text/plain. If we use
            # application/json instead, the browser will ask the user
            # to save the file. It's not great, but it's what we must do.
            mimetype = 'text/plain'

        super(WebAPIResponse, self).__init__(mimetype=mimetype, status=status)
        self.request = request
        self.callback = request.GET.get('callback', None)
        self.api_data = {'stat': stat}
        self.api_data.update(obj)
        self.content_set = False
        self.mimetype = mimetype
        self.encoders = encoders or get_registered_encoders()

        for header, value in headers.iteritems():
            self[header] = value
Beispiel #19
0
    def __init__(self, request, obj={}, stat='ok', api_format=None,
                 status=200, headers={}, encoders=[],
                 encoder_kwargs={}, mimetype=None, supported_mimetypes=None):
        if not api_format:
            if request.method == 'GET':
                api_format = request.GET.get('api_format', None)
            else:
                api_format = request.POST.get('api_format', None)

        if not supported_mimetypes:
            supported_mimetypes = self.supported_mimetypes

        if not mimetype:
            if not api_format:
                mimetype = get_http_requested_mimetype(request,
                                                       supported_mimetypes)
            elif api_format == "json":
                mimetype = 'application/json'
            elif api_format == "xml":
                mimetype = 'application/xml'

        if not mimetype:
            self.status_code = 400
            self.content_set = True
            return

        super(WebAPIResponse, self).__init__(content_type=mimetype,
                                             status=status)
        self.request = request
        self.callback = request.GET.get('callback', None)
        self.api_data = {'stat': stat}
        self.api_data.update(obj)
        self.content_set = False
        self.mimetype = mimetype
        self.encoders = encoders or get_registered_encoders()
        self.encoder_kwargs = encoder_kwargs

        for header, value in six.iteritems(headers):
            self[header] = value

        # Prevent IE8 from trying to download some AJAX responses as if they
        # were files.
        self['X-Content-Type-Options'] = 'nosniff'
Beispiel #20
0
    def __init__(self, request, obj={}, stat='ok', api_format=None,
                 status=200, headers={}, encoders=[]):
        if not api_format:
            if request.method == 'GET':
                api_format = request.GET.get('api_format', None)
            else:
                api_format = request.POST.get('api_format', None)

        if not api_format:
            mimetype = get_http_requested_mimetype(request, self.supported_mimetypes)
        elif api_format == "json":
            mimetype = 'application/json'
        elif api_format == "xml":
            mimetype = 'application/xml'
        else:
            mimetype = None

        if not mimetype:
            self.status_code = 400
            self.content_set = True
            return

        if mimetype == 'application/json' and request.FILES:
            # When uploading a file using AJAX to a webapi view,
            # we must set the mimetype to text/plain. If we use
            # application/json instead, the browser will ask the user
            # to save the file. It's not great, but it's what we must do.
            mimetype = 'text/plain'

        super(WebAPIResponse, self).__init__(mimetype=mimetype,
                                             status=status)
        self.request = request
        self.callback = request.GET.get('callback', None)
        self.api_data = {'stat': stat}
        self.api_data.update(obj)
        self.content_set = False
        self.mimetype = mimetype
        self.encoders = encoders or get_registered_encoders()

        for header, value in headers.iteritems():
            self[header] = value
Beispiel #21
0
    def build_response_args(self, request):
        is_list = (request._djblets_webapi_method == 'GET' and
                   not self.singleton and
                   (self.uri_object_key is None or
                    self.uri_object_key not in request._djblets_webapi_kwargs))

        if is_list:
            key = 'list'
        else:
            key = 'item'

        supported_mimetypes = [
            mime[key]
            for mime in self.allowed_mimetypes
            if mime[key]
        ]

        mimetype = get_http_requested_mimetype(request, supported_mimetypes)

        if (self.mimetype_vendor and
            mimetype in WebAPIResponse.supported_mimetypes):
            mimetype = self._build_resource_mimetype(mimetype, is_list)

        response_args = {
            'supported_mimetypes': supported_mimetypes,
            'mimetype': mimetype,
        }

        if is_list:
            for mimetype_pair in self.allowed_mimetypes:
                if (mimetype_pair['list'] == mimetype and
                    mimetype_pair['item']):
                    response_args['headers'] = {
                        'Item-Content-Type': mimetype_pair['item'],
                    }
                    break

        return response_args
Beispiel #22
0
    def build_response_args(self, request):
        is_list = (request._djblets_webapi_method == 'GET' and
                   not self.singleton and
                   (self.uri_object_key is None or
                    self.uri_object_key not in request._djblets_webapi_kwargs))

        if is_list:
            key = 'list'
        else:
            key = 'item'

        supported_mimetypes = [
            mime[key]
            for mime in self.allowed_mimetypes
            if mime.get(key)
        ]

        mimetype = get_http_requested_mimetype(request, supported_mimetypes)

        if (self.mimetype_vendor and
            mimetype in WebAPIResponse.supported_mimetypes):
            mimetype = self._build_resource_mimetype(mimetype, is_list)

        response_args = {
            'supported_mimetypes': supported_mimetypes,
            'mimetype': mimetype,
        }

        if is_list:
            for mimetype_pair in self.allowed_mimetypes:
                if (mimetype_pair.get('list') == mimetype and
                    mimetype_pair.get('item')):
                    response_args['headers'] = {
                        'Item-Content-Type': mimetype_pair['item'],
                    }
                    break

        return response_args
Beispiel #23
0
    def build_response_args(self, request):
        is_list = (request._djblets_webapi_method == 'GET' and
                   not self.singleton and
                   (self.uri_object_key is None or
                    self.uri_object_key not in request._djblets_webapi_kwargs))

        if is_list:
            supported_mimetypes = self.allowed_list_mimetypes
        else:
            supported_mimetypes = self.allowed_item_mimetypes

        mimetype = get_http_requested_mimetype(request,
                                               supported_mimetypes)

        if (self.mimetype_vendor and
            mimetype in WebAPIResponse.supported_mimetypes):
            mimetype = self._build_resource_mimetype(mimetype,
                                                     is_list)

        return {
            'supported_mimetypes': supported_mimetypes,
            'mimetype': mimetype,
        }
Beispiel #24
0
    def get(self, request, *args, **kwargs):
        """Return information about a commit.

        If the :mimetype:`text/x-patch` mimetype is requested, the contents of
        the patch will be returned.

        Otherwise, metadata about the commit (such as author name, author date,
        etc.) will be returned.
        """
        mimetype = get_http_requested_mimetype(
            request,
            [mimetype['item'] for mimetype in self.allowed_mimetypes])

        if mimetype != 'text/x-patch':
            return super(DiffCommitResource, self).get(request, *args,
                                                       **kwargs)

        try:
            review_request = resources.review_request.get_object(
                request, *args, **kwargs)
            commit = self.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_access_permissions(request, commit, *args, **kwargs):
            return self.get_no_access_error(request)

        tool = review_request.repository.get_scmtool()
        data = tool.get_parser('').raw_diff(commit)

        rsp = HttpResponse(data, content_type=mimetype)
        rsp['Content-Disposition'] = ('inline; filename=%s.patch'
                                      % commit.commit_id)

        set_last_modified(rsp, commit.last_modified)
        return rsp
Beispiel #25
0
    def get(self, request, *args, **kwargs):
        """Returns the information or contents on a per-file diff.

        The output varies by mimetype.

        If :mimetype:`application/json` or :mimetype:`application/xml` is
        used, then the fields for the diff are returned, like with any other
        resource.

        If :mimetype:`text/x-patch` is used, then the actual diff file itself
        is returned. This diff should be as it was when uploaded originally,
        for this file only, with potentially some extra SCM-specific headers
        stripped.

        If :mimetype:`application/vnd.reviewboard.org.diff.data+json` or
        :mimetype:`application/vnd.reviewboard.org.diff.data+xml` is used,
        then the raw diff data (lists of inserts, deletes, replaces, moves,
        header information, etc.) is returned in either JSON or XML. This
        contains nearly all of the information used to render the diff in
        the diff viewer, and can be useful for building a diff viewer that
        interfaces with Review Board.

        If ``?syntax-highlighting=1`` is passed, the rendered diff content
        for each line will contain HTML markup showing syntax highlighting.
        Otherwise, the content will be in plain text.

        The format of the diff data is a bit complex. The data is stored
        under a top-level ``diff_data`` element and contains the following
        information:

        .. list-table::
           :header-rows: 1
           :widths: 10 15 75

           * - Field
             - Type
             - Description

           * - **binary**
             - Boolean
             - Whether or not the file is a binary file. Binary files
               won't have any diff content to display.

           * - **chunks**
             - List of Dictionary
             - A list of chunks. These are used to render the diff. See below.

           * - **changed_chunk_indexes**
             - List of Integer
             - The list of chunks in the diff that have actual changes
               (inserts, deletes, or replaces).

           * - **new_file**
             - Boolean
             - Whether or not this is a newly added file, rather than an
               existing file in the repository.

           * - **num_changes**
             - Integer
             - The number of changes made in this file (chunks of adds,
               removes, or deletes).

        Each chunk contains the following fields:

        .. list-table::
           :header-rows: 1
           :widths: 10 15 75

           * - Field
             - Type
             - Description

           * - **change**
             - One of ``equal``, ``delete``, ``insert``, ``replace``
             - The type of change on this chunk. The type influences what
               sort of information is available for the chunk.

           * - **collapsable**
             - Boolean
             - Whether or not this chunk is collapseable. A collapseable chunk
               is one that is hidden by default in the diff viewer, but can
               be expanded. These will always be ``equal`` chunks, but not
               every ``equal`` chunk is necessarily collapseable (as they
               may be there to provide surrounding context for the changes).

           * - **index**
             - Integer
             - The index of the chunk. This is 0-based.

           * - **lines**
             - List of List
             - The list of rendered lines for a side-by-side diff. Each
               entry in the list is itself a list with 8 items:

               1. Row number of the line in the combined side-by-side diff.
               2. The line number of the line in the left-hand file, as an
                  integer (for ``replace``, ``delete``, and ``equal`` chunks)
                  or an empty string (for ``insert``).
               3. The text for the line in the left-hand file.
               4. The indexes within the text for the left-hand file that
                  have been replaced by text in the right-hand side. Each
                  index is a list of ``start, end`` positions, 0-based.
                  This is only available for ``replace`` lines. Otherwise the
                  list is empty.
               5. The line number of the line in the right-hand file, as an
                  integer (for ``replace``, ``insert`` and ``equal`` chunks)
                  or an empty string (for ``delete``).
               6. The text for the line in the right-hand file.
               7. The indexes within the text for the right-hand file that
                  are replacements for text in the left-hand file. Each
                  index is a list of ``start, end`` positions, 0-based.
                  This is only available for ``replace`` lines. Otherwise the
                  list is empty.
               8. A boolean that indicates if the line contains only
                  whitespace changes.

           * - **meta**
             - Dictionary
             - Additional information about the chunk. See below for more
               information.

           * - **numlines**
             - Integer
             - The number of lines in the chunk.

        A chunk's meta information contains:

        .. list-table::
           :header-rows: 1
           :widths: 25 15 60

           * - Field
             - Type
             - Description

           * - **headers**
             - List of (String, String)
             - Class definitions, function definitions, or other useful
               headers that should be displayed before this chunk. This helps
               users to identify where in a file they are and what the current
               chunk may be a part of.

           * - **whitespace_chunk**
             - Boolean
             - Whether or not the entire chunk consists only of whitespace
               changes.

           * - **whitespace_lines**
             - List of (Integer, Integer)
             - A list of ``start, end`` row indexes in the lins that contain
               whitespace-only changes. These are 1-based.

        Other meta information may be available, but most is intended for
        internal use and shouldn't be relied upon.
        """
        mimetype = get_http_requested_mimetype(
            request,
            [
                mimetype['item']
                for mimetype in self.allowed_mimetypes
            ])

        if mimetype == 'text/x-patch':
            return self._get_patch(request, *args, **kwargs)
        elif mimetype.startswith(self.DIFF_DATA_MIMETYPE_BASE + "+"):
            return self._get_diff_data(request, mimetype, *args, **kwargs)
        else:
            return super(FileDiffResource, self).get(request, *args, **kwargs)
Beispiel #26
0
 def test_get_requested_mimetype_with_unsupported_mimetype(self):
     """Testing get_requested_mimetype with unsupported mimetype"""
     self.assertIsNone(get_http_requested_mimetype(self.request,
                                                   ['text/plain']))
     self.assertIsNone(get_http_requested_mimetype(self.request,
                                                   ['foo/bar']))
Beispiel #27
0
 def test_get_requested_mimetype_with_unsupported_mimetype(self):
     """Testing get_requested_mimetype with unsupported mimetype"""
     self.assertIsNone(
         get_http_requested_mimetype(self.request, ['text/plain']))
     self.assertIsNone(
         get_http_requested_mimetype(self.request, ['foo/bar']))
Beispiel #28
0
    def get(self, request, *args, **kwargs):
        """Returns the information or contents on a per-file diff.

        The output varies by mimetype.

        If :mimetype:`application/json` or :mimetype:`application/xml` is
        used, then the fields for the diff are returned, like with any other
        resource.

        If :mimetype:`text/x-patch` is used, then the actual diff file itself
        is returned. This diff should be as it was when uploaded originally,
        for this file only, with potentially some extra SCM-specific headers
        stripped.

        If :mimetype:`application/vnd.reviewboard.org.diff.data+json` or
        :mimetype:`application/vnd.reviewboard.org.diff.data+xml` is used,
        then the raw diff data (lists of inserts, deletes, replaces, moves,
        header information, etc.) is returned in either JSON or XML. This
        contains nearly all of the information used to render the diff in
        the diff viewer, and can be useful for building a diff viewer that
        interfaces with Review Board.

        If ``?syntax-highlighting=1`` is passed, the rendered diff content
        for each line will contain HTML markup showing syntax highlighting.
        Otherwise, the content will be in plain text.

        The format of the diff data is a bit complex. The data is stored
        under a top-level ``diff_data`` element and contains the following
        information:

        .. webapi-resource-field-list::

           .. webapi-resource-field::
              :name: binary
              :type: bool

              Whether or not the file is a binary file. Binary files won't
              have any diff content to display.

           .. webapi-resource-field::
              :name: changed_chunk_indexes
              :type: list[int]

              The list of chunks in the diff that have actual changes
              (inserts, deletes, or replaces).

           .. webapi-resource-field::
              :name: chunks
              :type: list[dict]

              A list of chunks. These are used to render the diff. See
              below.

           .. webapi-resource-field::
              :name: new_file
              :type: bool

              Whether or not this is a newly added file, rather than an
              existing file in the repository.

           .. webapi-resource-field::
              :name: num_changes
              :type: int

              The number of changes made in this file (chunks of adds,
              removes, or deletes).

        Each chunk contains the following fields:

        .. webapi-resource-field-list::

           .. webapi-resource-field::
              :name: change
              :type: ('equal', 'delete', 'insert', 'replace')

              The type of change on this chunk. The type influences what
              sort of information is available for the chunk.

           .. webapi-resource-field::
              :name: collapsable
              :type: bool

              Whether or not this chunk is collapseable. A collapseable
              chunk is one that is hidden by default in the diff viewer,
              but can be expanded. These will always be ``equal`` chunks,
              but not every ``equal`` chunk is necessarily collapseable (as
              they may be there to provide surrounding context for the
              changes).

           .. webapi-resource-field::
              :name: index
              :type: int

              The index of the chunk. This is 0-based.

           .. webapi-resource-field::
              :name: lines
              :type: list[list]

              The list of rendered lines for a side-by-side diff. Each
              entry in the list is itself a list with 8 items:

              1. Row number of the line in the combined side-by-side diff.
              2. The line number of the line in the left-hand file, as an
                 integer (for ``replace``, ``delete``, and ``equal``
                 chunks) or an empty string (for ``insert``).
              3. The text for the line in the left-hand file.
              4. The indexes within the text for the left-hand file that
                 have been replaced by text in the right-hand side. Each
                 index is a list of ``start, end`` positions, 0-based.
                 This is only available for ``replace`` lines. Otherwise
                 the list is empty.
              5. The line number of the line in the right-hand file, as an
                 integer (for ``replace``, ``insert`` and ``equal`` chunks)
                 or an empty string (for ``delete``).
              6. The text for the line in the right-hand file.
              7. The indexes within the text for the right-hand file that
                 are replacements for text in the left-hand file. Each
                 index is a list of ``start, end`` positions, 0-based.
                 This is only available for ``replace`` lines. Otherwise
                 the list is empty.
              8. A boolean that indicates if the line contains only
                 whitespace changes.

           .. webapi-resource-field::
              :name: meta
              :type: dict

              Additional information about the chunk. See below for more
              information.

           .. webapi-resource-field::
              :name: numlines
              :type: int

              The number of lines in the chunk.

        A chunk's meta information contains:

        .. webapi-resource-field-list::

           .. webapi-resource-field::
              :name: headers
              :type: list[[unicode, unicode]]

              Class definitions, function definitions, or other useful
              headers that should be displayed before this chunk. This helps
              users to identify where in a file they are and what the current
              chunk may be a part of.

           .. webapi-resource-field::
              :name: whitespace_chunk
              :type: bool

              Whether or not the entire chunk consists only of whitespace
              changes.

           .. webapi-resource-field::
              :name: whitespace_lines
              :type: list[[int, int]]

              A list of ``(start, end)`` row indexes in the lins that contain
              whitespace-only changes. These are 1-based.

        Other meta information may be available, but most is intended for
        internal use and shouldn't be relied upon.
        """
        mimetype = get_http_requested_mimetype(
            request, [mimetype['item'] for mimetype in self.allowed_mimetypes])

        if mimetype == 'text/x-patch':
            return self._get_patch(request, *args, **kwargs)
        elif mimetype.startswith(self.DIFF_DATA_MIMETYPE_BASE + "+"):
            return self._get_diff_data(request, mimetype, *args, **kwargs)
        else:
            return super(FileDiffResource, self).get(request, *args, **kwargs)