Beispiel #1
0
static bool
ReadSuffixAndSpec(JSStructuredCloneReader* aReader,
                  OriginAttributes& aAttrs,
                  nsACString& aSpec)
{
    uint32_t suffixLength, specLength;
    if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
        return false;
    }

    nsAutoCString suffix;
    if (!suffix.SetLength(suffixLength, fallible)) {
        return false;
    }

    if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
        return false;
    }

    if (!aAttrs.PopulateFromSuffix(suffix)) {
        return false;
    }

    if (!aSpec.SetLength(specLength, fallible)) {
        return false;
    }

    if (!JS_ReadBytes(aReader, aSpec.BeginWriting(), specLength)) {
        return false;
    }

    return true;
}
void
SessionStorageManager::ClearStorages(ClearStorageType aType,
                                     const OriginAttributesPattern& aPattern,
                                     const nsACString& aOriginScope)
{
  for (auto iter1 = mOATable.Iter(); !iter1.Done(); iter1.Next()) {
    OriginAttributes oa;
    DebugOnly<bool> ok = oa.PopulateFromSuffix(iter1.Key());
    MOZ_ASSERT(ok);
    if (!aPattern.Matches(oa)) {
      // This table doesn't match the given origin attributes pattern
      continue;
    }

    OriginKeyHashTable* table = iter1.Data();
    for (auto iter2 = table->Iter(); !iter2.Done(); iter2.Next()) {
      if (aOriginScope.IsEmpty() ||
          StringBeginsWith(iter2.Key(), aOriginScope)) {
        if (aType == eAll) {
          iter2.Data()->Clear(SessionStorageCache::eDefaultSetType, false);
          iter2.Data()->Clear(SessionStorageCache::eSessionSetType, false);
        } else {
          MOZ_ASSERT(aType == eSessionOnly);
          iter2.Data()->Clear(SessionStorageCache::eSessionSetType, false);
        }
      }
    }
  }
}
Beispiel #3
0
// This is only a compatibility code for schema version 0.  Returns the 'scope'
// key in the schema version 0 format for the scope column.
nsCString Scheme0Scope(const nsACString& aOriginSuffix,
                       const nsACString& aOriginNoSuffix) {
  nsCString result;

  OriginAttributes oa;
  if (!aOriginSuffix.IsEmpty()) {
    DebugOnly<bool> success = oa.PopulateFromSuffix(aOriginSuffix);
    MOZ_ASSERT(success);
  }

  if (oa.mAppId != nsIScriptSecurityManager::NO_APP_ID ||
      oa.mInIsolatedMozBrowser) {
    result.AppendInt(oa.mAppId);
    result.Append(':');
    result.Append(oa.mInIsolatedMozBrowser ? 't' : 'f');
    result.Append(':');
  }

  // If there is more than just appid and/or inbrowser stored in origin
  // attributes, put it to the schema 0 scope as well.  We must do that
  // to keep the scope column unique (same resolution as schema 1 has
  // with originAttributes and originKey columns) so that switch between
  // schema 1 and 0 always works in both ways.
  nsAutoCString remaining;
  oa.mAppId = 0;
  oa.mInIsolatedMozBrowser = false;
  oa.CreateSuffix(remaining);
  if (!remaining.IsEmpty()) {
    MOZ_ASSERT(!aOriginSuffix.IsEmpty());

    if (result.IsEmpty()) {
      // Must contain the old prefix, otherwise we won't search for the whole
      // origin attributes suffix.
      result.AppendLiteral("0:f:");
    }

    // Append the whole origin attributes suffix despite we have already stored
    // appid and inbrowser.  We are only looking for it when the scope string
    // starts with "$appid:$inbrowser:" (with whatever valid values).
    //
    // The OriginAttributes suffix is a string in a form like:
    // "^addonId=101&userContextId=5" and it's ensured it always starts with '^'
    // and never contains ':'.  See OriginAttributes::CreateSuffix.
    result.Append(aOriginSuffix);
    result.Append(':');
  }

  result.Append(aOriginNoSuffix);

  return result;
}
Beispiel #4
0
NS_IMETHODIMP
nsPrincipal::Read(nsIObjectInputStream* aStream)
{
  nsCOMPtr<nsISupports> supports;
  nsCOMPtr<nsIURI> codebase;
  nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
  if (NS_FAILED(rv)) {
    return rv;
  }

  codebase = do_QueryInterface(supports);

  nsCOMPtr<nsIURI> domain;
  rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
  if (NS_FAILED(rv)) {
    return rv;
  }

  domain = do_QueryInterface(supports);

  nsAutoCString suffix;
  rv = aStream->ReadCString(suffix);
  NS_ENSURE_SUCCESS(rv, rv);

  OriginAttributes attrs;
  bool ok = attrs.PopulateFromSuffix(suffix);
  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);

  rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
  NS_ENSURE_SUCCESS(rv, rv);

  // This may be null.
  nsCOMPtr<nsIContentSecurityPolicy> csp = do_QueryInterface(supports, &rv);

  rv = Init(codebase, attrs);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = SetCsp(csp);
  NS_ENSURE_SUCCESS(rv, rv);

  // need to link in the CSP context here (link in the URI of the protected
  // resource).
  if (csp) {
    csp->SetRequestContext(codebase, nullptr, nullptr);
  }

  SetDomain(domain);

  return NS_OK;
}
Beispiel #5
0
static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader,
                              OriginAttributes& aAttrs, nsACString& aSpec,
                              nsACString& aOriginNoSuffix) {
  uint32_t suffixLength, specLength;
  if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
    return false;
  }

  nsAutoCString suffix;
  if (!suffix.SetLength(suffixLength, fallible)) {
    return false;
  }

  if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
    return false;
  }

  if (!aAttrs.PopulateFromSuffix(suffix)) {
    return false;
  }

  if (!aSpec.SetLength(specLength, fallible)) {
    return false;
  }

  if (!JS_ReadBytes(aReader, aSpec.BeginWriting(), specLength)) {
    return false;
  }

  uint32_t originNoSuffixLength, dummy;
  if (!JS_ReadUint32Pair(aReader, &originNoSuffixLength, &dummy)) {
    return false;
  }

  MOZ_ASSERT(dummy == 0);

  if (!aOriginNoSuffix.SetLength(originNoSuffixLength, fallible)) {
    return false;
  }

  if (!JS_ReadBytes(aReader, aOriginNoSuffix.BeginWriting(),
                    originNoSuffixLength)) {
    return false;
  }

  return true;
}
Beispiel #6
0
NS_IMETHODIMP
nsPrincipal::Read(nsIObjectInputStream* aStream)
{
  nsCOMPtr<nsISupports> supports;
  nsCOMPtr<nsIURI> codebase;
  nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
  if (NS_FAILED(rv)) {
    return rv;
  }

  codebase = do_QueryInterface(supports);

  nsCOMPtr<nsIURI> domain;
  rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
  if (NS_FAILED(rv)) {
    return rv;
  }

  domain = do_QueryInterface(supports);

  nsAutoCString suffix;
  rv = aStream->ReadCString(suffix);
  NS_ENSURE_SUCCESS(rv, rv);

  OriginAttributes attrs;
  bool ok = attrs.PopulateFromSuffix(suffix);
  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);

  rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
  NS_ENSURE_SUCCESS(rv, rv);

  rv = Init(codebase, attrs);
  NS_ENSURE_SUCCESS(rv, rv);

  mCSP = do_QueryInterface(supports, &rv);
  // make sure setRequestContext is called after Init(),
  // to make sure  the principals URI been initalized.
  if (mCSP) {
    mCSP->SetRequestContext(nullptr, this);
  }

  SetDomain(domain);

  return NS_OK;
}
Beispiel #7
0
static int
RemoveEntriesForPattern(PLHashEntry *entry, int32_t number, void *arg)
{
    nsDependentCString key(static_cast<const char*>(entry->key));

    // Extract the origin attributes suffix from the key.
    int32_t colon = key.Find(NS_LITERAL_CSTRING(":"));
    MOZ_ASSERT(colon != kNotFound);
    nsDependentCSubstring oaSuffix;
    oaSuffix.Rebind(key.BeginReading(), colon);

    // Build the OriginAttributes object of it...
    OriginAttributes oa;
    DebugOnly<bool> rv = oa.PopulateFromSuffix(oaSuffix);
    MOZ_ASSERT(rv);

    // ...and match it against the given pattern.
    OriginAttributesPattern const *pattern = static_cast<OriginAttributesPattern const*>(arg);
    if (pattern->Matches(oa)) {
        return HT_ENUMERATE_NEXT | HT_ENUMERATE_REMOVE;
    }
    return HT_ENUMERATE_NEXT;
}
Beispiel #8
0
nsresult
ServiceWorkerRegistrar::ReadData()
{
  // We cannot assert about the correct thread because normally this method
  // runs on a IO thread, but in gTests we call it from the main-thread.

  nsCOMPtr<nsIFile> file;

  {
    MonitorAutoLock lock(mMonitor);

    if (!mProfileDir) {
      return NS_ERROR_FAILURE;
    }

    nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }

  nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  bool exists;
  rv = file->Exists(&exists);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (!exists) {
    return NS_OK;
  }

  nsCOMPtr<nsIInputStream> stream;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(stream);
  MOZ_ASSERT(lineInputStream);

  nsAutoCString version;
  bool hasMoreLines;
  rv = lineInputStream->ReadLine(version, &hasMoreLines);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (!IsSupportedVersion(version)) {
    nsContentUtils::LogMessageToConsole(nsPrintfCString(
      "Unsupported service worker registrar version: %s", version.get()).get());
    return NS_ERROR_FAILURE;
  }

  nsTArray<ServiceWorkerRegistrationData> tmpData;

  bool overwrite = false;
  bool dedupe = false;
  while (hasMoreLines) {
    ServiceWorkerRegistrationData* entry = tmpData.AppendElement();

#define GET_LINE(x)                                   \
    rv = lineInputStream->ReadLine(x, &hasMoreLines); \
    if (NS_WARN_IF(NS_FAILED(rv))) {                  \
      return rv;                                      \
    }                                                 \
    if (NS_WARN_IF(!hasMoreLines)) {                  \
      return NS_ERROR_FAILURE;                        \
    }

    nsAutoCString line;
    nsAutoCString unused;
    if (version.EqualsLiteral(SERVICEWORKERREGISTRAR_VERSION)) {
      nsAutoCString suffix;
      GET_LINE(suffix);

      OriginAttributes attrs;
      if (!attrs.PopulateFromSuffix(suffix)) {
        return NS_ERROR_INVALID_ARG;
      }

      GET_LINE(entry->scope());

      entry->principal() =
        mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope());

      GET_LINE(entry->currentWorkerURL());

      nsAutoCString fetchFlag;
      GET_LINE(fetchFlag);
      if (!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
          !fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
        return NS_ERROR_INVALID_ARG;
      }
      entry->currentWorkerHandlesFetch() =
        fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);

      nsAutoCString cacheName;
      GET_LINE(cacheName);
      CopyUTF8toUTF16(cacheName, entry->cacheName());

      nsAutoCString loadFlags;
      GET_LINE(loadFlags);
      entry->loadFlags() = loadFlags.ToInteger(&rv, 16);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
      } else if (entry->loadFlags() != nsIRequest::LOAD_NORMAL &&
                 entry->loadFlags() != nsIRequest::VALIDATE_ALWAYS) {
        return NS_ERROR_INVALID_ARG;
      }
    } else if (version.EqualsLiteral("5")) {
      overwrite = true;
      dedupe = true;

      nsAutoCString suffix;
      GET_LINE(suffix);

      OriginAttributes attrs;
      if (!attrs.PopulateFromSuffix(suffix)) {
        return NS_ERROR_INVALID_ARG;
      }

      GET_LINE(entry->scope());

      entry->principal() =
        mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope());

      GET_LINE(entry->currentWorkerURL());

      nsAutoCString fetchFlag;
      GET_LINE(fetchFlag);
      if (!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
          !fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
        return NS_ERROR_INVALID_ARG;
      }
      entry->currentWorkerHandlesFetch() =
        fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);

      nsAutoCString cacheName;
      GET_LINE(cacheName);
      CopyUTF8toUTF16(cacheName, entry->cacheName());

      entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
    } else if (version.EqualsLiteral("4")) {
      overwrite = true;
      dedupe = true;

      nsAutoCString suffix;
      GET_LINE(suffix);

      OriginAttributes attrs;
      if (!attrs.PopulateFromSuffix(suffix)) {
        return NS_ERROR_INVALID_ARG;
      }

      GET_LINE(entry->scope());

      entry->principal() =
        mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope());

      GET_LINE(entry->currentWorkerURL());

      // default handlesFetch flag to Enabled
      entry->currentWorkerHandlesFetch() = true;

      nsAutoCString cacheName;
      GET_LINE(cacheName);
      CopyUTF8toUTF16(cacheName, entry->cacheName());

      entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
    } else if (version.EqualsLiteral("3")) {
      overwrite = true;
      dedupe = true;

      nsAutoCString suffix;
      GET_LINE(suffix);

      OriginAttributes attrs;
      if (!attrs.PopulateFromSuffix(suffix)) {
        return NS_ERROR_INVALID_ARG;
      }

      // principal spec is no longer used; we use scope directly instead
      GET_LINE(unused);

      GET_LINE(entry->scope());

      entry->principal() =
        mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope());

      GET_LINE(entry->currentWorkerURL());

      // default handlesFetch flag to Enabled
      entry->currentWorkerHandlesFetch() = true;

      nsAutoCString cacheName;
      GET_LINE(cacheName);
      CopyUTF8toUTF16(cacheName, entry->cacheName());

      entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
    } else if (version.EqualsLiteral("2")) {
      overwrite = true;
      dedupe = true;

      nsAutoCString suffix;
      GET_LINE(suffix);

      OriginAttributes attrs;
      if (!attrs.PopulateFromSuffix(suffix)) {
        return NS_ERROR_INVALID_ARG;
      }

      // principal spec is no longer used; we use scope directly instead
      GET_LINE(unused);

      GET_LINE(entry->scope());

      entry->principal() =
        mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope());

      // scriptSpec is no more used in latest version.
      GET_LINE(unused);

      GET_LINE(entry->currentWorkerURL());

      // default handlesFetch flag to Enabled
      entry->currentWorkerHandlesFetch() = true;

      nsAutoCString cacheName;
      GET_LINE(cacheName);
      CopyUTF8toUTF16(cacheName, entry->cacheName());

      // waitingCacheName is no more used in latest version.
      GET_LINE(unused);

      entry->loadFlags() = nsIRequest::VALIDATE_ALWAYS;
    } else {
      MOZ_ASSERT_UNREACHABLE("Should never get here!");
    }

#undef GET_LINE

    rv = lineInputStream->ReadLine(line, &hasMoreLines);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR)) {
      return NS_ERROR_FAILURE;
    }
  }

  stream->Close();

  // Copy data over to mData.
  for (uint32_t i = 0; i < tmpData.Length(); ++i) {
    bool match = false;
    if (dedupe) {
      MOZ_ASSERT(overwrite);
      // If this is an old profile, then we might need to deduplicate.  In
      // theory this can be removed in the future (Bug 1248449)
      for (uint32_t j = 0; j < mData.Length(); ++j) {
        // Use same comparison as RegisterServiceWorker. Scope contains
        // basic origin information.  Combine with any principal attributes.
        if (Equivalent(tmpData[i], mData[j])) {
          // Last match wins, just like legacy loading used to do in
          // the ServiceWorkerManager.
          mData[j] = tmpData[i];
          // Dupe found, so overwrite file with reduced list.
          match = true;
          break;
        }
      }
    } else {
#ifdef DEBUG
      // Otherwise assert no duplications in debug builds.
      for (uint32_t j = 0; j < mData.Length(); ++j) {
        MOZ_ASSERT(!Equivalent(tmpData[i], mData[j]));
      }
#endif
    }
    if (!match) {
      mData.AppendElement(tmpData[i]);
    }
  }

  // Overwrite previous version.
  // Cannot call SaveData directly because gtest uses main-thread.
  if (overwrite && NS_FAILED(WriteData())) {
    NS_WARNING("Failed to write data for the ServiceWorker Registations.");
    DeleteData();
  }

  return NS_OK;
}