Bug 1209081 - Part 1: Implement the "navigate" value for RequestMode; r=bkelly

This commit is contained in:
Ehsan Akhgari 2016-01-13 18:15:37 -05:00
parent 74567ab803
commit 98a69d988d
15 changed files with 44 additions and 15 deletions

View File

@ -60,6 +60,7 @@ MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/val
MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.")
MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.")
MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.")
MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.")
MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.")
MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.")

View File

@ -192,7 +192,8 @@ static_assert(int(HeadersGuardEnum::None) == 0 &&
static_assert(int(RequestMode::Same_origin) == 0 &&
int(RequestMode::No_cors) == 1 &&
int(RequestMode::Cors) == 2 &&
int(RequestMode::EndGuard_) == 3,
int(RequestMode::Navigate) == 3 &&
int(RequestMode::EndGuard_) == 4,
"RequestMode values are as expected");
static_assert(int(RequestCredentials::Omit) == 0 &&
int(RequestCredentials::Same_origin) == 1 &&

View File

@ -170,7 +170,8 @@ FetchDriver::HttpFetch()
nsSecurityFlags secFlags = nsILoadInfo::SEC_ABOUT_BLANK_INHERITS;
if (mRequest->Mode() == RequestMode::Cors) {
secFlags |= nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
} else if (mRequest->Mode() == RequestMode::Same_origin) {
} else if (mRequest->Mode() == RequestMode::Same_origin ||
mRequest->Mode() == RequestMode::Navigate) {
secFlags |= nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
} else if (mRequest->Mode() == RequestMode::No_cors) {
secFlags |= nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;

View File

@ -275,14 +275,13 @@ InternalRequest::MapChannelToRequestMode(nsIChannel* aChannel)
nsCOMPtr<nsILoadInfo> loadInfo;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aChannel->GetLoadInfo(getter_AddRefs(loadInfo))));
// RequestMode deviates from our internal security mode for navigations.
// While navigations normally allow cross origin we must set a same-origin
// RequestMode to get the correct service worker interception restrictions
// in place.
// TODO: remove the worker override once securityMode is fully implemented (bug 1189945)
nsContentPolicyType contentPolicy = loadInfo->InternalContentPolicyType();
if (IsNavigationContentPolicy(contentPolicy) ||
IsWorkerContentPolicy(contentPolicy)) {
if (IsNavigationContentPolicy(contentPolicy)) {
return RequestMode::Navigate;
}
// TODO: remove the worker override once securityMode is fully implemented (bug 1189945)
if (IsWorkerContentPolicy(contentPolicy)) {
return RequestMode::Same_origin;
}
@ -319,6 +318,7 @@ InternalRequest::MapChannelToRequestMode(nsIChannel* aChannel)
uint32_t corsMode;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(httpChannel->GetCorsMode(&corsMode)));
MOZ_ASSERT(corsMode != nsIHttpChannelInternal::CORS_MODE_NAVIGATE);
// This cast is valid due to static asserts in ServiceWorkerManager.cpp.
return static_cast<RequestMode>(corsMode);

View File

@ -284,6 +284,11 @@ Request::Constructor(const GlobalObject& aGlobal,
aInit.mCredentials.WasPassed() ? aInit.mCredentials.Value()
: fallbackCredentials;
if (mode == RequestMode::Navigate) {
aRv.ThrowTypeError<MSG_INVALID_REQUEST_MODE>(NS_LITERAL_STRING("navigate"));
return nullptr;
}
if (mode != RequestMode::EndGuard_) {
request->ClearCreatedByFetchEvent();
request->SetMode(mode);

View File

@ -7,11 +7,12 @@ onfetch = function(e) {
e.respondWith(e.request.text().then(function(text) {
var body = text === '' ? undefined : text;
var mode = e.request.mode == 'navigate' ? 'same-origin' : e.request.mode;
return fetch(url, {
method: e.request.method,
headers: e.request.headers,
body: body,
mode: e.request.mode,
mode: mode,
credentials: e.request.credentials,
redirect: e.request.redirect,
cache: e.request.cache,

View File

@ -151,6 +151,15 @@ function testHeaderGuard() {
ok(!r2.headers.has("Non-Simple-Header"), "no-cors Request header should have guard request-no-cors and prevent setting non-simple header.");
}
function testMode() {
try {
var req = new Request("http://example.com", {mode: "navigate"});
ok(false, "Creating a Request with navigate RequestMode should throw a TypeError");
} catch(e) {
is(e.name, "TypeError", "Creating a Request with navigate RequestMode should throw a TypeError");
}
}
function testMethod() {
// These get normalized.
var allowed = ["delete", "get", "head", "options", "post", "put" ];
@ -511,6 +520,7 @@ function runTest() {
testUrlFragment();
testUrlCredentials();
testUrlMalformed();
testMode();
testMethod();
testBug1109574();
testBug1184550();

View File

@ -55,7 +55,7 @@ enum RequestContext {
"xslt"
};
enum RequestMode { "same-origin", "no-cors", "cors" };
enum RequestMode { "same-origin", "no-cors", "cors", "navigate" };
enum RequestCredentials { "omit", "same-origin", "include" };
enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache" };
enum RequestRedirect { "follow", "error", "manual" };

View File

@ -568,7 +568,8 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
return;
}
MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin);
MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin ||
mRequestMode == RequestMode::Navigate);
if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
uint32_t mode = static_cast<uint32_t>(mRequestMode);

View File

@ -103,6 +103,8 @@ static_assert(nsIHttpChannelInternal::CORS_MODE_NO_CORS == static_cast<uint32_t>
"RequestMode enumeration value should match Necko CORS mode value.");
static_assert(nsIHttpChannelInternal::CORS_MODE_CORS == static_cast<uint32_t>(RequestMode::Cors),
"RequestMode enumeration value should match Necko CORS mode value.");
static_assert(nsIHttpChannelInternal::CORS_MODE_NAVIGATE == static_cast<uint32_t>(RequestMode::Navigate),
"RequestMode enumeration value should match Necko CORS mode value.");
static_assert(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW == static_cast<uint32_t>(RequestRedirect::Follow),
"RequestRedirect enumeration value should make Necko Redirect mode value.");

View File

@ -39,7 +39,7 @@ interface nsIHttpUpgradeListener : nsISupports
* using any feature exposed by this interface, be aware that this interface
* will change and you will be broken. You have been warned.
*/
[scriptable, uuid(332d5f9c-991c-45e3-922f-99e6fe0deb60)]
[scriptable, uuid(f292a080-f2f6-41d6-8aa4-71337e477360)]
interface nsIHttpChannelInternal : nsISupports
{
/**
@ -226,6 +226,7 @@ interface nsIHttpChannelInternal : nsISupports
const unsigned long CORS_MODE_SAME_ORIGIN = 0;
const unsigned long CORS_MODE_NO_CORS = 1;
const unsigned long CORS_MODE_CORS = 2;
const unsigned long CORS_MODE_NAVIGATE = 3;
/**
* Set by nsCORSListenerProxy to indicate CORS load type. Defaults to CORS_MODE_NO_CORS.
*/

View File

@ -95,9 +95,9 @@ async_test(function(t) {
assert_equals(requests[0].url, new URL(SCOPE, location).toString(),
'The first request to the SW must be the request for ' +
'the page.');
assert_equals(requests[0].mode, 'same-origin',
assert_equals(requests[0].mode, 'navigate',
'The mode of the first request to the SW must be ' +
'same-origin');
'navigate');
for (var i = 0; i < expected_urls.length; ++i) {
assert_equals(requests[i + 1].url, expected_urls[i],
'The URL of the request which was passed from XHR ' +

View File

@ -43,6 +43,8 @@ t.step(function() {
location.href.substring(0, location.href.lastIndexOf('/') + 1) +
scope,
'request.url should be passed to onfetch event.');
assert_equals(event.data.mode, 'navigate',
'request.mode should be passed to onfetch event.');
assert_equals(event.data.method, 'GET',
'request.method should be passed to onfetch event.');
assert_equals(event.data.referrer, location.href,

View File

@ -16,6 +16,9 @@ function get_request_init(base, params) {
var init = {};
init['method'] = params['method'] || base['method'];
init['mode'] = params['mode'] || base['mode'];
if (init['mode'] == 'navigate') {
init['mode'] = 'same-origin';
}
init['credentials'] = params['credentials'] || base['credentials'];
init['redirect'] = params['redirect-mode'] || base['redirect'];
return init;

View File

@ -22,6 +22,7 @@ onfetch = function(e) {
}
port.postMessage({
url: e.request.url,
mode: e.request.mode,
method: e.request.method,
referrer: e.request.referrer,
headers: headers,