Bug 1264178 - Part 1: Expose URL fragment to request but not response. r=bkelly

--HG--
extra : rebase_source : ee0cac184ac64b1fa9185f912753f10b61a55383
This commit is contained in:
Tom Tung 2016-11-07 10:16:34 +08:00
parent bea3aefea7
commit a63de77d6a
14 changed files with 175 additions and 153 deletions

View File

@ -50,12 +50,12 @@ struct HeadersEntry
nsCString name;
nsCString value;
};
struct CacheRequest
{
nsCString method;
nsCString urlWithoutQuery;
nsCString urlQuery;
nsCString urlFragment;
HeadersEntry[] headers;
HeadersGuardEnum headersGuard;
nsString referrer;

View File

@ -32,20 +32,15 @@ namespace mozilla {
namespace dom {
namespace cache {
namespace db {
const int32_t kFirstShippedSchemaVersion = 15;
namespace {
// Update this whenever the DB schema is changed.
const int32_t kLatestSchemaVersion = 23;
const int32_t kLatestSchemaVersion = 24;
// ---------
// The following constants define the SQL schema. These are defined in the
// same order the SQL should be executed in CreateOrMigrateSchema(). They are
// broken out as constants for convenient use in validation and migration.
// ---------
// The caches table is the single source of truth about what Cache
// objects exist for the origin. The contents of the Cache are stored
// in the entries table that references back to caches.
@ -103,14 +98,13 @@ const char* const kTableEntries =
"response_security_info_id INTEGER NULL REFERENCES security_info(id), "
"response_principal_info TEXT NOT NULL, "
"cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE, "
"request_redirect INTEGER NOT NULL, "
"request_referrer_policy INTEGER NOT NULL, "
"request_integrity TEXT NOT NULL"
"request_integrity TEXT NOT NULL, "
"request_url_fragment TEXT NOT NULL"
// New columns must be added at the end of table to migrate and
// validate properly.
")";
// Create an index to support the QueryCache() matching algorithm. This
// needs to quickly find entries in a given Cache that match the request
// URL. The url query is separated in order to support the ignoreSearch
@ -1655,6 +1649,7 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
"request_url_no_query_hash, "
"request_url_query, "
"request_url_query_hash, "
"request_url_fragment, "
"request_referrer, "
"request_referrer_policy, "
"request_headers_guard, "
@ -1679,6 +1674,7 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
":request_url_no_query_hash, "
":request_url_query, "
":request_url_query_hash, "
":request_url_fragment, "
":request_referrer, "
":request_referrer_policy, "
":request_headers_guard, "
@ -1724,19 +1720,19 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
nsAutoCString urlQueryHash;
rv = HashCString(crypto, aRequest.urlQuery(), urlQueryHash);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindUTF8StringAsBlobByName(
NS_LITERAL_CSTRING("request_url_query_hash"), urlQueryHash);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("request_url_fragment"),
aRequest.urlFragment());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindStringByName(NS_LITERAL_CSTRING("request_referrer"),
aRequest.referrer());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_referrer_policy"),
static_cast<int32_t>(aRequest.referrerPolicy()));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_headers_guard"),
static_cast<int32_t>(aRequest.headersGuard()));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@ -2043,13 +2039,13 @@ ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aConn);
MOZ_ASSERT(aSavedRequestOut);
nsCOMPtr<mozIStorageStatement> state;
nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT "
"request_method, "
"request_url_no_query, "
"request_url_query, "
"request_url_fragment, "
"request_referrer, "
"request_referrer_policy, "
"request_headers_guard, "
@ -2074,70 +2070,59 @@ ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
rv = state->GetUTF8String(0, aSavedRequestOut->mValue.method());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->GetUTF8String(1, aSavedRequestOut->mValue.urlWithoutQuery());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->GetUTF8String(2, aSavedRequestOut->mValue.urlQuery());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->GetString(3, aSavedRequestOut->mValue.referrer());
rv = state->GetUTF8String(3, aSavedRequestOut->mValue.urlFragment());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->GetString(4, aSavedRequestOut->mValue.referrer());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
int32_t referrerPolicy;
rv = state->GetInt32(4, &referrerPolicy);
rv = state->GetInt32(5, &referrerPolicy);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.referrerPolicy() =
static_cast<ReferrerPolicy>(referrerPolicy);
int32_t guard;
rv = state->GetInt32(5, &guard);
rv = state->GetInt32(6, &guard);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.headersGuard() =
static_cast<HeadersGuardEnum>(guard);
int32_t mode;
rv = state->GetInt32(6, &mode);
rv = state->GetInt32(7, &mode);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.mode() = static_cast<RequestMode>(mode);
int32_t credentials;
rv = state->GetInt32(7, &credentials);
rv = state->GetInt32(8, &credentials);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.credentials() =
static_cast<RequestCredentials>(credentials);
int32_t requestContentPolicyType;
rv = state->GetInt32(8, &requestContentPolicyType);
rv = state->GetInt32(9, &requestContentPolicyType);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.contentPolicyType() =
static_cast<nsContentPolicyType>(requestContentPolicyType);
int32_t requestCache;
rv = state->GetInt32(9, &requestCache);
rv = state->GetInt32(10, &requestCache);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.requestCache() =
static_cast<RequestCache>(requestCache);
int32_t requestRedirect;
rv = state->GetInt32(10, &requestRedirect);
rv = state->GetInt32(11, &requestRedirect);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mValue.requestRedirect() =
static_cast<RequestRedirect>(requestRedirect);
rv = state->GetString(11, aSavedRequestOut->mValue.integrity());
rv = state->GetString(12, aSavedRequestOut->mValue.integrity());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
bool nullBody = false;
rv = state->GetIsNull(12, &nullBody);
rv = state->GetIsNull(13, &nullBody);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mHasBodyId = !nullBody;
if (aSavedRequestOut->mHasBodyId) {
rv = ExtractId(state, 12, &aSavedRequestOut->mBodyId);
rv = ExtractId(state, 13, &aSavedRequestOut->mBodyId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
}
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT "
"name, "
@ -2492,7 +2477,7 @@ nsresult MigrateFrom19To20(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom20To21(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom21To22(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom22To23(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema);
// Configure migration functions to run for the given starting version.
Migration sMigrationList[] = {
Migration(15, MigrateFrom15To16),
@ -2503,10 +2488,9 @@ Migration sMigrationList[] = {
Migration(20, MigrateFrom20To21),
Migration(21, MigrateFrom21To22),
Migration(22, MigrateFrom22To23),
Migration(23, MigrateFrom23To24),
};
uint32_t sMigrationListLength = sizeof(sMigrationList) / sizeof(Migration);
nsresult
RewriteEntriesSchema(mozIStorageConnection* aConn)
{
@ -3001,15 +2985,31 @@ nsresult MigrateFrom22To23(mozIStorageConnection* aConn, bool& aRewriteSchema)
// The only change between 22 and 23 was a different snappy compression
// format, but it's backwards-compatible.
nsresult rv = aConn->SetSchemaVersion(23);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
return rv;
}
nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aConn);
// Add the request_url_fragment column.
nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE entries "
"ADD COLUMN request_url_fragment TEXT NOT NULL DEFAULT ''"
));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = aConn->SetSchemaVersion(24);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aRewriteSchema = true;
return rv;
}
} // anonymous namespace
} // namespace db
} // namespace cache
} // namespace dom

