Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/quota/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  OriginParser.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "OriginParser.h"

#include <regex>

#include "mozilla/OriginAttributes.h"
#include "mozilla/dom/quota/Constants.h"
#include "mozilla/dom/quota/QuotaCommon.h"

namespace mozilla::dom::quota {

// static
auto OriginParser::ParseOrigin(const nsACString& aOrigin, nsCString& aSpec,
                               OriginAttributes* aAttrs,
                               nsCString& aOriginalSuffix) -> ResultType {
  MOZ_ASSERT(!aOrigin.IsEmpty());
  MOZ_ASSERT(aAttrs);

  nsCString origin(aOrigin);
  int32_t pos = origin.RFindChar('^');

  if (pos == kNotFound) {
    aOriginalSuffix.Truncate();
  } else {
    aOriginalSuffix = Substring(origin, pos);
  }

  OriginAttributes originAttributes;

  nsCString originNoSuffix;
  bool ok = originAttributes.PopulateFromOrigin(aOrigin, originNoSuffix);
  if (!ok) {
    return InvalidOrigin;
  }

  OriginParser parser(originNoSuffix);

  *aAttrs = originAttributes;
  return parser.Parse(aSpec);
}

auto OriginParser::Parse(nsACString& aSpec) -> ResultType {
  while (mTokenizer.hasMoreTokens()) {
    const nsDependentCSubstring& token = mTokenizer.nextToken();

    HandleToken(token);

    if (mError) {
      break;
    }

    if (!mHandledTokens.IsEmpty()) {
      mHandledTokens.AppendLiteral(", ");
    }
    mHandledTokens.Append('\'');
    mHandledTokens.Append(token);
    mHandledTokens.Append('\'');
  }

  if (!mError && mTokenizer.separatorAfterCurrentToken()) {
    HandleTrailingSeparator();
  }

  if (mError) {
    QM_WARNING("Origin '%s' failed to parse, handled tokens: %s", mOrigin.get(),
               mHandledTokens.get());

    return (mSchemeType == eChrome || mSchemeType == eAbout) ? ObsoleteOrigin
                                                             : InvalidOrigin;
  }

  MOZ_ASSERT(mState == eComplete || mState == eHandledTrailingSeparator);

  // For IPv6 URL, it should at least have three groups.
  MOZ_ASSERT_IF(mIPGroup > 0, mIPGroup >= 3);

  nsAutoCString spec(mScheme);

  if (mSchemeType == eFile) {
    spec.AppendLiteral("://");

    if (mUniversalFileOrigin) {
      MOZ_ASSERT(mPathnameComponents.Length() == 1);

      spec.Append(mPathnameComponents[0]);
    } else {
      for (uint32_t count = mPathnameComponents.Length(), index = 0;
           index < count; index++) {
        spec.Append('/');
        spec.Append(mPathnameComponents[index]);
      }
    }

    aSpec = spec;

    return ValidOrigin;
  }

  if (mSchemeType == eAbout) {
    if (mMaybeObsolete) {
      // The "moz-safe-about+++home" was acciedntally created by a buggy nightly
      // and can be safely removed.
      return mHost.EqualsLiteral("home") ? ObsoleteOrigin : InvalidOrigin;
    }
    spec.Append(':');
  } else if (mSchemeType != eChrome) {
    spec.AppendLiteral("://");
  }

  spec.Append(mHost);

  if (!mPort.IsNull()) {
    spec.Append(':');
    spec.AppendInt(mPort.Value());
  }

  aSpec = spec;

  return mScheme.EqualsLiteral("app") ? ObsoleteOrigin : ValidOrigin;
}

void OriginParser::HandleScheme(const nsDependentCSubstring& aToken) {
  MOZ_ASSERT(!aToken.IsEmpty());
  MOZ_ASSERT(mState == eExpectingAppIdOrScheme || mState == eExpectingScheme);

  bool isAbout = false;
  bool isMozSafeAbout = false;
  bool isFile = false;
  bool isChrome = false;
  if (aToken.EqualsLiteral("http") || aToken.EqualsLiteral("https") ||
      (isAbout = aToken.EqualsLiteral("about") ||
                 (isMozSafeAbout = aToken.EqualsLiteral("moz-safe-about"))) ||
      aToken.EqualsLiteral("indexeddb") ||
      (isFile = aToken.EqualsLiteral("file")) || aToken.EqualsLiteral("app") ||
      aToken.EqualsLiteral("resource") ||
      aToken.EqualsLiteral("moz-extension") ||
      (isChrome = aToken.EqualsLiteral(kChromeOrigin)) ||
      aToken.EqualsLiteral("uuid")) {
    mScheme = aToken;

    if (isAbout) {
      mSchemeType = eAbout;
      mState = isMozSafeAbout ? eExpectingEmptyToken1OrHost : eExpectingHost;
    } else if (isChrome) {
      mSchemeType = eChrome;
      if (mTokenizer.hasMoreTokens()) {
        mError = true;
      }
      mState = eComplete;
    } else {
      if (isFile) {
        mSchemeType = eFile;
      }
      mState = eExpectingEmptyToken1;
    }

    return;
  }

  QM_WARNING("'%s' is not a valid scheme!", nsCString(aToken).get());

  mError = true;
}

void OriginParser::HandlePathnameComponent(
    const nsDependentCSubstring& aToken) {
  MOZ_ASSERT(!aToken.IsEmpty());
  MOZ_ASSERT(mState == eExpectingEmptyTokenOrDriveLetterOrPathnameComponent ||
             mState == eExpectingEmptyTokenOrPathnameComponent);
  MOZ_ASSERT(mSchemeType == eFile);

  mPathnameComponents.AppendElement(aToken);

  mState = mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
                                      : eComplete;
}

void OriginParser::HandleToken(const nsDependentCSubstring& aToken) {
  switch (mState) {
    case eExpectingAppIdOrScheme: {
      if (aToken.IsEmpty()) {
        QM_WARNING("Expected an app id or scheme (not an empty string)!");

        mError = true;
        return;
      }

      if (IsAsciiDigit(aToken.First())) {
        // nsDependentCSubstring doesn't provice ToInteger()
        nsCString token(aToken);

        nsresult rv;
        Unused << token.ToInteger(&rv);
        if (NS_SUCCEEDED(rv)) {
          mState = eExpectingInMozBrowser;
          return;
        }
      }

      HandleScheme(aToken);

      return;
    }

    case eExpectingInMozBrowser: {
      if (aToken.Length() != 1) {
        QM_WARNING("'%zu' is not a valid length for the inMozBrowser flag!",
                   aToken.Length());

        mError = true;
        return;
      }

      if ((aToken.First() != 't') && (aToken.First() != 'f')) {
        QM_WARNING("'%s' is not a valid value for the inMozBrowser flag!",
                   nsCString(aToken).get());

        mError = true;
        return;
      }

      mState = eExpectingScheme;

      return;
    }

    case eExpectingScheme: {
      if (aToken.IsEmpty()) {
        QM_WARNING("Expected a scheme (not an empty string)!");

        mError = true;
        return;
      }

      HandleScheme(aToken);

      return;
    }

    case eExpectingEmptyToken1: {
      if (!aToken.IsEmpty()) {
        QM_WARNING("Expected the first empty token!");

        mError = true;
        return;
      }

      mState = eExpectingEmptyToken2;

      return;
    }

    case eExpectingEmptyToken2: {
      if (!aToken.IsEmpty()) {
        QM_WARNING("Expected the second empty token!");

        mError = true;
        return;
      }

      if (mSchemeType == eFile) {
        mState = eExpectingEmptyTokenOrUniversalFileOrigin;
      } else {
        if (mSchemeType == eAbout) {
          mMaybeObsolete = true;
        }
        mState = eExpectingHost;
      }

      return;
    }

    case eExpectingEmptyTokenOrUniversalFileOrigin: {
      MOZ_ASSERT(mSchemeType == eFile);

      if (aToken.IsEmpty()) {
        mState = mTokenizer.hasMoreTokens()
                     ? eExpectingEmptyTokenOrDriveLetterOrPathnameComponent
                     : eComplete;

        return;
      }

      if (aToken.EqualsLiteral("UNIVERSAL_FILE_URI_ORIGIN")) {
        mUniversalFileOrigin = true;

        mPathnameComponents.AppendElement(aToken);

        mState = eComplete;

        return;
      }

      QM_WARNING(
          "Expected the third empty token or "
          "UNIVERSAL_FILE_URI_ORIGIN!");

      mError = true;
      return;
    }

    case eExpectingHost: {
      if (aToken.IsEmpty()) {
        QM_WARNING("Expected a host (not an empty string)!");

        mError = true;
        return;
      }

      mHost = aToken;

      if (aToken.First() == '[') {
        MOZ_ASSERT(mIPGroup == 0);

        ++mIPGroup;
        mState = eExpectingIPV6Token;

        MOZ_ASSERT(mTokenizer.hasMoreTokens());
        return;
      }

      if (mTokenizer.hasMoreTokens()) {
        if (mSchemeType == eAbout) {
          QM_WARNING("Expected an empty string after host!");

          mError = true;
          return;
        }

        mState = eExpectingPort;

        return;
      }

      mState = eComplete;

      return;
    }

    case eExpectingPort: {
      MOZ_ASSERT(mSchemeType == eNone);

      if (aToken.IsEmpty()) {
        QM_WARNING("Expected a port (not an empty string)!");

        mError = true;
        return;
      }

      // nsDependentCSubstring doesn't provice ToInteger()
      nsCString token(aToken);

      nsresult rv;
      uint32_t port = token.ToInteger(&rv);
      if (NS_SUCCEEDED(rv)) {
        mPort.SetValue() = port;
      } else {
        QM_WARNING("'%s' is not a valid port number!", token.get());

        mError = true;
        return;
      }

      mState = eComplete;

      return;
    }

    case eExpectingEmptyTokenOrDriveLetterOrPathnameComponent: {
      MOZ_ASSERT(mSchemeType == eFile);

      if (aToken.IsEmpty()) {
        mPathnameComponents.AppendElement(""_ns);

        mState = mTokenizer.hasMoreTokens()
                     ? eExpectingEmptyTokenOrPathnameComponent
                     : eComplete;

        return;
      }

      if (aToken.Length() == 1 && IsAsciiAlpha(aToken.First())) {
        mMaybeDriveLetter = true;

        mPathnameComponents.AppendElement(aToken);

        mState = mTokenizer.hasMoreTokens()
                     ? eExpectingEmptyTokenOrPathnameComponent
                     : eComplete;

        return;
      }

      HandlePathnameComponent(aToken);

      return;
    }

    case eExpectingEmptyTokenOrPathnameComponent: {
      MOZ_ASSERT(mSchemeType == eFile);

      if (aToken.IsEmpty()) {
        if (mMaybeDriveLetter) {
          MOZ_ASSERT(mPathnameComponents.Length() == 1);

          nsCString& pathnameComponent = mPathnameComponents[0];
          pathnameComponent.Append(':');

          mMaybeDriveLetter = false;
        } else {
          mPathnameComponents.AppendElement(""_ns);
        }

        mState = mTokenizer.hasMoreTokens()
                     ? eExpectingEmptyTokenOrPathnameComponent
                     : eComplete;

        return;
      }

      HandlePathnameComponent(aToken);

      return;
    }

    case eExpectingEmptyToken1OrHost: {
      MOZ_ASSERT(mSchemeType == eAbout &&
                 mScheme.EqualsLiteral("moz-safe-about"));

      if (aToken.IsEmpty()) {
        mState = eExpectingEmptyToken2;
      } else {
        mHost = aToken;
        mState = mTokenizer.hasMoreTokens() ? eExpectingPort : eComplete;
      }

      return;
    }

    case eExpectingIPV6Token: {
      // A safe check for preventing infinity recursion.
      if (++mIPGroup > 8) {
        mError = true;
        return;
      }

      mHost.AppendLiteral(":");
      mHost.Append(aToken);
      if (!aToken.IsEmpty() && aToken.Last() == ']') {
        mState = mTokenizer.hasMoreTokens() ? eExpectingPort : eComplete;
      }

      return;
    }

    default:
      MOZ_CRASH("Should never get here!");
  }
}

void OriginParser::HandleTrailingSeparator() {
  MOZ_ASSERT(mState == eComplete);
  MOZ_ASSERT(mSchemeType == eFile);

  mPathnameComponents.AppendElement(""_ns);

  mState = eHandledTrailingSeparator;
}

bool IsUUIDOrigin(const nsCString& aOrigin) {
  if (!StringBeginsWith(aOrigin, kUUIDOriginScheme)) {
    return false;
  }

  static const std::regex pattern(
      "^uuid://[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab"
      "][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$");

  return regex_match(aOrigin.get(), pattern);
}

bool IsUserContextSuffix(const nsACString& aSuffix, uint32_t aUserContextId) {
  OriginAttributes originAttributes;
  MOZ_ALWAYS_TRUE(originAttributes.PopulateFromSuffix(aSuffix));
  return originAttributes.mUserContextId == aUserContextId;
}

bool IsUserContextPattern(const OriginAttributesPattern& aPattern,
                          uint32_t aUserContextId) {
  const auto& userContextId = aPattern.mUserContextId;

  if (!userContextId.WasPassed()) {
    return false;
  }

  return userContextId.Value() == aUserContextId;
}

}  // namespace mozilla::dom::quota

Messung V0.5
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.