#36447: HttpRequest.get_preferred_type misorders types when more specific accepted types have lower q -------------------------------------+------------------------------------- Reporter: Anders Kaseorg | Owner: Jake | Howard Type: Bug | Status: assigned Component: HTTP handling | Version: 5.2 Severity: Release blocker | Resolution: Keywords: preferred media | Triage Stage: Accepted type | Has patch: 1 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Description changed by Anders Kaseorg:
Old description: > Consider this example from [https://www.rfc- > editor.org/rfc/rfc9110.html#section-12.5.1-18 RFC 9110 §12.5.1]: > > The media type quality factor associated with a given type is > determined by finding the media range with the highest precedence that > matches the type. For example, > {{{ > Accept: text/*;q=0.3, text/plain;q=0.7, text/plain;format=flowed, > text/plain;format=fixed;q=0.4, */*;q=0.5 > }}} > would cause the following values to be associated: > ||= Media Type =||= Quality Value =|| > || text/plain;format=flowed || 1 || > || text/plain || 0.7 || > || text/html || 0.3 || > || image/jpeg || 0.5 || > || text/plain;format=fixed || 0.4 || > || text/html;level=3 || 0.7 || > > Django’s `HttpRequest.get_preferred_type` fails to match this behavior. > > {{{ > >>> from django.conf import settings > >>> from django.http import HttpRequest > >>> settings.configure() > >>> request = HttpRequest() > >>> request.META["HTTP_ACCEPT"] = "text/*;q=0.3, text/plain;q=0.7, > text/plain;format=flowed, text/plain;format=fixed;q=0.4, */*;q=0.5" > >>> request.get_preferred_type(['text/plain', 'text/plain;format=fixed']) > # expected text/plain (0.7 > 0.4) > 'text/plain;format=fixed' > >>> request.get_preferred_type(['text/html', 'image/jpeg']) # expected > image/jpeg (0.3 < 0.5) > 'text/html' > >>> request.get_preferred_type(['text/html', 'text/html;level=3']) # > expected text/html;level=3 (0.3 < 0.7) > 'text/html' > >>> request.get_preferred_type(['image/jpeg', 'text/html']) # expected > image/jpeg (0.5 > 0.3) > 'text/html' > >>> request.get_preferred_type(['image/jpeg', 'text/plain;format=fixed']) > # expected image/jpeg (0.5 > 0.4) > 'text/plain;format=fixed' > >>> request.get_preferred_type(['text/plain;format=fixed', 'text/plain']) > # expected text/plain (0.4 < 0.7) > 'text/plain;format=fixed' > >>> request.get_preferred_type(['text/plain;format=fixed', 'image/jpeg']) > # expected image/jpeg (0.4 < 0.5) > 'text/plain;format=fixed' > >>> request.get_preferred_type(['text/plain;format=fixed', > 'text/html;level=3']) # expected text/html;level=3 (0.4 < 0.7) > 'text/plain;format=fixed' > >>> request.get_preferred_type(['text/html;level=3', > 'text/plain;format=fixed']) # expected text/html;level=3 (0.7 > 0.4) > 'text/plain;format=fixed' > }}} New description: Consider this example from [https://www.rfc- editor.org/rfc/rfc9110.html#section-12.5.1-18 RFC 9110 §12.5.1] (adjusted for [https://www.rfc-editor.org/errata/eid7138 erratum 7138]): The media type quality factor associated with a given type is determined by finding the media range with the highest precedence that matches the type. For example, {{{ Accept: text/*;q=0.3, text/plain;q=0.7, text/plain;format=flowed, text/plain;format=fixed;q=0.4, */*;q=0.5 }}} would cause the following values to be associated: ||= Media Type =||= Quality Value =|| || text/plain;format=flowed || 1 || || text/plain || 0.7 || || text/html || 0.3 || || image/jpeg || 0.5 || || text/plain;format=fixed || 0.4 || || text/html;level=3 || 0.3 || Django’s `HttpRequest.get_preferred_type` fails to match this behavior. {{{ >>> from django.conf import settings >>> from django.http import HttpRequest >>> settings.configure() >>> request = HttpRequest() >>> request.META["HTTP_ACCEPT"] = "text/*;q=0.3, text/plain;q=0.7, text/plain;format=flowed, text/plain;format=fixed;q=0.4, */*;q=0.5" >>> request.get_preferred_type(['text/plain', 'text/plain;format=fixed']) # expected text/plain (0.7 > 0.4) 'text/plain;format=fixed' >>> request.get_preferred_type(['text/html', 'image/jpeg']) # expected image/jpeg (0.3 < 0.5) 'text/html' >>> request.get_preferred_type(['image/jpeg', 'text/html']) # expected image/jpeg (0.5 > 0.3) 'text/html' >>> request.get_preferred_type(['image/jpeg', 'text/plain;format=fixed']) # expected image/jpeg (0.5 > 0.4) 'text/plain;format=fixed' >>> request.get_preferred_type(['image/jpeg', 'text/html;level=3']) # expected image/jpeg (0.5 > 0.3) 'text/html;level=3' >>> request.get_preferred_type(['text/plain;format=fixed', 'text/plain']) # expected text/plain (0.4 < 0.7) 'text/plain;format=fixed' >>> request.get_preferred_type(['text/plain;format=fixed', 'image/jpeg']) # expected image/jpeg (0.4 < 0.5) 'text/plain;format=fixed' >>> request.get_preferred_type(['text/html;level=3', 'image/jpeg']) # expected image/jpeg (0.3 < 0.5) 'text/html;level=3' }}} -- -- Ticket URL: <https://code.djangoproject.com/ticket/36447#comment:9> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/django-updates/01070197602a5ba9-2c2ba36a-69cf-4106-bb4c-e998f94a2e60-000000%40eu-central-1.amazonses.com.