View File

@ -122,18 +122,13 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
ErrorResult& aRv)
{
MOZ_ASSERT(aIn);
aIn->GetMethod(aOut.method());
nsAutoCString url;
aIn->GetURL(url);
nsCString url(aIn->GetURLWithoutFragment());
bool schemeValid;
ProcessURL(url, &schemeValid, &aOut.urlWithoutQuery(), &aOut.urlQuery(), aRv);
if (aRv.Failed()) {
return;
}
if (!schemeValid) {
if (aSchemeAction == TypeErrorOnInvalidScheme) {
NS_ConvertUTF8toUTF16 urlUTF16(url);
@ -142,10 +137,10 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
return;
}
}
aOut.urlFragment() = aIn->GetFragment();
aIn->GetReferrer(aOut.referrer());
aOut.referrerPolicy() = aIn->ReferrerPolicy_();
RefPtr<InternalHeaders> headers = aIn->Headers();
MOZ_ASSERT(headers);
ToHeadersEntryList(aOut.headers(), headers);
@ -306,17 +301,14 @@ TypeUtils::ToResponse(const CacheResponse& aIn)
RefPtr<Response> ref = new Response(GetGlobalObject(), ir);
return ref.forget();
}
already_AddRefed<InternalRequest>
TypeUtils::ToInternalRequest(const CacheRequest& aIn)
{
nsAutoCString url(aIn.urlWithoutQuery());
url.Append(aIn.urlQuery());
RefPtr<InternalRequest> internalRequest = new InternalRequest(url);
RefPtr<InternalRequest> internalRequest =
new InternalRequest(url, aIn.urlFragment());
internalRequest->SetMethod(aIn.method());
internalRequest->SetReferrer(aIn.referrer());
internalRequest->SetReferrerPolicy(aIn.referrerPolicy());
internalRequest->SetMode(aIn.mode());

View File

@ -25,6 +25,35 @@ function checkResponse(r, expectedBody) {
}
});
}
function checkFragment(cache, request, requestWithDifferentFragment) {
var req1 = new Request(request);
var req2 = new Request(requestWithDifferentFragment);
var res1 = new Response("Hello World1");
var res2 = new Response("Hello World2");
// Ensure both request and requestWithDifferentFragment have fragment.
ok(req1.url.includes('#fragment'), "Request URL should keep the fragment.");
ok(req2.url.includes('#other'), "Request URL should keep the fragment.");
cache.put(req1, res1).then(() => cache.put(req2, res2))
.then(function () {
// Test for ensuring we get the fragment from cache request.
cache.keys(req2).then(function(keys) {
keys.forEach(function(r, index, array) {
is(req2.url, r.url, "Request URL should be the same");
});
})
return cache.match(req1);
}).then(function (resp) {
return resp.text();
}).then(function (body) {
// Test for ensuring only the last response will be cached.
is(body, "Hello World2", "Response should be the same as last one");
cache.delete(req1);
cache.delete(req2);
});
return Promise.resolve();
}
fetch(new Request(request)).then(function(r) {
response = r;
@ -39,12 +68,13 @@ fetch(new Request(request)).then(function(r) {
}).then(function() {
testDone();
});
// The request argument can either be a URL string, or a Request object.
function testRequest(request, unknownRequest, requestWithAlternateQueryString,
requestWithDifferentFragment) {
return caches.open(name).then(function(cache) {
c = cache;
return checkFragment(c, request, requestWithDifferentFragment);
}).then(function() {
return c.add(request);
}).then(function() {
return Promise.all(

View File

@ -375,19 +375,15 @@ FetchDriver::HttpFetch()
// Step 4 onwards of "HTTP Fetch" is handled internally by Necko.
return NS_OK;
}
already_AddRefed<InternalResponse>
FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse,
bool aFoundOpaqueRedirect)
{
MOZ_ASSERT(aResponse);
AutoTArray<nsCString, 4> reqURLList;
mRequest->GetURLList(reqURLList);
mRequest->GetURLListWithoutFragment(reqURLList);
MOZ_ASSERT(!reqURLList.IsEmpty());
aResponse->SetURLList(reqURLList);
RefPtr<InternalResponse> filteredResponse;
if (aFoundOpaqueRedirect) {
filteredResponse = aResponse->OpaqueRedirectResponse();
@ -808,15 +804,18 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
if(NS_WARN_IF(NS_FAILED(rv))){
return rv;
}
nsCString spec;
rv = uriClone->GetSpec(spec);
if(NS_WARN_IF(NS_FAILED(rv))){
return rv;
}
nsCString fragment;
rv = uri->GetRef(fragment);
if(NS_WARN_IF(NS_FAILED(rv))){
return rv;
}
mRequest->AddURL(spec);
mRequest->AddURL(spec, fragment);
NS_ConvertUTF8toUTF16 tRPHeaderValue(tRPHeaderCValue);
// updates requests associated referrer policy according to the
// Referrer-Policy header (if any).

View File

@ -19,18 +19,16 @@
namespace mozilla {
namespace dom {
// The global is used to extract the principal.
already_AddRefed<InternalRequest>
InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const
{
MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(), "Internal Request's urlList should not be empty when copied from constructor.");
RefPtr<InternalRequest> copy = new InternalRequest(mURLList.LastElement());
RefPtr<InternalRequest> copy = new InternalRequest(mURLList.LastElement(),
mFragment);
copy->SetMethod(mMethod);
copy->mHeaders = new InternalHeaders(*mHeaders);
copy->SetUnsafeRequest();
copy->mBodyStream = mBodyStream;
copy->mForceOriginHeader = true;
// The "client" is not stored in our implementation. Fetch API users should
@ -75,11 +73,10 @@ InternalRequest::Clone()
if (replacementBody) {
mBodyStream.swap(replacementBody);
}
return clone.forget();
}
InternalRequest::InternalRequest(const nsACString& aURL)
InternalRequest::InternalRequest(const nsACString& aURL,
const nsACString& aFragment)
: mMethod("GET")
, mHeaders(new InternalHeaders(HeadersGuardEnum::None))
, mContentPolicyType(nsIContentPolicy::TYPE_FETCH)
@ -105,10 +102,10 @@ InternalRequest::InternalRequest(const nsACString& aURL)
, mUseURLCredentials(false)
{
MOZ_ASSERT(!aURL.IsEmpty());
AddURL(aURL);
AddURL(aURL, aFragment);
}
InternalRequest::InternalRequest(const nsACString& aURL,
const nsACString& aFragment,
const nsACString& aMethod,
already_AddRefed<InternalHeaders> aHeaders,
RequestCache aCacheMode,
@ -142,9 +139,8 @@ InternalRequest::InternalRequest(const nsACString& aURL,
, mUseURLCredentials(false)
{
MOZ_ASSERT(!aURL.IsEmpty());
AddURL(aURL);
AddURL(aURL, aFragment);
}
InternalRequest::InternalRequest(const InternalRequest& aOther)
: mMethod(aOther.mMethod)
, mURLList(aOther.mURLList)
@ -159,6 +155,7 @@ InternalRequest::InternalRequest(const InternalRequest& aOther)
, mCacheMode(aOther.mCacheMode)
, mRedirectMode(aOther.mRedirectMode)
, mIntegrity(aOther.mIntegrity)
, mFragment(aOther.mFragment)
, mAuthenticationFlag(aOther.mAuthenticationFlag)
, mForceOriginHeader(aOther.mForceOriginHeader)
, mPreserveContentCodings(aOther.mPreserveContentCodings)

View File

@ -87,17 +87,14 @@ class Request;
class IPCInternalRequest;
#define kFETCH_CLIENT_REFERRER_STR "about:client"
class InternalRequest final
{
friend class Request;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
explicit InternalRequest(const nsACString& aURL);
InternalRequest(const nsACString& aURL, const nsACString& aFragment);
InternalRequest(const nsACString& aURL,
const nsACString& aFragment,
const nsACString& aMethod,
already_AddRefed<InternalHeaders> aHeaders,
RequestCache aCacheMode,
@ -134,37 +131,49 @@ public:
mMethod.LowerCaseEqualsASCII("post") ||
mMethod.LowerCaseEqualsASCII("head");
}
// GetURL should get the request's current url. A request has an associated
// current url. It is a pointer to the last fetch URL in request's url list.
// GetURL should get the request's current url with fragment. A request has
// an associated current url. It is a pointer to the last fetch URL in
// request's url list.
void
GetURL(nsACString& aURL) const
{
MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(), "Internal Request's urlList should not be empty.");
aURL.Assign(mURLList.LastElement());
aURL.Assign(GetURLWithoutFragment());
if (GetFragment().IsEmpty()) {
return;
}
aURL.Append(NS_LITERAL_CSTRING("#"));
aURL.Append(GetFragment());
}
const nsCString&
GetURLWithoutFragment() const
{
MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
"Internal Request's urlList should not be empty.");
return mURLList.LastElement();
}
// AddURL should append the url into url list.
// Normally we strip the fragment from the URL in Request::Constructor.
// If internal code is directly constructing this object they must
// strip the fragment first. Since these should be well formed URLs we
// can use a simple check for a fragment here. The full parser is
// difficult to use off the main thread.
// Normally we strip the fragment from the URL in Request::Constructor and
// pass the fragment as the second argument into it.
// If a fragment is present in the URL it must be stripped and passed in
// separately.
void
AddURL(const nsACString& aURL)
AddURL(const nsACString& aURL, const nsACString& aFragment)
{
MOZ_ASSERT(!aURL.IsEmpty());
mURLList.AppendElement(aURL);
MOZ_ASSERT(mURLList.LastElement().Find(NS_LITERAL_CSTRING("#")) == kNotFound);
}
MOZ_ASSERT(!aURL.Contains('#'));
mURLList.AppendElement(aURL);
mFragment.Assign(aFragment);
}
// Get the URL list without their fragments.
void
GetURLList(nsTArray<nsCString>& aURLList)
GetURLListWithoutFragment(nsTArray<nsCString>& aURLList)
{
aURLList.Assign(mURLList);
}
void
GetReferrer(nsAString& aReferrer) const
{
@ -321,20 +330,23 @@ public:
{
return mIntegrity;
}
void
SetIntegrity(const nsAString& aIntegrity)
{
MOZ_ASSERT(mIntegrity.IsEmpty());
mIntegrity.Assign(aIntegrity);
}
const nsCString&
GetFragment() const
{
return mFragment;
}
nsContentPolicyType
ContentPolicyType() const
{
return mContentPolicyType;
}
void
SetContentPolicyType(nsContentPolicyType aContentPolicyType);
@ -491,15 +503,13 @@ private:
// The Environment Referrer Policy should be net::ReferrerPolicy so that it
// could be associated with nsIHttpChannel.
net::ReferrerPolicy mEnvironmentReferrerPolicy;
RequestMode mMode;
RequestCredentials mCredentialsMode;
MOZ_INIT_OUTSIDE_CTOR LoadTainting mResponseTainting;
RequestCache mCacheMode;
RequestRedirect mRedirectMode;
nsString mIntegrity;
nsCString mFragment;
MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;

View File

@ -89,16 +89,15 @@ ParseURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
}
return resolvedURI.forget();
}
void
GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
nsAString& aRequestURL, ErrorResult& aRv)
nsAString& aRequestURL, nsACString& aURLfragment,
ErrorResult& aRv)
{
nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv);
if (aRv.Failed()) {
return;
}
// This fails with URIs with weird protocols, even when they are valid,
// so we ignore the failure
nsAutoCString credentials;
@ -115,21 +114,23 @@ GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsAutoCString spec;
aRv = resolvedURIClone->GetSpec(spec);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
CopyUTF8toUTF16(spec, aRequestURL);
}
// Get the fragment from nsIURI.
aRv = resolvedURI->GetRef(aURLfragment);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
already_AddRefed<nsIURI>
ParseURLFromChrome(const nsAString& aInput, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIURI> uri;
aRv = NS_NewURI(getter_AddRefs(uri), aInput, nullptr, nullptr);
if (NS_WARN_IF(aRv.Failed())) {
@ -137,16 +138,14 @@ ParseURLFromChrome(const nsAString& aInput, ErrorResult& aRv)
}
return uri.forget();
}
void
GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
ErrorResult& aRv)
nsACString& aURLfragment, ErrorResult& aRv)
{
nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv);
if (aRv.Failed()) {
return;
}
// This fails with URIs with weird protocols, even when they are valid,
// so we ignore the failure
nsAutoCString credentials;
@ -163,16 +162,19 @@ GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsAutoCString spec;
aRv = uriClone->GetSpec(spec);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
CopyUTF8toUTF16(spec, aRequestURL);
}
// Get the fragment from nsIURI.
aRv = uri->GetRef(aURLfragment);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
already_AddRefed<URL>
ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
ErrorResult& aRv)
@ -188,16 +190,15 @@ ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
}
return url.forget();
}
void
GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
nsAString& aRequestURL, ErrorResult& aRv)
nsAString& aRequestURL, nsACString& aURLfragment,
ErrorResult& aRv)
{
RefPtr<URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
if (aRv.Failed()) {
return;
}
nsString username;
url->GetUsername(username, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@ -209,17 +210,27 @@ GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (!username.IsEmpty() || !password.IsEmpty()) {
aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
return;
}
// Get the fragment from URL.
nsAutoString fragment;
url->GetHash(fragment, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
// Note: URL::GetHash() includes the "#" and we want the fragment with out
// the hash symbol.
if (!fragment.IsEmpty()) {
CopyUTF16toUTF8(Substring(fragment, 1), aURLfragment);
}
url->SetHash(EmptyString(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
url->Stringify(aRequestURL, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
@ -284,38 +295,33 @@ Request::Constructor(const GlobalObject& aGlobal,
}
request = inputReq->GetInternalRequest();
} else {
// aInput is USVString.
// We need to get url before we create a InternalRequest.
nsAutoString input;
input.Assign(aInput.GetAsUSVString());
nsAutoString requestURL;
nsCString fragment;
if (NS_IsMainThread()) {
nsIDocument* doc = GetEntryDocument();
if (doc) {
GetRequestURLFromDocument(doc, input, requestURL, aRv);
GetRequestURLFromDocument(doc, input, requestURL, fragment, aRv);
} else {
// If we don't have a document, we must assume that this is a full URL.
GetRequestURLFromChrome(input, requestURL, aRv);
GetRequestURLFromChrome(input, requestURL, fragment, aRv);
}
} else {
GetRequestURLFromWorker(aGlobal, input, requestURL, aRv);
GetRequestURLFromWorker(aGlobal, input, requestURL, fragment, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request = new InternalRequest(NS_ConvertUTF16toUTF8(requestURL));
request = new InternalRequest(NS_ConvertUTF16toUTF8(requestURL), fragment);
}
request = request->GetRequestConstructorCopy(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RequestMode fallbackMode = RequestMode::EndGuard_;
RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
RequestCache fallbackCache = RequestCache::EndGuard_;

View File

@ -585,16 +585,13 @@ HttpServer::Connection::ConsumeLine(const char* aBuffer,
NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
nsDependentCSubstring method = tokens.nextToken();
NS_ENSURE_TRUE(NS_IsValidHTTPToken(method), NS_ERROR_UNEXPECTED);
NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
nsDependentCSubstring url = tokens.nextToken();
// Seems like it's also allowed to pass full urls with scheme+host+port.
// May need to support that.
NS_ENSURE_TRUE(url.First() == '/', NS_ERROR_UNEXPECTED);
mPendingReq = new InternalRequest(url);
mPendingReq = new InternalRequest(url, /* aURLFragment */ EmptyCString());
mPendingReq->SetMethod(method);
NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
nsDependentCSubstring version = tokens.nextToken();
NS_ENSURE_TRUE(StringBeginsWith(version, NS_LITERAL_CSTRING("HTTP/1.")),

View File

@ -231,16 +231,14 @@ function testMethod() {
} catch(e) {
is(e.name, "TypeError", "HEAD/GET request cannot have a body");
}
// Non HEAD/GET should not throw.
var r = new Request("", { method: "patch", body: "hello" });
}
function testUrlFragment() {
var req = new Request("./request#withfragment");
is(req.url, (new URL("./request", self.location.href)).href, "request.url should be serialized with exclude fragment flag set");
is(req.url, (new URL("./request#withfragment", self.location.href)).href,
"request.url should be serialized without exclude fragment flag set");
}
function testUrlMalformed() {
try {
var req = new Request("http:// example.com");

View File

@ -1248,6 +1248,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
nsTArray<nsCString> mHeaderNames;
nsTArray<nsCString> mHeaderValues;
nsCString mSpec;
nsCString mFragment;
nsCString mMethod;
nsString mClientId;
bool mIsReload;
@ -1319,18 +1320,17 @@ public:
nsCOMPtr<nsIURI> uriNoFragment;
rv = uri->CloneIgnoringRef(getter_AddRefs(uriNoFragment));
NS_ENSURE_SUCCESS(rv, rv);
rv = uriNoFragment->GetSpec(mSpec);
NS_ENSURE_SUCCESS(rv, rv);
rv = uri->GetRef(mFragment);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t loadFlags;
rv = channel->GetLoadFlags(&loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILoadInfo> loadInfo;
rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
NS_ENSURE_SUCCESS(rv, rv);
mContentPolicyType = loadInfo->InternalContentPolicyType();
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
@ -1475,8 +1475,8 @@ private:
result.SuppressException();
return false;
}
RefPtr<InternalRequest> internalReq = new InternalRequest(mSpec,
mFragment,
mMethod,
internalHeaders.forget(),
mCacheMode,

View File

@ -2,7 +2,3 @@
type: testharness
[Check request values when initialized from url string]
expected: FAIL
[Check request values when initialized from url and init values]
expected: FAIL

View File

@ -419,14 +419,13 @@ async_test(function(t) {
.then(function(frame) {
assert_equals(
frame.contentDocument.body.textContent,
'Fragment Not Found',
'Service worker should not expose URL fragments.');
'Fragment Found :' + fragment,
'Service worker should expose URL fragments in request.');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker must not expose FetchEvent URL fragments.');
async_test(function(t) {
var scope = 'resources/simple.html?cache';
var frame;

View File

@ -80,21 +80,19 @@ function handleUsedCheck(event) {
'bodyUsed: ' + lastResponseForUsedCheck.bodyUsed));
}
}
function handleFragmentCheck(event) {
var body;
if (event.request.url.indexOf('#') === -1) {
body = 'Fragment Not Found';
} else {
body = 'Fragment Found';
body = 'Fragment Found :' +
event.request.url.substring(event.request.url.indexOf('#'));
}
event.respondWith(new Response(body));
}
function handleCache(event) {
event.respondWith(new Response(event.request.cache));
}
function handleEventSource(event) {
if (event.request.mode === 'navigate') {
return;