#36411 closed Bug (fixed)
MediaType.get_preferred_type ignores params
| Reported by: | magicfelix | Owned by: | Jake Howard |
|---|---|---|---|
| Component: | HTTP handling | Version: | 5.2 |
| Severity: | Release blocker | Keywords: | |
| Cc: | Jake Howard, magicfelix | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I use the following code to get the preferred content type:
media_types = ["text/vcard; version=4.0", "text/vcard; version=3.0", "text/vcard", "text/directory"] print("Preferred type:", request.get_preferred_type(media_types))
A request using the following header …
Accept: text/vcard; version=3.0
… produces the following result
Preferred type: text/vcard; version=4.0
It should instead return text/vcard; version=3.0, as 4.0 was not included in the Accept header.
Change History (17)
comment:1 by , 6 months ago
comment:2 by , 6 months ago
There is also this old SO answer about Spring: https://stackoverflow.com/a/32073014
This apparently incorrect behaviour of Spring already has a Spring bug report, SPR-10903. The Spring developers closed it as "Works as Designed", noting:
I don't know any rule for comparing media types with their parameters effectively. It really depends on the media type...If you're actually trying to achieve REST versioning through media types, it seems that the most common solution is to use different media types, since their format obviously changed between versions:
comment:3 by , 6 months ago
| Cc: | added |
|---|
comment:4 by , 6 months ago
Looking at the Accept header in https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2, there are some examples including parameters:
Media ranges can be overridden by more specific media ranges or
specific media types. If more than one media range applies to a
given type, the most specific reference has precedence. For example,
Accept: text/*, text/plain, text/plain;format=flowed, */*
have the following precedence:
1. text/plain;format=flowed
2. text/plain
3. text/*
4. */*
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/html;q=0.7, text/html;level=1,
text/html;level=2;q=0.4, */*;q=0.5
would cause the following values to be associated:
+-------------------+---------------+
| Media Type | Quality Value |
+-------------------+---------------+
| text/html;level=1 | 1 |
| text/html | 0.7 |
| text/plain | 0.3 |
| image/jpeg | 0.5 |
| text/html;level=2 | 0.4 |
| text/html;level=3 | 0.7 |
+-------------------+---------------+
So I think we probably should take into account parameters but open to hearing other opinions
comment:5 by , 6 months ago
Nice find 👍 So it sounds like
- params to be included in matching, but also
- the precedence is determined by the specificity
? 🤔
comment:6 by , 6 months ago
I agree with Sarah that we should take into account the parameters (I'd not come across them before when I implemented this).
The q param specifically will still need some special handling when it comes to ordering, as I think all other parameters should be considered exact matches rather than trying to parse version numbers from them.
I believe the current implementation considers specificity in the ordering, but I may be wrong. Either way, we should make sure it's covered by tests!
comment:7 by , 6 months ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
| Triage Stage: | Unreviewed → Accepted |
comment:9 by , 5 months ago
| Severity: | Normal → Release blocker |
|---|
comment:10 by , 5 months ago
| Summary: | get_preferred_type ignores params → MediaType.get_preferred_type ignores params |
|---|
follow-up: 12 comment:11 by , 5 months ago
| Cc: | added |
|---|
Replying to magicfelix:
Hello! Could you please check if the proposed PR solves the issue for you?
comment:12 by , 5 months ago
Hello! Could you please check if the proposed PR solves the issue for you?
It does, thanks :)
comment:13 by , 5 months ago
| Patch needs improvement: | set |
|---|
comment:14 by , 5 months ago
| Patch needs improvement: | unset |
|---|
comment:15 by , 5 months ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Perhaps someone can weigh in on the correct behaviour on matching mime types, but
MediaType.match()only checks<main-type>/<sub-type>without consideration for the; <params>:def match(self, other): if self.is_all_types: return True other = MediaType(other) return self.main_type == other.main_type and self.sub_type in { "*", other.sub_type, }https://github.com/django/django/blob/d2732c30af28381f5a2ff1b08f754eeb7a6dfeca/django/http/request.py#L716-L719