diff options
7 files changed, 142 insertions, 13 deletions
diff --git a/media/blink/buffered_data_source.cc b/media/blink/buffered_data_source.cc index eb4c984..0fc1617 100644 --- a/media/blink/buffered_data_source.cc +++ b/media/blink/buffered_data_source.cc @@ -431,9 +431,10 @@ bool BufferedDataSource::CheckPartialResponseURL( // generated bytes and the target response. See http://crbug.com/489060#c32 // for details. // If the origin of the new response is different from the first response we - // deny the redirected response. - return response_original_url_.GetOrigin() == - partial_response_original_url.GetOrigin(); + // deny the redirected response unless the crossorigin attribute has been set. + return (response_original_url_.GetOrigin() == + partial_response_original_url.GetOrigin()) || + DidPassCORSAccessCheck(); } void BufferedDataSource::ReadCallback( diff --git a/media/blink/buffered_data_source_unittest.cc b/media/blink/buffered_data_source_unittest.cc index 878d5f7..aed8453 100644 --- a/media/blink/buffered_data_source_unittest.cc +++ b/media/blink/buffered_data_source_unittest.cc @@ -51,11 +51,12 @@ class MockBufferedDataSource : public BufferedDataSource { public: MockBufferedDataSource( const GURL& url, + BufferedResourceLoader::CORSMode cors_mode, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, WebLocalFrame* frame, BufferedDataSourceHost* host) : BufferedDataSource(url, - BufferedResourceLoader::kUnspecified, + cors_mode, task_runner, frame, new media::MediaLog(), @@ -128,13 +129,13 @@ class BufferedDataSourceTest : public testing::Test { MOCK_METHOD1(OnInitialize, void(bool)); - void Initialize(const char* url, bool expected) { + void InitializeWithCORS(const char* url, + bool expected, + BufferedResourceLoader::CORSMode cors_mode) { GURL gurl(url); - data_source_.reset( - new MockBufferedDataSource(gurl, - message_loop_.task_runner(), - view_->mainFrame()->toWebLocalFrame(), - &host_)); + data_source_.reset(new MockBufferedDataSource( + gurl, cors_mode, message_loop_.task_runner(), + view_->mainFrame()->toWebLocalFrame(), &host_)); data_source_->SetPreload(preload_); response_generator_.reset(new TestResponseGenerator(gurl, kFileSize)); @@ -148,6 +149,10 @@ class BufferedDataSourceTest : public testing::Test { EXPECT_EQ(data_source_->downloading(), is_http); } + void Initialize(const char* url, bool expected) { + InitializeWithCORS(url, expected, BufferedResourceLoader::kUnspecified); + } + // Helper to initialize tests with a valid 200 response. void InitializeWith200Response() { Initialize(kHttpUrl, true); @@ -577,6 +582,20 @@ TEST_F(BufferedDataSourceTest, ExecuteMixedResponseFailureTest(response1, response2); } +TEST_F(BufferedDataSourceTest, + Http_MixedResponse_ServiceWorkerProxiedAndDifferentOriginResponseCORS) { + InitializeWithCORS(kHttpUrl, true, BufferedResourceLoader::kAnonymous); + WebURLResponse response1 = + response_generator_->GeneratePartial206(0, kDataSize - 1); + response1.setWasFetchedViaServiceWorker(true); + response1.setOriginalURLViaServiceWorker(GURL(kHttpDifferentOriginUrl)); + WebURLResponse response2 = + response_generator_->GeneratePartial206(kDataSize, kDataSize * 2 - 1); + // The origin URL of response1 and response2 are different, but a CORS check + // has been passed for each request, so expect success. + ExecuteMixedResponseSuccessTest(response1, response2); +} + TEST_F(BufferedDataSourceTest, File_Retry) { InitializeWithFileResponse(); diff --git a/third_party/WebKit/LayoutTests/http/tests/media/mixed-range-response.html b/third_party/WebKit/LayoutTests/http/tests/media/mixed-range-response.html index e4fec36..f3a8c88 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/mixed-range-response.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/mixed-range-response.html @@ -16,9 +16,11 @@ // If the origin of 2. (mixed-range-response.php) and 6. (load-video.php) are // different, an error should occur. -function create_failure_audio_test(url) { +function create_failure_audio_test(url, crossOrigin) { return new Promise(function(resolve, reject) { var audio = document.createElement('audio'); + if (crossOrigin) + audio.crossOrigin = crossOrigin; audio.oncanplay = function() { reject('canplay event should not be fired. url: ' + url); }; @@ -28,9 +30,11 @@ function create_failure_audio_test(url) { }); } -function create_success_audio_test(url) { +function create_success_audio_test(url, crossOrigin) { return new Promise(function(resolve, reject) { var audio = document.createElement('audio'); + if (crossOrigin) + audio.crossOrigin = crossOrigin; audio.oncanplay = resolve; audio.onerror = function(e) { reject('error event should not be fired. url: ' + url); @@ -42,10 +46,75 @@ function create_success_audio_test(url) { var HOST_INFO = get_host_info(); var MIX_RESPONSE_PHP_PATH = '/media/resources/mixed-range-response.php'; +var REDIRECT_PHP_PATH = '/resources/redirect.php' var AUDIO_PATH = '/media/resources/load-video.php?' + 'name=../../../../media/content/silence.oga&type=audio/ogg'; promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_ORIGIN'] + AUDIO_PATH)); + }, 'Redirect from same-origin to same-origin must succeed.'); + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH)); + }, 'Redirect from same-origin to remote-origin must succeed.'); + +promise_test(function(t) { + return create_failure_audio_test( + HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH , + 'anonymous'); + }, 'CORS-disallowed remote-origin with crossOrigin=anonymous must fail.'); + + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN'], + 'anonymous'); + }, 'CORS-allowed remote-origin with crossOrigin=anonymous must succeed.'); + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_ORIGIN'] + AUDIO_PATH), + 'anonymous'); + }, 'Redirect from same-origin to same-origin with crossOrigin=anonymous must succeed.'); + +promise_test(function(t) { + return create_failure_audio_test( + HOST_INFO['HTTP_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH), + 'anonymous'); + }, 'Redirect from same-origin to CORS-disallowed remote-origin with crossOrigin=anonymous must fail.'); + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN']), + 'anonymous'); + }, 'Redirect from same-origin to CORS-allowed remote-origin with crossOrigin=anonymous must succeed.'); + +promise_test(function(t) { + return create_failure_audio_test( + HOST_INFO['HTTP_REMOTE_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN']), + 'anonymous'); + }, 'Redirect from CORS-disallowed remote-origin to CORS-allowed remote-origin with crossOrigin=anonymous must fail.'); + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_REMOTE_ORIGIN'] + REDIRECT_PHP_PATH + '?url=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN']) + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN'], + 'anonymous'); + }, 'Redirect from CORS-allowed remote-origin to CORS-allowed remote-origin with crossOrigin=anonymous must succeed.'); + +promise_test(function(t) { return create_success_audio_test( HOST_INFO['HTTP_ORIGIN'] + MIX_RESPONSE_PHP_PATH + '?location=' + encodeURIComponent(HOST_INFO['HTTP_ORIGIN'] + AUDIO_PATH)); @@ -69,5 +138,29 @@ promise_test(function(t) { encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH)); }, 'Mixing same remote-origin responses must succeed.'); +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_REMOTE_ORIGIN'] + MIX_RESPONSE_PHP_PATH + '?location=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN']) + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN'], + 'anonymous'); + }, 'Mixing same CORS-allowed remote-origin responses with crossOrigin=anonymous must succeed.'); + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_ORIGIN'] + MIX_RESPONSE_PHP_PATH + '?location=' + + encodeURIComponent(HOST_INFO['HTTP_REMOTE_ORIGIN'] + AUDIO_PATH + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN']), + 'anonymous'); + }, 'Mixing same-origin response and CORS-allowed remote-origin response with crossOrigin=anonymous must succeed.'); + +promise_test(function(t) { + return create_success_audio_test( + HOST_INFO['HTTP_REMOTE_ORIGIN'] + MIX_RESPONSE_PHP_PATH + '?location=' + + encodeURIComponent(HOST_INFO['HTTP_ORIGIN'] + AUDIO_PATH + '&cors_allow_origin=*') + + '&cors_allow_origin=' + HOST_INFO['HTTP_ORIGIN'], + 'anonymous'); + }, 'Mixing CORS-allowed remote-origin response and same-origin response with crossOrigin=anonymous must succeed.'); </script> </body> diff --git a/third_party/WebKit/LayoutTests/http/tests/media/resources/load-video.php b/third_party/WebKit/LayoutTests/http/tests/media/resources/load-video.php index 8f0e8eb..8e0bbb9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/resources/load-video.php +++ b/third_party/WebKit/LayoutTests/http/tests/media/resources/load-video.php @@ -3,11 +3,13 @@ $fileName = $_GET["name"]; $type = $_GET["type"]; $norange = $_GET["norange"]; + $cors_allow_origin = $_GET["cors_allow_origin"]; $_GET = array(); $_GET['name'] = $fileName; $_GET['type'] = $type; $_GET['norange'] = $norange; + $_GET['cors_allow_origin'] = $cors_allow_origin; @include("./serve-video.php"); ?> diff --git a/third_party/WebKit/LayoutTests/http/tests/media/resources/mixed-range-response.php b/third_party/WebKit/LayoutTests/http/tests/media/resources/mixed-range-response.php index 6d6dbd9..a6581d7 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/resources/mixed-range-response.php +++ b/third_party/WebKit/LayoutTests/http/tests/media/resources/mixed-range-response.php @@ -1,6 +1,9 @@ <?php if (isset($_SERVER['HTTP_RANGE']) && ($_SERVER['HTTP_RANGE'] == 'bytes=0-')) { header('HTTP/1.0 206 Partial Content'); + if (isset($_GET['cors_allow_origin'])) { + header("Access-Control-Allow-Origin: " . $_GET['cors_allow_origin']); + } header('Content-Type: audio/ogg'); # 12983 is the file size of media/content/silence.oga. header('Content-Range: bytes 0-2/12983'); @@ -9,4 +12,7 @@ if (isset($_SERVER['HTTP_RANGE']) && ($_SERVER['HTTP_RANGE'] == 'bytes=0-')) { } header('HTTP/1.1 307 Temporary Redirect'); header('Location: ' . $_GET["location"]); +if (isset($_GET['cors_allow_origin'])) { + header("Access-Control-Allow-Origin: " . $_GET['cors_allow_origin']); +} ?> diff --git a/third_party/WebKit/LayoutTests/http/tests/media/resources/serve-video.php b/third_party/WebKit/LayoutTests/http/tests/media/resources/serve-video.php index 9bfcf02..a13edf0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/resources/serve-video.php +++ b/third_party/WebKit/LayoutTests/http/tests/media/resources/serve-video.php @@ -27,6 +27,9 @@ header("Accept-Ranges: bytes"); header("Content-Range: bytes " . $start . "-" . $end . "/" . $fileSize); } + if (isset($_GET['cors_allow_origin'])) { + header("Access-Control-Allow-Origin: " . $_GET['cors_allow_origin']); + } header("Connection: close"); $chunkSize = 1024 * 256; diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp index adb2523..c1276fe 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp @@ -160,8 +160,13 @@ DocumentThreadableLoader::DocumentThreadableLoader(Document& document, Threadabl // create a new one, and copy these headers. const HTTPHeaderMap& headerMap = request.httpHeaderFields(); for (const auto& header : headerMap) { - if (FetchUtils::isSimpleHeader(header.key, header.value)) + if (FetchUtils::isSimpleHeader(header.key, header.value)) { m_simpleRequestHeaders.add(header.key, header.value); + } else if (equalIgnoringCase(header.key, "range") && m_options.crossOriginRequestPolicy == UseAccessControl && m_options.preflightPolicy == PreventPreflight) { + // Allow an exception for the "range" header for when CORS callers request no preflight, this ensures cross-origin + // redirects work correctly for crossOrigin enabled WebURLRequest::RequestContextVideo type requests. + m_simpleRequestHeaders.add(header.key, header.value); + } } // DocumentThreadableLoader is used by all javascript initiated fetch, so |