Auto merge of #16126 - ferjm:issue-14520-block-media-csv, r=nox

Block scripts with text/csv, audio/*, video/* and image/* mime types

This patch implements step 12 of the Main Fetch section of the Fetch API standard. It blocks the load of scripts with `text/csv`, `audio/*`, `video/*` and `image/*` mime types.

Credit for the logic of `should_block_mime_type` function should go to the author of #14770.

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #14520
- [X] There are tests for these changes

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16126)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-04-05 02:34:27 -05:00 committed by GitHub
commit 1071c3339f
4 changed files with 83 additions and 1 deletions

View file

@ -244,6 +244,8 @@ pub fn main_fetch(request: &mut Request,
let response_is_network_error = response.is_network_error(); let response_is_network_error = response.is_network_error();
let should_replace_with_nosniff_error = let should_replace_with_nosniff_error =
!response_is_network_error && should_be_blocked_due_to_nosniff(request.type_, &response.headers); !response_is_network_error && should_be_blocked_due_to_nosniff(request.type_, &response.headers);
let should_replace_with_mime_type_error =
!response_is_network_error && should_be_blocked_due_to_mime_type(request.type_, &response.headers);
// Step 15. // Step 15.
let mut network_error_response = response.get_network_error().cloned().map(Response::network_error); let mut network_error_response = response.get_network_error().cloned().map(Response::network_error);
@ -261,13 +263,16 @@ pub fn main_fetch(request: &mut Request,
// Step 17. // Step 17.
// TODO: handle blocking as mixed content. // TODO: handle blocking as mixed content.
// TODO: handle blocking by content security policy. // TODO: handle blocking by content security policy.
// TODO: handle blocking due to MIME type.
let blocked_error_response; let blocked_error_response;
let internal_response = let internal_response =
if should_replace_with_nosniff_error { if should_replace_with_nosniff_error {
// Defer rebinding result // Defer rebinding result
blocked_error_response = Response::network_error(NetworkError::Internal("Blocked by nosniff".into())); blocked_error_response = Response::network_error(NetworkError::Internal("Blocked by nosniff".into()));
&blocked_error_response &blocked_error_response
} else if should_replace_with_mime_type_error {
// Defer rebinding result
blocked_error_response = Response::network_error(NetworkError::Internal("Blocked by mime type".into()));
&blocked_error_response
} else { } else {
internal_response internal_response
}; };
@ -598,6 +603,21 @@ pub fn should_be_blocked_due_to_nosniff(request_type: Type, response_headers: &H
}; };
} }
/// https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type?
fn should_be_blocked_due_to_mime_type(request_type: Type, response_headers: &Headers) -> bool {
let mime_type = match response_headers.get::<ContentType>() {
Some(header) => header,
None => return false,
};
request_type == Type::Script && match *mime_type {
ContentType(Mime(TopLevel::Audio, _, _)) |
ContentType(Mime(TopLevel::Video, _, _)) |
ContentType(Mime(TopLevel::Image, _, _)) => true,
ContentType(Mime(TopLevel::Text, SubLevel::Ext(ref ext), _)) => ext == "csv",
_ => false,
}
}
/// https://fetch.spec.whatwg.org/#block-bad-port /// https://fetch.spec.whatwg.org/#block-bad-port
pub fn should_be_blocked_due_to_bad_port(url: &ServoUrl) -> bool { pub fn should_be_blocked_due_to_bad_port(url: &ServoUrl) -> bool {
// Step 1 is not applicable, this function just takes the URL directly. // Step 1 is not applicable, this function just takes the URL directly.

View file

@ -43604,6 +43604,11 @@
{} {}
] ]
], ],
"fetch/api/resources/script-with-header.py": [
[
{}
]
],
"fetch/api/resources/status.py": [ "fetch/api/resources/status.py": [
[ [
{} {}
@ -87238,6 +87243,12 @@
{} {}
] ]
], ],
"fetch/api/basic/block-mime-as-script.html": [
[
"/fetch/api/basic/block-mime-as-script.html",
{}
]
],
"fetch/api/basic/conditional-get.html": [ "fetch/api/basic/conditional-get.html": [
[ [
"/fetch/api/basic/conditional-get.html", "/fetch/api/basic/conditional-get.html",
@ -163675,6 +163686,10 @@
"f6d0b4fe4850c1dda40fab0f83ca04cba49e2e84", "f6d0b4fe4850c1dda40fab0f83ca04cba49e2e84",
"support" "support"
], ],
"fetch/api/basic/block-mime-as-script.html": [
"1dd503f1537b09f7aa875ea9a636d587b03601e3",
"testharness"
],
"fetch/api/basic/conditional-get.html": [ "fetch/api/basic/conditional-get.html": [
"77822a239b405b0b5c0259a335bac6cbe26b7fed", "77822a239b405b0b5c0259a335bac6cbe26b7fed",
"testharness" "testharness"
@ -164411,6 +164426,10 @@
"387c35bf1e576f00a10ce5abb4cc92e78da56845", "387c35bf1e576f00a10ce5abb4cc92e78da56845",
"support" "support"
], ],
"fetch/api/resources/script-with-header.py": [
"0c988e869e2e7af06bef67a2eba8211554b38323",
"support"
],
"fetch/api/resources/status.py": [ "fetch/api/resources/status.py": [
"d521bae08fa1ee19e7bbf4301157703e567ad5c6", "d521bae08fa1ee19e7bbf4301157703e567ad5c6",
"support" "support"

View file

@ -0,0 +1,39 @@
<!doctype html>
<meta charset="utf-8">
<title>Block mime type as script</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div></div>
<script>
var noop = function() {};
["text/csv",
"audio/aiff",
"audio/midi",
"audio/whatever",
"video/avi",
"video/fli",
"video/whatever",
"image/jpeg",
"image/gif",
"image/whatever"].forEach(function(test_case) {
async_test(function(t) {
var script = document.createElement("script");
script.onerror = t.step_func_done(noop);
script.onload = t.unreached_func("Unexpected load event");
script.src = "../resources/script-with-header.py?mime=" + test_case;
document.body.appendChild(script);
}, "Should fail loading script with " + test_case + " MIME type");
});
["html", "plain"].forEach(function(test_case) {
async_test(function(t) {
var script = document.createElement("script");
script.onerror = t.unreached_func("Unexpected error event");
script.onload = t.step_func_done(noop);
script.src = "../resources/script-with-header.py?mime=text/" + test_case;
document.body.appendChild(script);
}, "Should load script with text/" + test_case + " MIME type");
});
</script>

View file

@ -0,0 +1,4 @@
def main(request, response):
headers = [("Content-type", request.GET.first("mime"))]
content = "console.log('Script loaded')"
return 200, headers, content