mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
mod_negotiation: Do not send the qs parameter in the Content-Type.
A MultiViews response took the media type of the selected file as it was, so the qs source quality set with AddType was sent to the client. Drop it after the variant has been selected. Other parameters are kept. PR: 53595 GitHub: closes #824 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939268 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
2
changes-entries/negotiation-qs-content-type.txt
Normal file
2
changes-entries/negotiation-qs-content-type.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
*) mod_negotiation: Do not send the "qs" source quality parameter of the selected
|
||||
variant in the Content-Type of a response negotiated by MultiViews. PR 53595
|
||||
@@ -3068,6 +3068,41 @@ static int handle_map_file(request_rec *r)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* The "qs" parameter of a variant's media type is only its source quality
|
||||
* for the selection, see get_entry(), and does not belong in the
|
||||
* Content-Type of the response. Return content_type without it, all
|
||||
* other parameters are kept as they are.
|
||||
*/
|
||||
static const char *strip_source_quality(apr_pool_t *p,
|
||||
const char *content_type)
|
||||
{
|
||||
const char *line = content_type;
|
||||
char *stripped;
|
||||
int found = 0;
|
||||
|
||||
if (!ap_strcasestr(content_type, "qs")) {
|
||||
return content_type;
|
||||
}
|
||||
|
||||
stripped = ap_get_token(p, &line, 0);
|
||||
while (*line == ';') {
|
||||
const char *param = line++;
|
||||
const char *name = ap_get_token(p, &line, 1);
|
||||
apr_size_t len = strcspn(name, "= \t");
|
||||
|
||||
if (len == 2 && name[len] && !ap_cstr_casecmpn(name, "qs", 2)) {
|
||||
found = 1;
|
||||
}
|
||||
else {
|
||||
stripped = apr_pstrcat(p, stripped,
|
||||
apr_pstrmemdup(p, param, line - param),
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return found ? apr_pstrcat(p, stripped, line, NULL) : content_type;
|
||||
}
|
||||
|
||||
static int handle_multi(request_rec *r)
|
||||
{
|
||||
negotiation_state *neg;
|
||||
@@ -3124,6 +3159,14 @@ static int handle_multi(request_rec *r)
|
||||
/* now do a "fast redirect" ... promotes the sub_req into the main req */
|
||||
ap_internal_fast_redirect(sub_req, r);
|
||||
|
||||
if (r->content_type) {
|
||||
const char *type = strip_source_quality(r->pool, r->content_type);
|
||||
|
||||
if (type != r->content_type) {
|
||||
ap_set_content_type_ex(r, type, AP_REQUEST_IS_TRUSTED_CT(r));
|
||||
}
|
||||
}
|
||||
|
||||
/* give no advise for time on this subrequest. Perhaps we
|
||||
* should tally the last mtime among all variants, and date
|
||||
* the most recent, but that could confuse the proxies.
|
||||
|
||||
@@ -135,6 +135,15 @@
|
||||
LanguagePriority zh-TW fr fu en de
|
||||
</Directory>
|
||||
|
||||
<Directory @SERVERROOT@/htdocs/modules/negotiation/qs>
|
||||
Options +MultiViews
|
||||
AddType text/html;qs=0.9 .html
|
||||
AddType application/xhtml+xml;qs=1.0 .xhtml
|
||||
AddType "text/html;charset=utf-8;qs=0.8" .qsafter
|
||||
AddType "text/html;QS=0.8;charset=utf-8" .qsbefore
|
||||
AddType "application/example;foo=\"a;b\";q=0.7;qs=0.5;bar=\"c, d\"" .quoted
|
||||
</Directory>
|
||||
|
||||
<IfDefine APACHE2>
|
||||
<IfModule @CGI_MODULE@>
|
||||
<Directory @SERVERROOT@/htdocs/modules/negotiation/query>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
after
|
||||
@@ -0,0 +1 @@
|
||||
before
|
||||
@@ -0,0 +1 @@
|
||||
html
|
||||
@@ -0,0 +1 @@
|
||||
xhtml
|
||||
@@ -0,0 +1 @@
|
||||
quoted
|
||||
@@ -0,0 +1 @@
|
||||
html
|
||||
@@ -0,0 +1 @@
|
||||
xht
|
||||
@@ -0,0 +1,5 @@
|
||||
URI: tm1.htm
|
||||
Content-Type: text/html; qs=0.9
|
||||
|
||||
URI: tm2.xht
|
||||
Content-Type: application/xhtml+xml; qs=1.0
|
||||
@@ -3,12 +3,15 @@
|
||||
Covers default-language selection, explicit variant requests, Accept-Language
|
||||
obedience (plain + compressed + typemap), quality-rating preferences, a
|
||||
non-existent highest-quality fallback, a typemap query-string case, and
|
||||
Accept content-type negotiation (with 406 cases).
|
||||
Accept content-type negotiation (with 406 cases), and the source quality
|
||||
("qs") of a variant not showing up in the Content-Type of the response.
|
||||
|
||||
Perl original used ``need_module('negotiation') && need_cgi &&
|
||||
need_module('mime')``.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from apache_pytest import need_cgi, need_module, t_cmp
|
||||
@@ -153,3 +156,39 @@ def test_content_type(http, accept, expected):
|
||||
else:
|
||||
assert t_cmp(r.status_code, 406), \
|
||||
f"expect Not Acceptable for Accept: {accept}"
|
||||
|
||||
|
||||
XML = "application/xhtml+xml"
|
||||
|
||||
# "qs" only decides between variants, the other parameters are kept
|
||||
QS_PARAMS = [
|
||||
("after", "text/html;charset=utf-8"),
|
||||
("before", "text/html;charset=utf-8"),
|
||||
("quoted", 'application/example;foo="a;b";q=0.7;bar="c, d"'),
|
||||
]
|
||||
|
||||
|
||||
def _content_type(resp):
|
||||
assert resp.status_code == 200
|
||||
return re.sub(r";\s+", ";", resp.headers["content-type"])
|
||||
|
||||
|
||||
@need_module("negotiation", "mime")
|
||||
@pytest.mark.parametrize("path", ["doc", "typemap.var"])
|
||||
@pytest.mark.parametrize("accept,expected", [
|
||||
(f"text/html, {XML}", XML),
|
||||
("text/html", "text/html"),
|
||||
(f"text/html, {XML};q=0.5", "text/html"),
|
||||
])
|
||||
def test_source_quality(http, path, accept, expected):
|
||||
r = http.GET(f"/modules/negotiation/qs/{path}", headers={"Accept": accept})
|
||||
assert t_cmp(_content_type(r), expected), \
|
||||
"qs selects the variant but is not sent in Content-Type"
|
||||
|
||||
|
||||
@need_module("negotiation", "mime")
|
||||
@pytest.mark.parametrize("name,expected", QS_PARAMS, ids=[n for n, _ in QS_PARAMS])
|
||||
def test_source_quality_parameters(http, name, expected):
|
||||
r = http.GET(f"/modules/negotiation/qs/{name}", headers={"Accept": "*/*"})
|
||||
assert t_cmp(_content_type(r), expected), \
|
||||
"only qs is removed from the Content-Type"
|
||||
|
||||
Reference in New Issue
Block a user