Bug 1251872 - Part 2: Store the Request referrerPolicy in the DOM Cache; r=bkelly
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 27 Feb 2016 14:08:58 -0500
changeset 323057 4d0d6bb9abee9f527a96ee2f5ddc308ce961acbe
parent 323056 a87e26a12a988360cbfdc2d3773ec7d83a84712d
child 323058 5f236850a5832f1fbae22f8b924aeb652de49e7c
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1251872
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1251872 - Part 2: Store the Request referrerPolicy in the DOM Cache; r=bkelly This patch also fixes an existing bug where we used to call RewriteEntriesSchema at the end of each individual migration, which is wrong since after the first call, sqlite will think that it's dealing with the final schema. So far we were lucky that we only changed the actual schema once.
dom/cache/CacheTypes.ipdlh
dom/cache/DBSchema.cpp
dom/cache/IPCUtils.h
dom/cache/TypeUtils.cpp
dom/cache/test/xpcshell/test_migration.js
--- a/dom/cache/CacheTypes.ipdlh
+++ b/dom/cache/CacheTypes.ipdlh
@@ -5,16 +5,17 @@
 include protocol PCache;
 include protocol PCachePushStream;
 include protocol PCacheStreamControl;
 include InputStreamParams;
 include ChannelInfo;
 include PBackgroundSharedTypes;
 
 using HeadersGuardEnum from "mozilla/dom/cache/IPCUtils.h";
+using ReferrerPolicy from "mozilla/dom/cache/IPCUtils.h";
 using RequestCredentials from "mozilla/dom/cache/IPCUtils.h";
 using RequestMode from "mozilla/dom/cache/IPCUtils.h";
 using RequestCache from "mozilla/dom/cache/IPCUtils.h";
 using RequestRedirect from "mozilla/dom/cache/IPCUtils.h";
 using ResponseType from "mozilla/dom/cache/IPCUtils.h";
 using mozilla::void_t from "ipc/IPCMessageUtils.h";
 using struct nsID from "nsID.h";
 
