Commit d3562176 authored by Kenichi Ishibashi's avatar Kenichi Ishibashi Committed by Commit Bot

Set WasFetchedViaServiceWorker for multipart image response

When creating a ResourceResponse from another ResourceResponse,
we need to copy WasFetchedViaServiceWorker and
ResponseTypeViaServiceWorker.

Bug: 737648
Change-Id: I9405738221ef5232e235f9fc400f204b7b558596
Reviewed-on: https://chromium-review.googlesource.com/907012
Commit-Queue: Kenichi Ishibashi <bashi@chromium.org>
Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537579}
parent 4cf1e6a8
<!DOCTYPE html>
<title>Tests for cross-origin multipart image returned by service worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script>
// This tests loading a multipart image via service worker. The service worker responds with
// an opaque or a non-opaque response. The content of opaque response should not be readable.
const script = 'resources/multipart-image-worker.js';
const scope = 'resources/multipart-image-iframe.html';
let frame;
function check_image_data(data) {
assert_equals(data[0], 255);
assert_equals(data[1], 0);
assert_equals(data[2], 0);
assert_equals(data[3], 255);
}
promise_test(t => {
return service_worker_unregister_and_register(t, script, scope)
.then(registration => {
promise_test(() => {
if (frame) {
frame.remove();
}
return registration.unregister();
}, 'restore global state');
return wait_for_state(t, registration.installing, 'activated');
})
.then(() => with_iframe(scope))
.then(f => {
frame = f;
});
}, 'initialize global state');
promise_test(t => {
return frame.contentWindow.load_multipart_image('same-origin-multipart-image')
.then(img => frame.contentWindow.get_image_data(img))
.then(img_data => {
check_image_data(img_data.data);
});
}, 'same-origin multipart image via SW should be readable');
promise_test(t => {
return frame.contentWindow.load_multipart_image('cross-origin-multipart-image-with-cors-approved')
.then(img => frame.contentWindow.get_image_data(img))
.then(img_data => {
check_image_data(img_data.data);
});
}, 'cross-origin multipart image via SW with approved CORS should be readable');
promise_test(t => {
return frame.contentWindow.load_multipart_image('cross-origin-multipart-image-with-no-cors')
.then(img => {
assert_throws('SecurityError', () => frame.contentWindow.get_image_data(img));
});
}, 'cross-origin multipart image with no-cors via SW should not be readable');
promise_test(t => {
const promise = frame.contentWindow.load_multipart_image('cross-origin-multipart-image-with-cors-rejected');
return promise_rejects(t, new DOMException('load failed', 'NetworkError'), promise);
}, 'cross-origin multipart image via SW with rejected CORS should fail to load');
</script>
<script>
function load_multipart_image(src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img');
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', (e) => reject(new DOMException('load failed', 'NetworkError')));
img.src = src;
});
}
function get_image_data(img) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
// When |img.src| is cross origin, this should throw a SecurityError.
const imageData = context.getImageData(0, 0, 1, 1);
return imageData;
}
</script>
importScripts('/common/get-host-info.sub.js');
importScripts('test-helpers.sub.js');
const host_info = get_host_info();
const multipart_image_path = base_path() + 'multipart-image.py';
const sameorigin_url = host_info['HTTPS_ORIGIN'] + multipart_image_path;
const cross_origin_url = host_info['HTTPS_REMOTE_ORIGIN'] + multipart_image_path;
self.addEventListener('fetch', event => {
const url = event.request.url;
if (url.indexOf('cross-origin-multipart-image-with-no-cors') >= 0) {
event.respondWith(fetch(cross_origin_url, {mode: 'no-cors'}));
} else if (url.indexOf('cross-origin-multipart-image-with-cors-rejected') >= 0) {
event.respondWith(fetch(cross_origin_url, {mode: 'cors'}));
} else if (url.indexOf('cross-origin-multipart-image-with-cors-approved') >= 0) {
event.respondWith(fetch(cross_origin_url + '?approvecors', {mode: 'cors'}));
} else if (url.indexOf('same-origin-multipart-image') >= 0) {
event.respondWith(fetch(sameorigin_url));
}
});
# A request handler that serves a multipart image.
import os
BOUNDARY = 'cutHere'
def create_part(path):
with open(path, 'rb') as f:
return 'Content-Type: image/png\r\n\r\n' + f.read() + '--%s' % BOUNDARY
def main(request, response):
content_type = 'multipart/x-mixed-replace; boundary=%s' % BOUNDARY
headers = [('Content-Type', content_type)]
if 'approvecors' in request.GET:
headers.append(('Access-Control-Allow-Origin', '*'))
image_path = os.path.join(request.doc_root, 'images')
body = create_part(os.path.join(image_path, 'green-1x1.png'))
body = body + create_part(os.path.join(image_path, 'red-16x16.png'))
return headers, body
......@@ -616,6 +616,13 @@ void ImageResource::OnePartInMultipartReceived(
const ResourceResponse& response) {
DCHECK(multipart_parser_);
if (!GetResponse().IsNull()) {
CHECK_EQ(GetResponse().WasFetchedViaServiceWorker(),
response.WasFetchedViaServiceWorker());
CHECK_EQ(GetResponse().ResponseTypeViaServiceWorker(),
response.ResponseTypeViaServiceWorker());
}
SetResponse(response);
if (multipart_parsing_state_ == MultipartParsingState::kWaitingForFirstPart) {
// We have nothing to do because we don't have any data.
......
......@@ -141,6 +141,10 @@ bool MultipartImageResourceParser::ParseHeaders() {
// replacement headers. We only replace the same few headers that gecko does.
// See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
ResourceResponse response(original_response_.Url());
response.SetWasFetchedViaServiceWorker(
original_response_.WasFetchedViaServiceWorker());
response.SetResponseTypeViaServiceWorker(
original_response_.ResponseTypeViaServiceWorker());
for (const auto& header : original_response_.HttpHeaderFields())
response.AddHTTPHeaderField(header.key, header.value);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment