def select_renderer(self, request, renderers, format_suffix=None): """ Given a request and a list of renderers, return a two-tuple of: (renderer, media type). """ accepts = self.get_accept_list(request) # Check the acceptable media types against each renderer, # attempting more specific media types first # NB. The inner loop here isn't as bad as it first looks :) # Worst case is we're looping over len(accept_list) * len(self.renderers) for media_type_set in order_by_precedence(accepts): for renderer in renderers: for media_type in media_type_set: if media_type_matches(renderer.media_type, media_type): # Return the most specific media type as accepted. media_type_wrapper = _MediaType(media_type) if (_MediaType(renderer.media_type).precedence > media_type_wrapper.precedence): # Eg client requests '*/*' # Accepted media type is 'application/json' full_media_type = ';'.join( (renderer.media_type, ) + tuple('{0}={1}'.format( key, value.decode(HTTP_HEADER_ENCODING)) for key, value in media_type_wrapper.params.items())) return renderer, full_media_type else: # Eg client requests 'application/json; indent=8' # Accepted media type is 'application/json; indent=8' return renderer, media_type raise exceptions.NotAcceptable(available_renderers=renderers)
def media_type_matches(first, other): """Return true if this MediaType satisfies the given MediaType.""" first = _MediaType(first) other = _MediaType(other) for key in first.params.keys(): if key != 'profile' and other.params.get(key, None) != first.params.get(key, None): return False # handle specific profile parameter try: if not profile_matches(first.params.get('profile', None), other.params.get('profile', None)): return False except ValueError: raise NotAcceptable("Invalid profile requested." ) if (first.sub_type != '*' and other.sub_type != '*' and other.sub_type != first.sub_type): return False if (first.main_type != '*' and other.main_type != '*' and other.main_type != first.main_type): return False return True
def select_renderer(self, request, renderers, format_suffix=None): """ Given a request and a list of renderers, return a two-tuple of: (renderer, media type). """ # Allow URL style format override. eg. "?format=json format_query_param = self.settings.URL_FORMAT_OVERRIDE format = format_suffix or request.QUERY_PARAMS.get(format_query_param) if format: renderers = self.filter_renderers(renderers, format) accepts = self.get_accept_list(request) # Check the acceptable media types against each renderer, # attempting more specific media types first # NB. The inner loop here isn't as bad as it first looks :) # Worst case is we're looping over len(accept_list) * len(self.renderers) for media_type_set in order_by_precedence(accepts): for renderer in renderers: for media_type in media_type_set: if media_type_matches(renderer.media_type, media_type): # Return the most specific media type as accepted. if (_MediaType(renderer.media_type).precedence > _MediaType(media_type).precedence): # Eg client requests '*/*' # Accepted media type is 'application/json' return renderer, renderer.media_type else: # Eg client requests 'application/json; indent=8' # Accepted media type is 'application/json; indent=8' return renderer, media_type raise exceptions.NotAcceptable(available_renderers=renderers)
def select_renderer(self, request, renderers, format_suffix=None): """ Given a request and a list of renderers, return a two-tuple of: (renderer, media type). """ # Allow URL style format override. eg. "?format=json format_query_param = self.settings.URL_FORMAT_OVERRIDE format = format_suffix or request.query_params.get(format_query_param) if format: renderers = self.filter_renderers(renderers, format) accepts = self.get_accept_list(request) # Check the acceptable media types against each renderer, # attempting more specific media types first # NB. The inner loop here isn't as bad as it first looks :) # Worst case is we're looping over len(accept_list) * len(self.renderers) for media_type_set in order_by_precedence(accepts): for renderer in renderers: for media_type in media_type_set: if media_type_matches(renderer.media_type, media_type): # Return the most specific media type as accepted. if _MediaType(renderer.media_type).precedence > _MediaType(media_type).precedence: # Eg client requests '*/*' # Accepted media type is 'application/json' return renderer, renderer.media_type else: # Eg client requests 'application/json; indent=8' # Accepted media type is 'application/json; indent=8' return renderer, media_type raise exceptions.NotAcceptable(available_renderers=renderers)
def determine_version(self, request, *args, **kwargs): """Use either Accept header or query parameter for versioning.""" # Patterned after rest_framework.versioning.AcceptHeaderVersioning media_type = _MediaType(request.accepted_media_type) header_version = media_type.params.get(self.header_version_param, None) if header_version is not None: header_version = unicode_http_header(header_version) # Patterned after rest_framework.versioning.QueryParameterVersioning query_version = request.query_params.get(self.query_version_param, None) if header_version is not None and query_version is not None and header_version != query_version: raise APIVersionMismatch() if header_version is not None and not self.is_allowed_version( header_version): # Behave like AcceptHeaderVersioning raise exceptions.NotAcceptable(self.invalid_version_in_header) if query_version is not None and not self.is_allowed_version( query_version): # Behave like QueryParameterVersioning raise exceptions.NotFound(self.invalid_version_in_query) version = header_version or query_version or self.default_version # self.default_version is always allowed, no need to re-check is_allowed_version here return version
def determine_version(self, request, *args, **kwargs): media_type = _MediaType(request.accepted_media_type) version = media_type.params.get(self.version_param, self.default_version) version = unicode_http_header(version) if not self.is_allowed_version(version): raise exceptions.NotAcceptable(self.invalid_version_message) return version
def determine_version(self, request, *args, **kwargs): media_type = _MediaType(request.META.get('HTTP_ACCEPT')) version = media_type.params.get(self.version_param, 0) version = unicode_http_header(version) if not version and request.path.startswith('/schema'): version = request.GET.get('version', self.allowed_versions[-1]) if version not in self.allowed_versions: raise exceptions.NotAcceptable({ 'detail': "Invalid version in 'Accept' header.", 'allowed_versions': [ int(v) for v in self.allowed_versions ], 'valid_content_types': [ media_type_format_json, media_type_format_xml, media_type_format_yaml, ], 'example_header': ( f'Accept: {media_type_format_json}; ' f'version={self.allowed_versions[-1]}' ) }) request.version = version return version
def modify_for_versioning(patterns, method, path, view, requested_version): assert view.versioning_class and view.request assert requested_version view.request.version = requested_version if issubclass(view.versioning_class, versioning.URLPathVersioning): version_param = view.versioning_class.version_param # substitute version variable to emulate request path = uritemplate.partial(path, var_dict={version_param: requested_version}) if isinstance(path, URITemplate): path = path.uri # emulate router behaviour by injecting substituted variable into view view.kwargs[version_param] = requested_version elif issubclass(view.versioning_class, versioning.NamespaceVersioning): try: view.request.resolver_match = get_resolver( urlconf=tuple(detype_pattern(p) for p in patterns) ).resolve(path) except Resolver404: error(f"namespace versioning path resolution failed for {path}. path will be ignored.") elif issubclass(view.versioning_class, versioning.AcceptHeaderVersioning): # Append the version into request accepted_media_type. # e.g "application/json; version=1.0" # To allow the AcceptHeaderVersioning negotiator going through. if not hasattr(view.request, 'accepted_renderer'): # Probably a mock request, content negotation was not performed, so, we do it now. negotiated = view.perform_content_negotiation(view.request) view.request.accepted_renderer, view.request.accepted_media_type = negotiated media_type = _MediaType(view.request.accepted_media_type) view.request.accepted_media_type = ( f'{media_type.full_type}; {view.versioning_class.version_param}={requested_version}' ) return path
def test_mediatype_string_representation(self): mediatype = _MediaType('test/*; foo=bar') params_str = '' for key, val in mediatype.params.items(): params_str += '; %s=%s' % (key, val) expected = 'test/*' + params_str assert str(mediatype) == expected
def determine_version(self, request, *args, **kwargs): media_type = _MediaType(request.accepted_media_type) version = media_type.params.get(self.version_param, None) if version is None: raise exceptions.NotAcceptable('A version is required.') return super(AcceptHeaderVersioningRequired, self).determine_version(request, *args, **kwargs)
def get_header_version(self, request): invalid_version_message = 'Invalid version in "Accept" header.' media_type = _MediaType(request.accepted_media_type) version = media_type.params.get(self.version_param) if not version: return None version = unicode_http_header(version) if not self.is_allowed_version(version): raise drf_exceptions.NotAcceptable(invalid_version_message) return version
def select_renderer(self, request, renderers, format_suffix=None): """ Given a request and a list of renderers, return a two-tuple of: (renderer, media type). """ # Allow URL style format override. eg. "?format=json format_query_param = self.settings.URL_FORMAT_OVERRIDE format = format_suffix or request.query_params.get(format_query_param) if format: renderers = self.filter_renderers(renderers, format) accepts = self.get_accept_list(request) # Check the acceptable media types against each renderer, # attempting more specific media types first # NB. The inner loop here isn't as bad as it first looks :) # Worst case is we're looping over len(accept_list) * len(self.renderers) for media_type_set in order_by_precedence(accepts): for renderer in renderers: for media_type in media_type_set: if media_type_matches(renderer.media_type, media_type): # Return the most specific media type as accepted. media_type_wrapper = _MediaType(media_type) if ( _MediaType(renderer.media_type).precedence > media_type_wrapper.precedence ): # Eg client requests '*/*' # Accepted media type is 'application/json' full_media_type = ';'.join( (renderer.media_type,) + tuple('{0}={1}'.format( key, value.decode(HTTP_HEADER_ENCODING)) for key, value in media_type_wrapper.params.items())) return renderer, full_media_type else: # Eg client requests 'application/json; indent=8' # Accepted media type is 'application/json; indent=8' return renderer, media_type return (renderers[0], renderers[0].media_type)
def test_mediatype_match_is_false_if_keys_not_match(self): mediatype = _MediaType(';test_param=foo') another_mediatype = _MediaType(';test_param=bar') assert mediatype.match(another_mediatype) is False
def test_mediatype_string_representation(self): mediatype = _MediaType('test/*; foo=bar') assert str(mediatype) == 'test/*; foo=bar'
def jsonapi_params(media_type_str: str) -> bool: media_type = _MediaType(media_type_str) # We don't use _MediaType.match() because we want an *exact* match, without matching */* return ( media_type.full_type == "application/vnd.api+json" and media_type.params )
def test_match_is_false_if_main_types_not_match(self): mediatype = _MediaType('test_1') anoter_mediatype = _MediaType('test_2') assert mediatype.match(anoter_mediatype) is False
def test_mediatype_precedence_with_wildcard_subtype(self): mediatype = _MediaType('test/*') assert mediatype.precedence == 1
def determine_version(request): media_type = _MediaType(request.META.get("HTTP_ACCEPT")) version = media_type.params.get("version") version = unicode_http_header(version) return version or None