@@ -55,16 +56,17 @@ struct HeadersEntry
 struct CacheRequest
 {
   nsCString method;
   nsCString urlWithoutQuery;
   nsCString urlQuery;
   HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
   nsString referrer;
+  ReferrerPolicy referrerPolicy;
   RequestMode mode;
   RequestCredentials credentials;
   CacheReadStreamOrVoid body;
   uint32_t contentPolicyType;
   RequestCache requestCache;
   RequestRedirect requestRedirect;
 };
 
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -32,17 +32,17 @@ namespace dom {
 namespace cache {
 namespace db {
 
 const int32_t kFirstShippedSchemaVersion = 15;
 
 namespace {
 
 // Update this whenever the DB schema is changed.
-const int32_t kLatestSchemaVersion = 19;
+const int32_t kLatestSchemaVersion = 20;
 
 // ---------
 // 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
@@ -99,19 +99,20 @@ const char* const kTableEntries =
     "response_status INTEGER NOT NULL, "
     "response_status_text TEXT NOT NULL, "
     "response_headers_guard INTEGER NOT NULL, "
     "response_body_id TEXT NULL, "
     "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"
     // New columns must be added at the end of table to migrate and
     // validate properly.
-    "request_redirect INTEGER NOT NULL"
   ")";
 
 // 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
 // option.  Finally, we index hashes of the URL values instead of the
 // actual strings to avoid excessive disk bloat.  The index will duplicate
 // the contents of the columsn in the index.  The hash index will prune
@@ -184,16 +185,24 @@ static_assert(kWalAutoCheckpointSize % k
 // database schema accordingly and adjust the failing static_assert.
 static_assert(int(HeadersGuardEnum::None) == 0 &&
               int(HeadersGuardEnum::Request) == 1 &&
               int(HeadersGuardEnum::Request_no_cors) == 2 &&
               int(HeadersGuardEnum::Response) == 3 &&
               int(HeadersGuardEnum::Immutable) == 4 &&
               int(HeadersGuardEnum::EndGuard_) == 5,
               "HeadersGuardEnum values are as expected");
+static_assert(int(ReferrerPolicy::_empty) == 0 &&
+              int(ReferrerPolicy::No_referrer) == 1 &&
+              int(ReferrerPolicy::No_referrer_when_downgrade) == 2 &&
+              int(ReferrerPolicy::Origin_only) == 3 &&
+              int(ReferrerPolicy::Origin_when_cross_origin) == 4 &&
+              int(ReferrerPolicy::Unsafe_url) == 5 &&
+              int(ReferrerPolicy::EndGuard_) == 6,
+              "ReferrerPolicy values are as expected");
 static_assert(int(RequestMode::Same_origin) == 0 &&
               int(RequestMode::No_cors) == 1 &&
               int(RequestMode::Cors) == 2 &&
               int(RequestMode::Navigate) == 3 &&
               int(RequestMode::EndGuard_) == 4,
               "RequestMode values are as expected");
 static_assert(int(RequestCredentials::Omit) == 0 &&
               int(RequestCredentials::Same_origin) == 1 &&
@@ -1630,16 +1639,17 @@ InsertEntry(mozIStorageConnection* aConn
   rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "INSERT INTO entries ("
       "request_method, "
       "request_url_no_query, "
       "request_url_no_query_hash, "
       "request_url_query, "
       "request_url_query_hash, "
       "request_referrer, "
+      "request_referrer_policy, "
       "request_headers_guard, "
       "request_mode, "
       "request_credentials, "
       "request_contentpolicytype, "
       "request_cache, "
       "request_redirect, "
       "request_body_id, "
       "response_type, "
@@ -1653,16 +1663,17 @@ InsertEntry(mozIStorageConnection* aConn
       "cache_id "
     ") VALUES ("
       ":request_method, "
       ":request_url_no_query, "
       ":request_url_no_query_hash, "
       ":request_url_query, "
       ":request_url_query_hash, "
       ":request_referrer, "
+      ":request_referrer_policy, "
       ":request_headers_guard, "
       ":request_mode, "
       ":request_credentials, "
       ":request_contentpolicytype, "
       ":request_cache, "
       ":request_redirect, "
       ":request_body_id, "
       ":response_type, "
@@ -1705,16 +1716,20 @@ InsertEntry(mozIStorageConnection* aConn
   rv = state->BindUTF8StringAsBlobByName(
     NS_LITERAL_CSTRING("request_url_query_hash"), urlQueryHash);
   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; }
 
   rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_mode"),
                               static_cast<int32_t>(aRequest.mode()));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
@@ -1983,16 +1998,17 @@ ReadRequest(mozIStorageConnection* aConn
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "request_method, "
       "request_url_no_query, "
       "request_url_query, "
       "request_referrer, "
+      "request_referrer_policy, "
       "request_headers_guard, "
       "request_mode, "
       "request_credentials, "
       "request_contentpolicytype, "
       "request_cache, "
       "request_redirect, "
       "request_body_id "
     "FROM entries "
@@ -2014,58 +2030,64 @@ ReadRequest(mozIStorageConnection* aConn
   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());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
+  int32_t referrerPolicy;
+  rv = state->GetInt32(4, &referrerPolicy);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+  aSavedRequestOut->mValue.referrerPolicy() =
+    static_cast<ReferrerPolicy>(referrerPolicy);
+
   int32_t guard;
-  rv = state->GetInt32(4, &guard);
+  rv = state->GetInt32(5, &guard);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mValue.headersGuard() =
     static_cast<HeadersGuardEnum>(guard);
 
   int32_t mode;
-  rv = state->GetInt32(5, &mode);
+  rv = state->GetInt32(6, &mode);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mValue.mode() = static_cast<RequestMode>(mode);
 
   int32_t credentials;
-  rv = state->GetInt32(6, &credentials);
+  rv = state->GetInt32(7, &credentials);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mValue.credentials() =
     static_cast<RequestCredentials>(credentials);
 
   int32_t requestContentPolicyType;
-  rv = state->GetInt32(7, &requestContentPolicyType);
+  rv = state->GetInt32(8, &requestContentPolicyType);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mValue.contentPolicyType() =
     static_cast<nsContentPolicyType>(requestContentPolicyType);
 
   int32_t requestCache;
-  rv = state->GetInt32(8, &requestCache);
+  rv = state->GetInt32(9, &requestCache);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mValue.requestCache() =
     static_cast<RequestCache>(requestCache);
 
   int32_t requestRedirect;
-  rv = state->GetInt32(9, &requestRedirect);
+  rv = state->GetInt32(10, &requestRedirect);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mValue.requestRedirect() =
     static_cast<RequestRedirect>(requestRedirect);
 
   bool nullBody = false;
-  rv = state->GetIsNull(10, &nullBody);
+  rv = state->GetIsNull(11, &nullBody);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedRequestOut->mHasBodyId = !nullBody;
 
   if (aSavedRequestOut->mHasBodyId) {
-    rv = ExtractId(state, 10, &aSavedRequestOut->mBodyId);
+    rv = ExtractId(state, 11, &aSavedRequestOut->mBodyId);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   }
 
   rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "name, "
       "value "
     "FROM request_headers "
@@ -2391,80 +2413,47 @@ Validate(mozIStorageConnection* aConn)
 
   return rv;
 }
 
 // -----
 // Schema migration code
 // -----
 
-typedef nsresult (*MigrationFunc)(mozIStorageConnection*);
+typedef nsresult (*MigrationFunc)(mozIStorageConnection*, bool&);
 struct Migration
 {
   MOZ_CONSTEXPR Migration(int32_t aFromVersion, MigrationFunc aFunc)
     : mFromVersion(aFromVersion)
     , mFunc(aFunc)
   { }
   int32_t mFromVersion;
   MigrationFunc mFunc;
 };
 
 // Declare migration functions here.  Each function should upgrade
 // the version by a single increment.  Don't skip versions.
-nsresult MigrateFrom15To16(mozIStorageConnection* aConn);
-nsresult MigrateFrom16To17(mozIStorageConnection* aConn);
-nsresult MigrateFrom17To18(mozIStorageConnection* aConn);
-nsresult MigrateFrom18To19(mozIStorageConnection* aConn);
+nsresult MigrateFrom15To16(mozIStorageConnection* aConn, bool& aRewriteSchema);
+nsresult MigrateFrom16To17(mozIStorageConnection* aConn, bool& aRewriteSchema);
+nsresult MigrateFrom17To18(mozIStorageConnection* aConn, bool& aRewriteSchema);
+nsresult MigrateFrom18To19(mozIStorageConnection* aConn, bool& aRewriteSchema);
+nsresult MigrateFrom19To20(mozIStorageConnection* aConn, bool& aRewriteSchema);
 
 // Configure migration functions to run for the given starting version.
 Migration sMigrationList[] = {
   Migration(15, MigrateFrom15To16),
   Migration(16, MigrateFrom16To17),
   Migration(17, MigrateFrom17To18),
   Migration(18, MigrateFrom18To19),
+  Migration(19, MigrateFrom19To20),
 };
 
 uint32_t sMigrationListLength = sizeof(sMigrationList) / sizeof(Migration);
 
 nsresult
-Migrate(mozIStorageConnection* aConn)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aConn);
-
-  int32_t currentVersion = 0;
-  nsresult rv = aConn->GetSchemaVersion(&currentVersion);
-  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
-  while (currentVersion < kLatestSchemaVersion) {
-    // Wiping old databases is handled in DBAction because it requires
-    // making a whole new mozIStorageConnection.  Make sure we don't
-    // accidentally get here for one of those old databases.
-    MOZ_ASSERT(currentVersion >= kFirstShippedSchemaVersion);
-
-    for (uint32_t i = 0; i < sMigrationListLength; ++i) {
-      if (sMigrationList[i].mFromVersion == currentVersion) {
-        rv = sMigrationList[i].mFunc(aConn);
-        if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-        break;
-      }
-    }
-
-    DebugOnly<int32_t> lastVersion = currentVersion;
-    rv = aConn->GetSchemaVersion(&currentVersion);
-    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-    MOZ_ASSERT(currentVersion > lastVersion);
-  }
-
-  MOZ_ASSERT(currentVersion == kLatestSchemaVersion);
-
-  return rv;
-}
-
-nsresult
 RewriteEntriesSchema(mozIStorageConnection* aConn)
 {
   nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "PRAGMA writable_schema = ON"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   nsCOMPtr<mozIStorageStatement> state;
@@ -2483,17 +2472,65 @@ RewriteEntriesSchema(mozIStorageConnecti
   rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "PRAGMA writable_schema = OFF"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-nsresult MigrateFrom15To16(mozIStorageConnection* aConn)
+nsresult
+Migrate(mozIStorageConnection* aConn)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(aConn);
+
+  int32_t currentVersion = 0;
+  nsresult rv = aConn->GetSchemaVersion(&currentVersion);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  bool rewriteSchema = false;
+
+  while (currentVersion < kLatestSchemaVersion) {
+    // Wiping old databases is handled in DBAction because it requires
+    // making a whole new mozIStorageConnection.  Make sure we don't
+    // accidentally get here for one of those old databases.
+    MOZ_ASSERT(currentVersion >= kFirstShippedSchemaVersion);
+
+    for (uint32_t i = 0; i < sMigrationListLength; ++i) {
+      if (sMigrationList[i].mFromVersion == currentVersion) {
+        bool shouldRewrite = false;
+        rv = sMigrationList[i].mFunc(aConn, shouldRewrite);
+        if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+        if (shouldRewrite) {
+          rewriteSchema = true;
+        }
+        break;
+      }
+    }
+
+    DebugOnly<int32_t> lastVersion = currentVersion;
+    rv = aConn->GetSchemaVersion(&currentVersion);
+    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+    MOZ_ASSERT(currentVersion > lastVersion);
+  }
+
+  MOZ_ASSERT(currentVersion == kLatestSchemaVersion);
+
+  if (rewriteSchema) {
+    // Now overwrite the master SQL for the entries table to remove the column
+    // default value.  This is also necessary for our Validate() method to
+    // pass on this database.
+    rv = RewriteEntriesSchema(aConn);
+  }
+
+  return rv;
+}
+
+nsresult MigrateFrom15To16(mozIStorageConnection* aConn, bool& aRewriteSchema)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   mozStorageTransaction trans(aConn, true,
                               mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
   // Add the request_redirect column with a default value of "follow".  Note,
@@ -2502,30 +2539,26 @@ nsresult MigrateFrom15To16(mozIStorageCo
   // We don't actually want to keep the default in the schema for future
   // INSERTs.
   nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "ALTER TABLE entries "
     "ADD COLUMN request_redirect INTEGER NOT NULL DEFAULT 0"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
-  // Now overwrite the master SQL for the entries table to remove the column
-  // default value.  This is also necessary for our Validate() method to
-  // pass on this database.
-  rv = RewriteEntriesSchema(aConn);
-  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
   rv = aConn->SetSchemaVersion(16);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
+  aRewriteSchema = true;
+
   return rv;
 }
 
 nsresult
-MigrateFrom16To17(mozIStorageConnection* aConn)
+MigrateFrom16To17(mozIStorageConnection* aConn, bool& aRewriteSchema)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   // This migration path removes the response_redirected and
   // response_redirected_url columns from the entries table.  sqlite doesn't
   // support removing a column from a table using ALTER TABLE, so we need to
   // create a new table without those columns, fill it up with the existing
@@ -2640,30 +2673,24 @@ MigrateFrom16To17(mozIStorageConnection*
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   bool hasMoreData = false;
   rv = state->ExecuteStep(&hasMoreData);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   if (NS_WARN_IF(hasMoreData)) { return NS_ERROR_FAILURE; }
 
-  // Finally, rewrite the schema for the entries database, otherwise the
-  // returned SQL string from sqlite will wrap the name of the table in quotes,
-  // breaking the checks in Validate().
-  rv = RewriteEntriesSchema(aConn);
-  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-
   rv = aConn->SetSchemaVersion(17);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 nsresult
-MigrateFrom17To18(mozIStorageConnection* aConn)
+MigrateFrom17To18(mozIStorageConnection* aConn, bool& aRewriteSchema)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   mozStorageTransaction trans(aConn, true,
                               mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
   // This migration is needed in order to remove "only-if-cached" RequestCache
@@ -2683,17 +2710,17 @@ MigrateFrom17To18(mozIStorageConnection*
 
   rv = aConn->SetSchemaVersion(18);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 nsresult
-MigrateFrom18To19(mozIStorageConnection* aConn)
+MigrateFrom18To19(mozIStorageConnection* aConn, bool& aRewriteSchema)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   mozStorageTransaction trans(aConn, true,
                               mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
   // This migration is needed in order to update the RequestMode values for
@@ -2714,15 +2741,42 @@ MigrateFrom18To19(mozIStorageConnection*
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aConn->SetSchemaVersion(19);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
+nsresult MigrateFrom19To20(mozIStorageConnection* aConn, bool& aRewriteSchema)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(aConn);
+
+  mozStorageTransaction trans(aConn, true,
+                              mozIStorageConnection::TRANSACTION_IMMEDIATE);
+
+  // Add the request_referrer_policy column with a default value of
+  // "no-referrer-when-downgrade".  Note, we only use a default value here
+  // because its required by ALTER TABLE and we need to apply the default
+  // "no-referrer-when-downgrade" to existing records in the table. We don't
+  // actually want to keep the default in the schema for future INSERTs.
+  nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "ALTER TABLE entries "
+    "ADD COLUMN request_referrer_policy INTEGER NOT NULL DEFAULT 2"
+  ));
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  rv = aConn->SetSchemaVersion(20);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  aRewriteSchema = true;
+
+  return rv;
+}
+
 
 } // anonymous namespace
 
 } // namespace db
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/IPCUtils.h
+++ b/dom/cache/IPCUtils.h
@@ -19,16 +19,21 @@
 
 namespace IPC {
   template<>
   struct ParamTraits<mozilla::dom::HeadersGuardEnum> :
     public ContiguousEnumSerializer<mozilla::dom::HeadersGuardEnum,
                                     mozilla::dom::HeadersGuardEnum::None,
                                     mozilla::dom::HeadersGuardEnum::EndGuard_> {};
   template<>
+  struct ParamTraits<mozilla::dom::ReferrerPolicy> :
+    public ContiguousEnumSerializer<mozilla::dom::ReferrerPolicy,
+                                    mozilla::dom::ReferrerPolicy::_empty,
+                                    mozilla::dom::ReferrerPolicy::EndGuard_> {};
+  template<>
   struct ParamTraits<mozilla::dom::RequestMode> :
     public ContiguousEnumSerializer<mozilla::dom::RequestMode,
                                     mozilla::dom::RequestMode::Same_origin,
                                     mozilla::dom::RequestMode::EndGuard_> {};
   template<>
   struct ParamTraits<mozilla::dom::RequestCredentials> :
     public ContiguousEnumSerializer<mozilla::dom::RequestCredentials,
                                     mozilla::dom::RequestCredentials::Omit,
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -165,16 +165,17 @@ TypeUtils::ToCacheRequest(CacheRequest& 
       NS_ConvertUTF8toUTF16 urlUTF16(url);
       aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Request"),
                                                  urlUTF16);
       return;
     }
   }
 
   aIn->GetReferrer(aOut.referrer());
+  aOut.referrerPolicy() = aIn->ReferrerPolicy_();
 
   RefPtr<InternalHeaders> headers = aIn->Headers();
   MOZ_ASSERT(headers);
   ToHeadersEntryList(aOut.headers(), headers);
   aOut.headersGuard() = headers->Guard();
   aOut.mode() = aIn->Mode();
   aOut.credentials() = aIn->GetCredentialsMode();
   aOut.contentPolicyType() = aIn->ContentPolicyType();
@@ -335,16 +336,17 @@ TypeUtils::ToInternalRequest(const Cache
 
   internalRequest->SetMethod(aIn.method());
 
   nsAutoCString url(aIn.urlWithoutQuery());
   url.Append(aIn.urlQuery());
   internalRequest->SetURL(url);
 
   internalRequest->SetReferrer(aIn.referrer());
+  internalRequest->SetReferrerPolicy(aIn.referrerPolicy());
   internalRequest->SetMode(aIn.mode());
   internalRequest->SetCredentialsMode(aIn.credentials());
   internalRequest->SetContentPolicyType(aIn.contentPolicyType());
   internalRequest->SetCacheMode(aIn.requestCache());
   internalRequest->SetRedirectMode(aIn.requestRedirect());
 
   RefPtr<InternalHeaders> internalHeaders =
     ToInternalHeaders(aIn.headers(), aIn.headersGuard());
--- a/dom/cache/test/xpcshell/test_migration.js
+++ b/dom/cache/test/xpcshell/test_migration.js
@@ -17,16 +17,17 @@ function run_test() {
     return cache.keys();
   }).then(function(requestList) {
     ok(requestList.length > 0, 'should have at least one request in cache');
     requestList.forEach(function(request) {
       ok(request, 'each request in list should be non-null');
       ok(request.redirect === 'follow', 'request.redirect should default to "follow"');
       ok(request.cache === 'default', 'request.cache should have been updated to "default"' + request.cache);
       ok(request.mode === 'navigate', 'request.mode should have been updated to "navigate"');
+      ok(request.referrerPolicy === 'no-referrer-when-downgrade', 'request.referrerPolicy should have been updated to "no-referrer-when-downgrade"');
     });
     return Promise.all(requestList.map(function(request) {
       return cache.match(request);
     }));
   }).then(function(responseList) {
     ok(responseList.length > 0, 'should have at least one response in cache');
     responseList.forEach(function(response) {
       ok(response, 'each response in list should be non-null');