From abf9e7e5a46e11569a6e03f989bec5f6300955db Mon Sep 17 00:00:00 2001 From: abhiabhi94 <13880786+abhiabhi94@users.noreply.github.com> Date: Sat, 2 Jul 2022 15:46:00 +0530 Subject: [PATCH] Change instances of parse_header to be compatible with parse_header_parameters - for djago versions greater than 4.1. Change made in https://github.com/django/django/commit/d4d5427571b4bf3a21c902276c2a00215c2a37cc. --- rest_framework/compat.py | 17 +++++++++++++++++ rest_framework/parsers.py | 5 +++-- rest_framework/renderers.py | 4 ++-- rest_framework/request.py | 4 ++-- rest_framework/utils/mediatypes.py | 5 ++--- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 4bae7729f..93be706dc 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -2,6 +2,7 @@ The `compat` module provides support for backwards compatibility with older versions of Django/Python, and compatibility wrappers around optional packages. """ +import django from django.conf import settings from django.views.generic import View @@ -157,3 +158,19 @@ else: SHORT_SEPARATORS = (',', ':') LONG_SEPARATORS = (', ', ': ') INDENT_SEPARATORS = (',', ': ') + + +if django.VERSION > (4, 1): + from django.utils.http import parse_header_parameters + + def parse_header_params(params, encoding='utf-8'): + key, pdict = parse_header_parameters(params) + # parse_header_params expects values in the bytes format and + # returns string values. + pdict = {k:v.encode(encoding) for k, v in pdict.items()} + return key, pdict +else: + from django.http.multipartparser import parse_header + + def parse_header_params(params, encoding='utf-8'): + return parse_header(params.encode(encoding)) diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index fc4eb1428..3cfe63208 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -13,13 +13,14 @@ from django.http import QueryDict from django.http.multipartparser import ChunkIter from django.http.multipartparser import \ MultiPartParser as DjangoMultiPartParser -from django.http.multipartparser import MultiPartParserError, parse_header +from django.http.multipartparser import MultiPartParserError from django.utils.encoding import force_str from rest_framework import renderers from rest_framework.exceptions import ParseError from rest_framework.settings import api_settings from rest_framework.utils import json +from rest_framework.compat import parse_header_params class DataAndFiles: @@ -201,7 +202,7 @@ class FileUploadParser(BaseParser): try: meta = parser_context['request'].META - disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION'].encode()) + disposition = parse_header_params(meta['HTTP_CONTENT_DISPOSITION']) filename_parm = disposition[1] if 'filename*' in filename_parm: return self.get_encoded_filename(filename_parm) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 8824fa660..4783a7dab 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -14,7 +14,6 @@ from django import forms from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.paginator import Page -from django.http.multipartparser import parse_header from django.template import engines, loader from django.urls import NoReverseMatch from django.utils.html import mark_safe @@ -30,6 +29,7 @@ from rest_framework.settings import api_settings from rest_framework.utils import encoders, json from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.utils.field_mapping import ClassLookupDict +from rest_framework.compat import parse_header_params def zero_as_none(value): @@ -72,7 +72,7 @@ class JSONRenderer(BaseRenderer): # If the media type looks like 'application/json; indent=4', # then pretty print the result. # Note that we coerce `indent=0` into `indent=None`. - base_media_type, params = parse_header(accepted_media_type.encode('ascii')) + base_media_type, params = parse_header_params(accepted_media_type, encoding='ascii') try: return zero_as_none(max(min(int(params['indent']), 8), 0)) except (KeyError, ValueError, TypeError): diff --git a/rest_framework/request.py b/rest_framework/request.py index 17ceadb08..df7315df1 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -14,19 +14,19 @@ from contextlib import contextmanager from django.conf import settings from django.http import HttpRequest, QueryDict -from django.http.multipartparser import parse_header from django.http.request import RawPostDataException from django.utils.datastructures import MultiValueDict from rest_framework import HTTP_HEADER_ENCODING, exceptions from rest_framework.settings import api_settings +from rest_framework.compat import parse_header_params def is_form_media_type(media_type): """ Return True if the media type is a valid form media type. """ - base_media_type, params = parse_header(media_type.encode(HTTP_HEADER_ENCODING)) + base_media_type, params = parse_header_params(media_type, encoding=HTTP_HEADER_ENCODING) return (base_media_type == 'application/x-www-form-urlencoded' or base_media_type == 'multipart/form-data') diff --git a/rest_framework/utils/mediatypes.py b/rest_framework/utils/mediatypes.py index 40bdf2615..687aadc73 100644 --- a/rest_framework/utils/mediatypes.py +++ b/rest_framework/utils/mediatypes.py @@ -3,9 +3,8 @@ Handling of media types, as found in HTTP Content-Type and Accept headers. See https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 """ -from django.http.multipartparser import parse_header - from rest_framework import HTTP_HEADER_ENCODING +from rest_framework.compat import parse_header_params def media_type_matches(lhs, rhs): @@ -46,7 +45,7 @@ def order_by_precedence(media_type_lst): class _MediaType: def __init__(self, media_type_str): self.orig = '' if (media_type_str is None) else media_type_str - self.full_type, self.params = parse_header(self.orig.encode(HTTP_HEADER_ENCODING)) + self.full_type, self.params = parse_header_params(self.orig, encoding=HTTP_HEADER_ENCODING) self.main_type, sep, self.sub_type = self.full_type.partition('/') def match(self, other):