From 7be3f7659503c50b7ae9c9b8016d8e3ea84b8d23 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 23 Mar 2018 17:17:32 -0400 Subject: [PATCH 01/22] bug 1353296 - get rid of filter_upload_symbols. r=dustin filter_upload_symbols is a relic of task configurations that were written before we had a better handle on taskgraph generation. We should only be uploading symbols for nightly builds anyway, so this is better served using newer filtering methods. upload-symbols tasks were specified to run on non-nightly build types in the kind.yml, but those were filtered out in filter_upload_symbols. I believe these were simply an artifact of the initial upload-symbols implementation happening before nightly builds were running in Taskcluster. MozReview-Commit-ID: Je1NytrVPT8 --HG-- extra : rebase_source : a961c17d329af848fa7bb64c5186135d37dd412f --- taskcluster/ci/upload-symbols/kind.yml | 19 ++----------------- taskcluster/taskgraph/target_tasks.py | 10 +--------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/taskcluster/ci/upload-symbols/kind.yml b/taskcluster/ci/upload-symbols/kind.yml index e1a6e93dac30..eb6cd303c3ee 100644 --- a/taskcluster/ci/upload-symbols/kind.yml +++ b/taskcluster/ci/upload-symbols/kind.yml @@ -12,23 +12,8 @@ transforms: kind-dependencies: - build -only-for-build-platforms: - - linux64/opt - - linux64/debug - - linux64-nightly/opt - - linux-nightly/opt - - linux64-devedition-nightly/opt - - linux-devedition-nightly/opt - - android-aarch64-nightly/opt - - android-api-16/opt - - android-api-16-nightly/opt - - android-x86-nightly/opt - - macosx64-nightly/opt - - macosx64-devedition-nightly/opt - - win32-nightly/opt - - win64-nightly/opt - - win32-devedition-nightly/opt - - win64-devedition-nightly/opt +only-for-attributes: + - nightly job-template: description: Upload Symbols diff --git a/taskcluster/taskgraph/target_tasks.py b/taskcluster/taskgraph/target_tasks.py index 6b97aa2fed29..cc70ed56467c 100644 --- a/taskcluster/taskgraph/target_tasks.py +++ b/taskcluster/taskgraph/target_tasks.py @@ -40,14 +40,6 @@ def filter_on_platforms(task, platforms): return (platform in platforms) -def filter_upload_symbols(task, parameters): - # Filters out symbols when there are not part of a nightly or a release build - # TODO Remove this too specific filter (bug 1353296) - return '-upload-symbols' not in task.label or \ - task.attributes.get('nightly') or \ - parameters.get('project') in ('mozilla-beta', 'mozilla-release') - - def filter_beta_release_tasks(task, parameters, ignore_kinds=None, allow_l10n=False): if not standard_filter(task, parameters): return False @@ -94,7 +86,7 @@ def filter_beta_release_tasks(task, parameters, ignore_kinds=None, allow_l10n=Fa def standard_filter(task, parameters): return all( filter_func(task, parameters) for filter_func in - (filter_out_nightly, filter_for_project, filter_upload_symbols) + (filter_out_nightly, filter_for_project) ) From ee4ed687a36cffcb0b9e87f32cc11e05e2d637a2 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 28 Feb 2018 06:28:01 -0500 Subject: [PATCH 02/22] bug 1437577 - Upload symbols from try server builds to symbols.mozilla.org instead of symbols.stage.mozaws.net. r=peterbe The symbol server recently gained the ability to upload symbols from try to a different prefix in the symbols bucket. If we change the token stored in the Taskcluster secret `project/releng/gecko/build/level-1/gecko-symbol-upload` to one that has only "upload try symbols" permissions then we can upload symbols from try server builds directly to symbols.mo. MozReview-Commit-ID: HjQclKKXbA3 --HG-- extra : rebase_source : 8afed0bf52565bad513c30a7d5de274b356d6d84 --- toolkit/crashreporter/tools/upload_symbols.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/toolkit/crashreporter/tools/upload_symbols.py b/toolkit/crashreporter/tools/upload_symbols.py index 91ca0d05cd69..98e2e8f52ed5 100644 --- a/toolkit/crashreporter/tools/upload_symbols.py +++ b/toolkit/crashreporter/tools/upload_symbols.py @@ -92,10 +92,6 @@ def main(): # Allow overwriting of the upload url with an environmental variable if 'SOCORRO_SYMBOL_UPLOAD_URL' in os.environ: url = os.environ['SOCORRO_SYMBOL_UPLOAD_URL'] - elif os.environ.get('MOZ_SCM_LEVEL', '1') == '1': - # Use the Tecken staging server for try uploads for now. - # This will eventually be changed in bug 1138617. - url = 'https://symbols.stage.mozaws.net/upload/' else: url = DEFAULT_URL From 666e28db6e6687dcfaae929aa3a9452b4ad69a28 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 12 Apr 2018 11:50:23 -0400 Subject: [PATCH 03/22] bug 1437577 - preserve treeherder.platform from job into task. r=dustin Tasks like upload-symbols that have a dependency on a build job want to copy the treeherder.platform from the build job but it gets lost in the task transform currently. This simply copies it into an extra.treeherder-platform key to make life easier. MozReview-Commit-ID: H4PtC4mvIYA --HG-- extra : rebase_source : 5588bdadfcff8eb8f35935dc5c05dcde5658da83 --- taskcluster/taskgraph/transforms/task.py | 1 + 1 file changed, 1 insertion(+) diff --git a/taskcluster/taskgraph/transforms/task.py b/taskcluster/taskgraph/transforms/task.py index c551c38164ce..7413a744b3db 100644 --- a/taskcluster/taskgraph/transforms/task.py +++ b/taskcluster/taskgraph/transforms/task.py @@ -1473,6 +1473,7 @@ def build_task(config, tasks): extra['parent'] = os.environ.get('TASK_ID', '') task_th = task.get('treeherder') if task_th: + extra.setdefault('treeherder-platform', task_th['platform']) treeherder = extra.setdefault('treeherder', {}) machine_platform, collection = task_th['platform'].split('/', 1) From 1120b5bb3e9b16b060b6cce275443ebde89872c6 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 12 Apr 2018 08:49:43 -0400 Subject: [PATCH 04/22] bug 1437577 - allow uploading symbols from any build type on try. r=dustin Previously we would only generate upload-symbols tasks for nightly builds, since we only want to upload symbols for builds we ship to users. On try, developers may want to use the symbol server but very rarely want to do nightly builds, so allow uploading symbols from any build type there. MozReview-Commit-ID: IYs9mZii3DN --HG-- extra : rebase_source : 15acb889510bb07ed3d29ea802997f11796dad9f --- taskcluster/ci/upload-symbols/kind.yml | 8 ++++---- .../taskgraph/transforms/upload_symbols.py | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/taskcluster/ci/upload-symbols/kind.yml b/taskcluster/ci/upload-symbols/kind.yml index eb6cd303c3ee..fe2e02ba78d2 100644 --- a/taskcluster/ci/upload-symbols/kind.yml +++ b/taskcluster/ci/upload-symbols/kind.yml @@ -12,9 +12,6 @@ transforms: kind-dependencies: - build -only-for-attributes: - - nightly - job-template: description: Upload Symbols worker-type: aws-provisioner-v1/gecko-{level}-b-linux @@ -38,4 +35,7 @@ job-template: run-on-projects: by-build-platform: .*devedition.*: ['mozilla-beta', 'maple'] - default: ['all'] + # Only upload symbols for nightlies on most branches. + .*(? Date: Mon, 7 May 2018 16:33:33 -0400 Subject: [PATCH 05/22] Bug 1432067 - Ignore zero sized tables. r=jrmuizel --- gfx/qcms/iccread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/qcms/iccread.c b/gfx/qcms/iccread.c index 5e6836f82523..1a921ba7133a 100644 --- a/gfx/qcms/iccread.c +++ b/gfx/qcms/iccread.c @@ -606,7 +606,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag // 24bits * 3 won't overflow either clut_size = clut_size * num_out_channels; - if (clut_size > MAX_CLUT_SIZE) + if (clut_size == 0 || clut_size > MAX_CLUT_SIZE) return NULL; lut = malloc(sizeof(struct lutmABType) + (clut_size) * sizeof(float)); From 54b1b3b99d30333629126287f69fa4312c74fc19 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 19 Apr 2018 17:22:41 -0600 Subject: [PATCH 06/22] Bug 1457999: Part 1 - Move command line argument utils and safe mode checks into a common header file; r=jimm --- toolkit/xre/CmdLineAndEnvUtils.h | 390 ++++++++++++++++++ toolkit/xre/PolicyChecks.h | 46 +++ toolkit/xre/SafeMode.h | 93 +++++ toolkit/xre/moz.build | 8 +- toolkit/xre/nsAppRunner.cpp | 258 ++---------- toolkit/xre/nsWindowsRestart.cpp | 139 +------ .../test/win/TestXREMakeCommandLineWin.cpp | 14 +- 7 files changed, 574 insertions(+), 374 deletions(-) create mode 100644 toolkit/xre/CmdLineAndEnvUtils.h create mode 100644 toolkit/xre/PolicyChecks.h create mode 100644 toolkit/xre/SafeMode.h diff --git a/toolkit/xre/CmdLineAndEnvUtils.h b/toolkit/xre/CmdLineAndEnvUtils.h new file mode 100644 index 000000000000..3222baeee10a --- /dev/null +++ b/toolkit/xre/CmdLineAndEnvUtils.h @@ -0,0 +1,390 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_CmdLineAndEnvUtils_h +#define mozilla_CmdLineAndEnvUtils_h + +// NB: This code may be used outside of xul and thus must not depend on XPCOM + +#if defined(MOZILLA_INTERNAL_API) +#include "prenv.h" +#include "prprf.h" +#include +#elif defined(XP_WIN) +#include +#endif + +#if defined(XP_WIN) +#include "mozilla/Move.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" + +#include +#endif // defined(XP_WIN) + +#include "mozilla/TypedEnumBits.h" + +#include +#include + +// Undo X11/X.h's definition of None +#undef None + +namespace mozilla { + +enum ArgResult { + ARG_NONE = 0, + ARG_FOUND = 1, + ARG_BAD = 2 // you wanted a param, but there isn't one +}; + +template +inline void +RemoveArg(int& argc, CharT **argv) +{ + do { + *argv = *(argv + 1); + ++argv; + } while (*argv); + + --argc; +} + +namespace internal { + +template +inline bool +strimatch(FuncT aToLowerFn, const CharT* lowerstr, const CharT* mixedstr) +{ + while(*lowerstr) { + if (!*mixedstr) return false; // mixedstr is shorter + if (static_cast(aToLowerFn(*mixedstr)) != *lowerstr) return false; // no match + + ++lowerstr; + ++mixedstr; + } + + if (*mixedstr) return false; // lowerstr is shorter + + return true; +} + +} // namespace internal + +inline bool +strimatch(const char* lowerstr, const char* mixedstr) +{ + return internal::strimatch(&tolower, lowerstr, mixedstr); +} + +inline bool +strimatch(const wchar_t* lowerstr, const wchar_t* mixedstr) +{ + return internal::strimatch(&towlower, lowerstr, mixedstr); +} + +enum class FlagLiteral +{ + osint, + safemode +}; + +template +inline const CharT* GetLiteral(); + +#define DECLARE_FLAG_LITERAL(enum_name, literal) \ + template <> inline \ + const char* GetLiteral() \ + { \ + return literal; \ + } \ + \ + template <> inline \ + const wchar_t* GetLiteral() \ + { \ + return L##literal; \ + } + +DECLARE_FLAG_LITERAL(osint, "osint") +DECLARE_FLAG_LITERAL(safemode, "safe-mode") + +enum class CheckArgFlag : uint32_t +{ + None = 0, + CheckOSInt = (1 << 0), // Retrun ARG_BAD if osint arg is also present. + RemoveArg = (1 << 1) // Remove the argument from the argv array. +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CheckArgFlag) + +/** + * Check for a commandline flag. If the flag takes a parameter, the + * parameter is returned in aParam. Flags may be in the form -arg or + * --arg (or /arg on win32). + * + * @param aArgc The argc value. + * @param aArgv The original argv. + * @param aArg the parameter to check. Must be lowercase. + * @param aParam if non-null, the -arg will be stored in this pointer. + * This is *not* allocated, but rather a pointer to the argv data. + * @param aFlags Flags @see CheckArgFlag + */ +template +inline ArgResult +CheckArg(int& aArgc, CharT** aArgv, const CharT* aArg, const CharT **aParam, + CheckArgFlag aFlags) +{ + MOZ_ASSERT(aArgv && aArg); + + CharT **curarg = aArgv + 1; // skip argv[0] + ArgResult ar = ARG_NONE; + + while (*curarg) { + CharT *arg = curarg[0]; + + if (arg[0] == '-' +#if defined(XP_WIN) + || *arg == '/' +#endif + ) { + ++arg; + + if (*arg == '-') { + ++arg; + } + + if (strimatch(aArg, arg)) { + if (aFlags & CheckArgFlag::RemoveArg) { + RemoveArg(aArgc, curarg); + } else { + ++curarg; + } + + if (!aParam) { + ar = ARG_FOUND; + break; + } + + if (*curarg) { + if (**curarg == '-' +#if defined(XP_WIN) + || **curarg == '/' +#endif + ) { + return ARG_BAD; + } + + *aParam = *curarg; + + if (aFlags & CheckArgFlag::RemoveArg) { + RemoveArg(aArgc, curarg); + } + + ar = ARG_FOUND; + break; + } + + return ARG_BAD; + } + } + + ++curarg; + } + + if ((aFlags & CheckArgFlag::CheckOSInt) && ar == ARG_FOUND) { + ArgResult arOSInt = CheckArg(aArgc, aArgv, + GetLiteral(), + static_cast(nullptr), + CheckArgFlag::None); + if (arOSInt == ARG_FOUND) { + ar = ARG_BAD; +#if defined(MOZILLA_INTERNAL_API) + PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n"); +#endif // defined(MOZILLA_INTERNAL_API) + } + } + + return ar; +} + +#if defined(XP_WIN) + +namespace internal { + +/** + * Get the length that the string will take and takes into account the + * additional length if the string needs to be quoted and if characters need to + * be escaped. + */ +inline int +ArgStrLen(const wchar_t *s) +{ + int backslashes = 0; + int i = wcslen(s); + bool hasDoubleQuote = wcschr(s, L'"') != nullptr; + // Only add doublequotes if the string contains a space or a tab + bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; + + if (addDoubleQuotes) { + i += 2; // initial and final duoblequote + } + + if (hasDoubleQuote) { + while (*s) { + if (*s == '\\') { + ++backslashes; + } else { + if (*s == '"') { + // Escape the doublequote and all backslashes preceding the doublequote + i += backslashes + 1; + } + + backslashes = 0; + } + + ++s; + } + } + + return i; +} + +/** + * Copy string "s" to string "d", quoting the argument as appropriate and + * escaping doublequotes along with any backslashes that immediately precede + * doublequotes. + * The CRT parses this to retrieve the original argc/argv that we meant, + * see STDARGV.C in the MSVC CRT sources. + * + * @return the end of the string + */ +inline wchar_t* +ArgToString(wchar_t *d, const wchar_t *s) +{ + int backslashes = 0; + bool hasDoubleQuote = wcschr(s, L'"') != nullptr; + // Only add doublequotes if the string contains a space or a tab + bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; + + if (addDoubleQuotes) { + *d = '"'; // initial doublequote + ++d; + } + + if (hasDoubleQuote) { + int i; + while (*s) { + if (*s == '\\') { + ++backslashes; + } else { + if (*s == '"') { + // Escape the doublequote and all backslashes preceding the doublequote + for (i = 0; i <= backslashes; ++i) { + *d = '\\'; + ++d; + } + } + + backslashes = 0; + } + + *d = *s; + ++d; ++s; + } + } else { + wcscpy(d, s); + d += wcslen(s); + } + + if (addDoubleQuotes) { + *d = '"'; // final doublequote + ++d; + } + + return d; +} + +} // namespace internal + +/** + * Creates a command line from a list of arguments. + */ +inline UniquePtr +MakeCommandLine(int argc, wchar_t **argv) +{ + int i; + int len = 0; + + // The + 1 of the last argument handles the allocation for null termination + for (i = 0; i < argc; ++i) { + len += internal::ArgStrLen(argv[i]) + 1; + } + + // Protect against callers that pass 0 arguments + if (len == 0) { + len = 1; + } + + auto s = MakeUnique(len); + if (!s) { + return nullptr; + } + + wchar_t *c = s.get(); + for (i = 0; i < argc; ++i) { + c = internal::ArgToString(c, argv[i]); + if (i + 1 != argc) { + *c = ' '; + ++c; + } + } + + *c = '\0'; + + return Move(s); +} + +#endif // defined(XP_WIN) + +// Save literal putenv string to environment variable. +inline void +SaveToEnv(const char *aEnvString) +{ +#if defined(MOZILLA_INTERNAL_API) + char *expr = strdup(aEnvString); + if (expr) { + PR_SetEnv(expr); + } + + // We intentionally leak |expr| here since it is required by PR_SetEnv. + MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr); +#elif defined(XP_WIN) + // This is the same as the NSPR implementation + // (Note that we don't need to do a strdup for this case; the CRT makes a copy) + _putenv(aEnvString); +#else +#error "Not implemented for this configuration" +#endif +} + +inline bool +EnvHasValue(const char* aVarName) +{ +#if defined(MOZILLA_INTERNAL_API) + const char* val = PR_GetEnv(aVarName); + return val && *val; +#elif defined(XP_WIN) + // This is the same as the NSPR implementation + const char* val = getenv(aVarName); + return val && *val; +#else +#error "Not implemented for this configuration" +#endif +} + +} // namespace mozilla + +#endif // mozilla_CmdLineAndEnvUtils_h diff --git a/toolkit/xre/PolicyChecks.h b/toolkit/xre/PolicyChecks.h new file mode 100644 index 000000000000..5a93153c1ea6 --- /dev/null +++ b/toolkit/xre/PolicyChecks.h @@ -0,0 +1,46 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_PolicyChecks_h +#define mozilla_PolicyChecks_h + +#if defined(XP_WIN) + +#include + +// NB: This code must be able to run apart from XPCOM + +namespace mozilla { + +inline bool +PolicyHasRegValue(HKEY aKey, LPCWSTR aName, DWORD* aValue) +{ + DWORD len = sizeof(DWORD); + LONG ret = ::RegGetValueW(aKey, L"SOFTWARE\\Policies\\Mozilla\\Firefox", aName, + RRF_RT_DWORD, nullptr, aValue, &len); + return ret == ERROR_SUCCESS; +} + +inline bool +PolicyCheckBoolean(LPCWSTR aPolicyName) +{ + DWORD value; + if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, aPolicyName, &value)) { + return value == 1; + } + + if (PolicyHasRegValue(HKEY_CURRENT_USER, aPolicyName, &value)) { + return value == 1; + } + + return false; +} + +} // namespace mozilla + +#endif // defined(XP_WIN) + +#endif // mozilla_PolicyChecks_h diff --git a/toolkit/xre/SafeMode.h b/toolkit/xre/SafeMode.h new file mode 100644 index 000000000000..2c4aa978473b --- /dev/null +++ b/toolkit/xre/SafeMode.h @@ -0,0 +1,93 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_SafeMode_h +#define mozilla_SafeMode_h + +// NB: This code must be able to run apart from XPCOM + +#include "mozilla/CmdLineAndEnvUtils.h" +#include "mozilla/Maybe.h" + +#if defined(XP_WIN) +#include "mozilla/PolicyChecks.h" +#include +#endif // defined(XP_WIN) + +// Undo X11/X.h's definition of None +#undef None + +namespace mozilla { + +enum class SafeModeFlag : uint32_t +{ + None = 0, + Unset = (1 << 0) +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SafeModeFlag) + +template +inline Maybe +IsSafeModeRequested(int& aArgc, CharT* aArgv[], + const SafeModeFlag aFlags = SafeModeFlag::Unset) +{ + CheckArgFlag checkArgFlags = CheckArgFlag::CheckOSInt; + if (aFlags & SafeModeFlag::Unset) { + checkArgFlags |= CheckArgFlag::RemoveArg; + } + + ArgResult ar = CheckArg(aArgc, aArgv, + GetLiteral(), + static_cast(nullptr), + checkArgFlags); + if (ar == ARG_BAD) { + return Nothing(); + } + + bool result = ar == ARG_FOUND; + +#if defined(XP_WIN) + // If the shift key is pressed and the ctrl and / or alt keys are not pressed + // during startup, start in safe mode. GetKeyState returns a short and the high + // order bit will be 1 if the key is pressed. By masking the returned short + // with 0x8000 the result will be 0 if the key is not pressed and non-zero + // otherwise. + if ((GetKeyState(VK_SHIFT) & 0x8000) && + !(GetKeyState(VK_CONTROL) & 0x8000) && + !(GetKeyState(VK_MENU) & 0x8000) && + !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) { + result = true; + } + + if (result && PolicyCheckBoolean(L"DisableSafeMode")) { + result = false; + } +#endif // defined(XP_WIN) + +#if defined(XP_MACOSX) + if ((GetCurrentEventKeyModifiers() & optionKey) && + !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) { + result = true; + } +#endif // defined(XP_MACOSX) + + // The Safe Mode Policy should not be enforced for the env var case + // (used by updater and crash-recovery). + if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) { + result = true; + if (aFlags & SafeModeFlag::Unset) { + // unset the env variable + SaveToEnv("MOZ_SAFE_MODE_RESTART="); + } + } + + return Some(result); +} + +} // namespace mozilla + +#endif // mozilla_SafeMode_h diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index b7bf67ac25e0..431b98917e62 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -30,13 +30,19 @@ EXPORTS += [ 'nsIAppStartupNotifier.h', ] -EXPORTS.mozilla += ['AutoSQLiteLifetime.h', 'Bootstrap.h'] +EXPORTS.mozilla += [ + 'AutoSQLiteLifetime.h', + 'Bootstrap.h', + 'CmdLineAndEnvUtils.h', + 'SafeMode.h', +] if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']: EXPORTS += ['EventTracer.h'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXPORTS.mozilla += [ + 'PolicyChecks.h', 'WinDllServices.h', ] SOURCES += [ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 9b33cc51fb46..c6f2ba2986ed 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -10,6 +10,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/ChaosMode.h" +#include "mozilla/CmdLineAndEnvUtils.h" #include "mozilla/IOInterposer.h" #include "mozilla/Likely.h" #include "mozilla/MemoryChecking.h" @@ -232,6 +233,7 @@ #endif #include "mozilla/mozalloc_oom.h" +#include "SafeMode.h" extern uint32_t gRestartMode; extern void InstallSignalHandlers(const char *ProgramName); @@ -306,25 +308,6 @@ using mozilla::dom::ContentParent; using mozilla::dom::ContentChild; using mozilla::intl::LocaleService; -// Save literal putenv string to environment variable. -static void -SaveToEnv(const char *putenv) -{ - char *expr = strdup(putenv); - if (expr) - PR_SetEnv(expr); - // We intentionally leak |expr| here since it is required by PR_SetEnv. - MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr); -} - -// Tests that an environment variable exists and has a value -static bool -EnvHasValue(const char *name) -{ - const char *val = PR_GetEnv(name); - return (val && *val); -} - // Save the given word to the specified environment variable. static void SaveWordToEnv(const char *name, const nsACString & word) @@ -400,22 +383,6 @@ SaveFileToEnvIfUnset(const char *name, nsIFile *file) SaveFileToEnv(name, file); } -static bool -strimatch(const char* lowerstr, const char* mixedstr) -{ - while(*lowerstr) { - if (!*mixedstr) return false; // mixedstr is shorter - if (tolower(*mixedstr) != *lowerstr) return false; // no match - - ++lowerstr; - ++mixedstr; - } - - if (*mixedstr) return false; // lowerstr is shorter - - return true; -} - static bool gIsExpectedExit = false; void MozExpectedExit() { @@ -482,94 +449,22 @@ enum RemoteResult { REMOTE_ARG_BAD = 2 }; -enum ArgResult { - ARG_NONE = 0, - ARG_FOUND = 1, - ARG_BAD = 2 // you wanted a param, but there isn't one -}; - -static void RemoveArg(char **argv) -{ - do { - *argv = *(argv + 1); - ++argv; - } while (*argv); - - --gArgc; -} - /** * Check for a commandline flag. If the flag takes a parameter, the * parameter is returned in aParam. Flags may be in the form -arg or * --arg (or /arg on win32). * * @param aArg the parameter to check. Must be lowercase. - * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present - * when aArg is also present. * @param aParam if non-null, the -arg will be stored in this pointer. * This is *not* allocated, but rather a pointer to the argv data. - * @param aRemArg if true, the argument is removed from the gArgv array. + * @param aFlags flags @see CheckArgFlag */ static ArgResult -CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true) +CheckArg(const char* aArg, const char** aParam = nullptr, + CheckArgFlag aFlags = CheckArgFlag::RemoveArg) { MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()"); - - char **curarg = gArgv + 1; // skip argv[0] - ArgResult ar = ARG_NONE; - - while (*curarg) { - char *arg = curarg[0]; - - if (arg[0] == '-' -#if defined(XP_WIN) - || *arg == '/' -#endif - ) { - ++arg; - if (*arg == '-') - ++arg; - - if (strimatch(aArg, arg)) { - if (aRemArg) - RemoveArg(curarg); - else - ++curarg; - if (!aParam) { - ar = ARG_FOUND; - break; - } - - if (*curarg) { - if (**curarg == '-' -#if defined(XP_WIN) - || **curarg == '/' -#endif - ) - return ARG_BAD; - - *aParam = *curarg; - if (aRemArg) - RemoveArg(curarg); - ar = ARG_FOUND; - break; - } - return ARG_BAD; - } - } - - ++curarg; - } - - if (aCheckOSInt && ar == ARG_FOUND) { - ArgResult arOSInt = CheckArg("osint"); - if (arOSInt == ARG_FOUND) { - ar = ARG_BAD; - PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n"); - } - } - - return ar; + return CheckArg(gArgc, gArgv, aArg, aParam, aFlags); } /** @@ -582,38 +477,7 @@ CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullp static ArgResult CheckArgExists(const char* aArg) { - char **curarg = gArgv + 1; // skip argv[0] - while (*curarg) { - char *arg = curarg[0]; - - if (arg[0] == '-' -#if defined(XP_WIN) - || *arg == '/' -#endif - ) { - ++arg; - if (*arg == '-') - ++arg; - - char delimiter = '='; -#if defined(XP_WIN) - delimiter = ':'; -#endif - int i; - for (i = 0; arg[i] && arg[i] != delimiter; i++) {} - char tmp = arg[i]; - arg[i] = '\0'; - bool found = strimatch(aArg, arg); - arg[i] = tmp; - if (found) { - return ARG_FOUND; - } - } - - ++curarg; - } - - return ARG_NONE; + return CheckArg(aArg, nullptr, CheckArgFlag::None); } #if defined(XP_WIN) @@ -1799,14 +1663,14 @@ ParseRemoteCommandLine(nsCString& program, { ArgResult ar; - ar = CheckArg("p", false, profile, false); + ar = CheckArg("p", profile, CheckArgFlag::None); if (ar == ARG_BAD) { // Leave it to the normal command line handling to handle this situation. return REMOTE_NOT_FOUND; } const char *temp = nullptr; - ar = CheckArg("a", true, &temp); + ar = CheckArg("a", &temp, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); return REMOTE_ARG_BAD; @@ -1815,7 +1679,7 @@ ParseRemoteCommandLine(nsCString& program, program.Assign(temp); } - ar = CheckArg("u", true, username); + ar = CheckArg("u", username, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); return REMOTE_ARG_BAD; @@ -2322,7 +2186,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n *aResult = nullptr; *aStartOffline = false; - ar = CheckArg("offline", true); + ar = CheckArg("offline", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --offline is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -2344,7 +2208,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n } // reset-profile and migration args need to be checked before any profiles are chosen below. - ar = CheckArg("reset-profile", true); + ar = CheckArg("reset-profile", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --reset-profile is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -2353,7 +2217,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n gDoProfileReset = true; } - ar = CheckArg("migration", true); + ar = CheckArg("migration", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --migration is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -2380,8 +2244,8 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n // Clear out flags that we handled (or should have handled!) last startup. const char *dummy; - CheckArg("p", false, &dummy); - CheckArg("profile", false, &dummy); + CheckArg("p", &dummy); + CheckArg("profile", &dummy); CheckArg("profilemanager"); if (gDoProfileReset) { @@ -2410,7 +2274,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return NS_LockProfilePath(lf, localDir, nullptr, aResult); } - ar = CheckArg("profile", true, &arg); + ar = CheckArg("profile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --profile requires a path\n"); return NS_ERROR_FAILURE; @@ -2444,7 +2308,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult); } - ar = CheckArg("createprofile", true, &arg); + ar = CheckArg("createprofile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --createprofile requires a profile name\n"); return NS_ERROR_FAILURE; @@ -2500,7 +2364,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n rv = aProfileSvc->GetProfileCount(&count); NS_ENSURE_SUCCESS(rv, rv); - ar = CheckArg("p", false, &arg); + ar = CheckArg("p", &arg); if (ar == ARG_BAD) { ar = CheckArg("osint"); if (ar == ARG_FOUND) { @@ -2565,7 +2429,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n } } - ar = CheckArg("profilemanager", true); + ar = CheckArg("profilemanager", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --profilemanager is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -3161,33 +3025,6 @@ public: #endif }; -#ifdef XP_WIN -namespace { - -bool PolicyHasRegValue(HKEY aKey, LPCWSTR aName, DWORD* aValue) -{ - DWORD len = sizeof(DWORD); - LONG ret = ::RegGetValueW(aKey, L"SOFTWARE\\Policies\\Mozilla\\Firefox", aName, - RRF_RT_DWORD, nullptr, aValue, &len); - return ret == ERROR_SUCCESS; -} - -bool SafeModeBlockedByPolicy() -{ - LPCTSTR policyName = L"DisableSafeMode"; - DWORD value; - if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, policyName, &value)) { - return value == 1; - } - if (PolicyHasRegValue(HKEY_CURRENT_USER, policyName, &value)) { - return value == 1; - } - return false; -} - -} // anonymous namespace -#endif // XP_WIN - #if defined(XP_UNIX) && !defined(ANDROID) static SmprintfPointer FormatUid(uid_t aId) @@ -3366,7 +3203,7 @@ XREMain::XRE_mainInit(bool* aExitFlag) // Check for application.ini overrides const char* override = nullptr; - ar = CheckArg("override", true, &override); + ar = CheckArg("override", &override, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { Output(true, "Incorrect number of arguments passed to --override"); return 1; @@ -3586,49 +3423,12 @@ XREMain::XRE_mainInit(bool* aExitFlag) gRestartArgv[gRestartArgc] = nullptr; - - ar = CheckArg("safe-mode", true); - if (ar == ARG_BAD) { - PR_fprintf(PR_STDERR, "Error: argument --safe-mode is invalid when argument --osint is specified\n"); + Maybe safeModeRequested = IsSafeModeRequested(gArgc, gArgv); + if (!safeModeRequested) { return 1; } - if (ar == ARG_FOUND) { - gSafeMode = true; - } -#ifdef XP_WIN - // If the shift key is pressed and the ctrl and / or alt keys are not pressed - // during startup start in safe mode. GetKeyState returns a short and the high - // order bit will be 1 if the key is pressed. By masking the returned short - // with 0x8000 the result will be 0 if the key is not pressed and non-zero - // otherwise. - if ((GetKeyState(VK_SHIFT) & 0x8000) && - !(GetKeyState(VK_CONTROL) & 0x8000) && - !(GetKeyState(VK_MENU) & 0x8000) && - !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) { - gSafeMode = true; - } -#endif - -#ifdef XP_MACOSX - if ((GetCurrentEventKeyModifiers() & optionKey) && - !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) - gSafeMode = true; -#endif - -#ifdef XP_WIN -if (gSafeMode && SafeModeBlockedByPolicy()) { - gSafeMode = false; - } -#endif - - // The Safe Mode Policy should not be enforced for the env var case - // (used by updater and crash-recovery). - if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) { - gSafeMode = true; - // unset the env variable - SaveToEnv("MOZ_SAFE_MODE_RESTART="); - } + gSafeMode = safeModeRequested.value(); #ifdef XP_WIN { @@ -3681,7 +3481,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) { // Handle --no-remote and --new-instance command line arguments. Setup // the environment to better accommodate other components and various // restart scenarios. - ar = CheckArg("no-remote", true); + ar = CheckArg("no-remote", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --no-remote is invalid when argument --osint is specified\n"); return 1; @@ -3690,7 +3490,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) { SaveToEnv("MOZ_NO_REMOTE=1"); } - ar = CheckArg("new-instance", true); + ar = CheckArg("new-instance", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --new-instance is invalid when argument --osint is specified\n"); return 1; @@ -3717,7 +3517,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) { NS_ENSURE_SUCCESS(rv, 1); // Check for --register, which registers chrome and then exits immediately. - ar = CheckArg("register", true); + ar = CheckArg("register", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --register is invalid when argument --osint is specified\n"); return 1; @@ -4253,7 +4053,7 @@ XREMain::XRE_mainStartup(bool* aExitFlag) // to make sure that the maintenance service successfully launches the // callback application. const char *logFile = nullptr; - if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) { + if (ARG_FOUND == CheckArg("dump-args", &logFile)) { FILE* logFP = fopen(logFile, "wb"); if (logFP) { for (int i = 1; i < gRestartArgc; ++i) { @@ -5108,7 +4908,7 @@ XRE_InitCommandLine(int aArgc, char* aArgv[]) #endif const char *path = nullptr; - ArgResult ar = CheckArg("greomni", false, &path); + ArgResult ar = CheckArg("greomni", &path); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --greomni requires a path argument\n"); return NS_ERROR_FAILURE; @@ -5124,7 +4924,7 @@ XRE_InitCommandLine(int aArgc, char* aArgv[]) return rv; } - ar = CheckArg("appomni", false, &path); + ar = CheckArg("appomni", &path); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --appomni requires a path argument\n"); return NS_ERROR_FAILURE; diff --git a/toolkit/xre/nsWindowsRestart.cpp b/toolkit/xre/nsWindowsRestart.cpp index 11a654f34c92..7fa3b0de7e66 100644 --- a/toolkit/xre/nsWindowsRestart.cpp +++ b/toolkit/xre/nsWindowsRestart.cpp @@ -11,6 +11,7 @@ #define nsWindowsRestart_cpp #endif +#include "mozilla/CmdLineAndEnvUtils.h" #include "nsUTF8Utils.h" #include @@ -19,135 +20,6 @@ #include #pragma comment(lib, "userenv.lib") -/** - * Get the length that the string will take and takes into account the - * additional length if the string needs to be quoted and if characters need to - * be escaped. - */ -static int ArgStrLen(const wchar_t *s) -{ - int backslashes = 0; - int i = wcslen(s); - BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr; - // Only add doublequotes if the string contains a space or a tab - BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; - - if (addDoubleQuotes) { - i += 2; // initial and final duoblequote - } - - if (hasDoubleQuote) { - while (*s) { - if (*s == '\\') { - ++backslashes; - } else { - if (*s == '"') { - // Escape the doublequote and all backslashes preceding the doublequote - i += backslashes + 1; - } - - backslashes = 0; - } - - ++s; - } - } - - return i; -} - -/** - * Copy string "s" to string "d", quoting the argument as appropriate and - * escaping doublequotes along with any backslashes that immediately precede - * doublequotes. - * The CRT parses this to retrieve the original argc/argv that we meant, - * see STDARGV.C in the MSVC CRT sources. - * - * @return the end of the string - */ -static wchar_t* ArgToString(wchar_t *d, const wchar_t *s) -{ - int backslashes = 0; - BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr; - // Only add doublequotes if the string contains a space or a tab - BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; - - if (addDoubleQuotes) { - *d = '"'; // initial doublequote - ++d; - } - - if (hasDoubleQuote) { - int i; - while (*s) { - if (*s == '\\') { - ++backslashes; - } else { - if (*s == '"') { - // Escape the doublequote and all backslashes preceding the doublequote - for (i = 0; i <= backslashes; ++i) { - *d = '\\'; - ++d; - } - } - - backslashes = 0; - } - - *d = *s; - ++d; ++s; - } - } else { - wcscpy(d, s); - d += wcslen(s); - } - - if (addDoubleQuotes) { - *d = '"'; // final doublequote - ++d; - } - - return d; -} - -/** - * Creates a command line from a list of arguments. The returned - * string is allocated with "malloc" and should be "free"d. - * - * argv is UTF8 - */ -wchar_t* -MakeCommandLine(int argc, wchar_t **argv) -{ - int i; - int len = 0; - - // The + 1 of the last argument handles the allocation for null termination - for (i = 0; i < argc; ++i) - len += ArgStrLen(argv[i]) + 1; - - // Protect against callers that pass 0 arguments - if (len == 0) - len = 1; - - wchar_t *s = (wchar_t*) malloc(len * sizeof(wchar_t)); - if (!s) - return nullptr; - - wchar_t *c = s; - for (i = 0; i < argc; ++i) { - c = ArgToString(c, argv[i]); - if (i + 1 != argc) { - *c = ' '; - ++c; - } - } - - *c = '\0'; - - return s; -} - /** * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we * can't link to updater.exe. @@ -222,10 +94,9 @@ WinLaunchChild(const wchar_t *exePath, HANDLE userToken, HANDLE *hProcess) { - wchar_t *cl; BOOL ok; - cl = MakeCommandLine(argc, argv); + mozilla::UniquePtr cl(mozilla::MakeCommandLine(argc, argv)); if (!cl) { return FALSE; } @@ -237,7 +108,7 @@ WinLaunchChild(const wchar_t *exePath, if (userToken == nullptr) { ok = CreateProcessW(exePath, - cl, + cl.get(), nullptr, // no special security attributes nullptr, // no special thread attributes FALSE, // don't inherit filehandles @@ -256,7 +127,7 @@ WinLaunchChild(const wchar_t *exePath, ok = CreateProcessAsUserW(userToken, exePath, - cl, + cl.get(), nullptr, // no special security attributes nullptr, // no special thread attributes FALSE, // don't inherit filehandles @@ -294,7 +165,5 @@ WinLaunchChild(const wchar_t *exePath, LocalFree(lpMsgBuf); } - free(cl); - return ok; } diff --git a/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp b/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp index 00d786aa2bfc..d0c13335a2e8 100644 --- a/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp +++ b/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp @@ -69,10 +69,10 @@ verifyCmdLineCreation(wchar_t *inCmdLine, wcscat(inCmdLineNew, inCmdLine); LPWSTR *inArgv = CommandLineToArgvW(inCmdLineNew, &inArgc); - wchar_t *outCmdLine = MakeCommandLine(inArgc - 1, inArgv + 1); - wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine) + 1) * sizeof(wchar_t)); + auto outCmdLine = mozilla::MakeCommandLine(inArgc - 1, inArgv + 1); + wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine.get()) + 1) * sizeof(wchar_t)); wcscpy(outCmdLineNew, DUMMY_ARG1); - wcscat(outCmdLineNew, outCmdLine); + wcscat(outCmdLineNew, outCmdLine.get()); LPWSTR *outArgv = CommandLineToArgvW(outCmdLineNew, &outArgc); if (VERBOSE) { @@ -80,7 +80,7 @@ verifyCmdLineCreation(wchar_t *inCmdLine, wprintf(L"Verbose Output\n"); wprintf(L"--------------\n"); wprintf(L"Input command line : >%s<\n", inCmdLine); - wprintf(L"MakeComandLine output: >%s<\n", outCmdLine); + wprintf(L"MakeComandLine output: >%s<\n", outCmdLine.get()); wprintf(L"Expected command line: >%s<\n", compareCmdLine); wprintf(L"input argc : %d\n", inArgc - 1); @@ -107,7 +107,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } @@ -123,12 +122,11 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } } - isEqual = (wcscmp(outCmdLine, compareCmdLine) == 0); + isEqual = (wcscmp(outCmdLine.get(), compareCmdLine) == 0); if (!isEqual) { wprintf(L"TEST-%s-FAIL | %s | Command Line Comparison (check %2d)\n", passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); @@ -139,7 +137,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } @@ -156,7 +153,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } From c6740bdbdb5739acb4d3ba232663829695c221f7 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 19 Apr 2018 17:23:31 -0600 Subject: [PATCH 07/22] Bug 1457999: Part 2 - Update the updater and maintenance service with changes made in part 1; r=mhowell --- toolkit/components/maintenanceservice/workmonitor.cpp | 11 +++++------ toolkit/mozapps/update/updater/updater.cpp | 5 ++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/toolkit/components/maintenanceservice/workmonitor.cpp b/toolkit/components/maintenanceservice/workmonitor.cpp index 21acdcc6de9e..4da86d5c0958 100644 --- a/toolkit/components/maintenanceservice/workmonitor.cpp +++ b/toolkit/components/maintenanceservice/workmonitor.cpp @@ -14,6 +14,7 @@ #pragma comment(lib, "ole32.lib") #pragma comment(lib, "rpcrt4.lib") +#include "mozilla/CmdLineAndEnvUtils.h" #include "nsWindowsHelpers.h" #include "workmonitor.h" @@ -31,7 +32,6 @@ // Updates usually take less than a minute so this seems like a // significantly large and safe amount of time to wait. static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000; -wchar_t* MakeCommandLine(int argc, wchar_t** argv); BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode); BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, LPCWSTR newFileName); @@ -190,7 +190,7 @@ StartUpdateProcess(int argc, // The updater command line is of the form: // updater.exe update-dir apply [wait-pid [callback-dir callback-path args]] - LPWSTR cmdLine = MakeCommandLine(argc, argv); + auto cmdLine = mozilla::MakeCommandLine(argc, argv); int index = 3; if (IsOldCommandline(argc, argv)) { @@ -212,8 +212,8 @@ StartUpdateProcess(int argc, // do anything special that it needs to do for service updates. // Search in updater.cpp for more info on MOZ_USING_SERVICE. putenv(const_cast("MOZ_USING_SERVICE=1")); - LOG(("Starting service with cmdline: %ls", cmdLine)); - processStarted = CreateProcessW(argv[0], cmdLine, + LOG(("Starting service with cmdline: %ls", cmdLine.get())); + processStarted = CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, FALSE, CREATE_DEFAULT_ERROR_MODE, nullptr, @@ -279,13 +279,12 @@ StartUpdateProcess(int argc, DWORD lastError = GetLastError(); LOG_WARN(("Could not create process as current user, " "updaterPath: %ls; cmdLine: %ls. (%d)", - argv[0], cmdLine, lastError)); + argv[0], cmdLine.get(), lastError)); } // Empty value on putenv is how you remove an env variable in Windows putenv(const_cast("MOZ_USING_SERVICE=")); - free(cmdLine); return updateWasSuccessful; } diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 531f693165f7..b2a38ccc8fde 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -3104,7 +3104,7 @@ int NS_main(int argc, NS_tchar **argv) return 1; } - wchar_t *cmdLine = MakeCommandLine(argc - 1, argv + 1); + auto cmdLine = mozilla::MakeCommandLine(argc - 1, argv + 1); if (!cmdLine) { CloseHandle(elevatedFileHandle); return 1; @@ -3250,12 +3250,11 @@ int NS_main(int argc, NS_tchar **argv) SEE_MASK_NOCLOSEPROCESS; sinfo.hwnd = nullptr; sinfo.lpFile = argv[0]; - sinfo.lpParameters = cmdLine; + sinfo.lpParameters = cmdLine.get(); sinfo.lpVerb = L"runas"; sinfo.nShow = SW_SHOWNORMAL; bool result = ShellExecuteEx(&sinfo); - free(cmdLine); if (result) { WaitForSingleObject(sinfo.hProcess, INFINITE); From ff8b4c5d69e84195674e96316cd4b8a0ef4b743e Mon Sep 17 00:00:00 2001 From: Aki Sasaki Date: Mon, 7 May 2018 14:08:24 -0700 Subject: [PATCH 08/22] bug 1403548 - filter out asan on beta+release. r=catlee --HG-- extra : rebase_source : ac1f9badbe1e13d7dca43122cafb1d332830aa5b --- taskcluster/taskgraph/target_tasks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/taskcluster/taskgraph/target_tasks.py b/taskcluster/taskgraph/target_tasks.py index cc70ed56467c..c25314940adc 100644 --- a/taskcluster/taskgraph/target_tasks.py +++ b/taskcluster/taskgraph/target_tasks.py @@ -57,6 +57,8 @@ def filter_beta_release_tasks(task, parameters, ignore_kinds=None, allow_l10n=Fa # On beta, Nightly builds are already PGOs 'linux-pgo', 'linux64-pgo', 'win32-pgo', 'win64-pgo', + # ASAN is central-only + 'linux64-asan-reporter-nightly', ): return False if str(platform).startswith('android') and 'nightly' in str(platform): From a1373c8d5a71251fc47979720bd84a8c703e3ad2 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 25 Apr 2018 15:25:16 -0600 Subject: [PATCH 09/22] Bug 1451524: Switch the default interceptor VM policy over from unique to shared; r=handyman --- mozglue/misc/interceptor/VMSharingPolicies.h | 17 ++++++++++------- mozglue/misc/nsWindowsDllInterceptor.h | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/mozglue/misc/interceptor/VMSharingPolicies.h b/mozglue/misc/interceptor/VMSharingPolicies.h index 8e2dd27f72c4..05bd391c799b 100644 --- a/mozglue/misc/interceptor/VMSharingPolicies.h +++ b/mozglue/misc/interceptor/VMSharingPolicies.h @@ -9,7 +9,6 @@ #include "mozilla/Assertions.h" #include "mozilla/Types.h" -#include "mozilla/StaticPtr.h" namespace mozilla { namespace interceptor { @@ -165,7 +164,8 @@ public: return; } - MOZ_RELEASE_ASSERT(sPerProcVM->append(ProcMapEntry(aArgs...))); + bool appended = sPerProcVM->append(ProcMapEntry(aArgs...)); + MOZ_RELEASE_ASSERT(appended); } explicit operator bool() const @@ -173,7 +173,8 @@ public: AutoCriticalSection lock(&sCS); ProcMapEntry* entry; - MOZ_RELEASE_ASSERT(find(mPid, &entry)); + bool found = find(mPid, &entry); + MOZ_RELEASE_ASSERT(found); return !!entry->mVMPolicy; } @@ -183,7 +184,8 @@ public: AutoCriticalSection lock(&sCS); ProcMapEntry* entry; - MOZ_RELEASE_ASSERT(find(mPid, &entry)); + bool found = find(mPid, &entry); + MOZ_RELEASE_ASSERT(found); return entry->mVMPolicy; } @@ -241,7 +243,8 @@ public: AutoCriticalSection lock(&sCS); ProcMapEntry* entry; - MOZ_RELEASE_ASSERT(find(mPid, &entry)); + bool found = find(mPid, &entry); + MOZ_RELEASE_ASSERT(found); TrampolineCollection items(Move(entry->mVMPolicy.Items())); @@ -292,12 +295,12 @@ private: static DWORD GetPid(HANDLE aHandle) { return ::GetProcessId(aHandle); } DWORD mPid; - static StaticAutoPtr sPerProcVM; + static MapT* sPerProcVM; static CRITICAL_SECTION sCS; }; template -StaticAutoPtr::MapT> +typename VMSharingPolicyShared::MapT * VMSharingPolicyShared::sPerProcVM; template diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 36f5dbb15913..bb2ddbce8b76 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -88,7 +88,7 @@ enum }; template > class WindowsDllInterceptor final { From 415cd5e05ea551f635944a3bdfed3c62a1c8f446 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Tue, 17 Apr 2018 13:48:21 -0600 Subject: [PATCH 10/22] Bug 1454745: Skeletal bootstrap process; r=mhowell --- browser/app/LauncherProcessWin.cpp | 147 +++++++++++++++++++++++++++ browser/app/LauncherProcessWin.h | 18 ++++ browser/app/ProcThreadAttributes.h | 153 +++++++++++++++++++++++++++++ browser/app/moz.build | 3 + browser/app/nsBrowserApp.cpp | 2 + toolkit/xre/nsWindowsWMain.cpp | 13 +++ 6 files changed, 336 insertions(+) create mode 100644 browser/app/LauncherProcessWin.cpp create mode 100644 browser/app/LauncherProcessWin.h create mode 100644 browser/app/ProcThreadAttributes.h diff --git a/browser/app/LauncherProcessWin.cpp b/browser/app/LauncherProcessWin.cpp new file mode 100644 index 000000000000..ff2b3329ac29 --- /dev/null +++ b/browser/app/LauncherProcessWin.cpp @@ -0,0 +1,147 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#include "LauncherProcessWin.h" + +#include + +#include "mozilla/Attributes.h" +#include "mozilla/CmdLineAndEnvUtils.h" +#include "mozilla/Maybe.h" +#include "mozilla/SafeMode.h" +#include "mozilla/UniquePtr.h" +#include "nsWindowsHelpers.h" + +#include + +#include "ProcThreadAttributes.h" + +/** + * At this point the child process has been created in a suspended state. Any + * additional startup work (eg, blocklist setup) should go here. + * + * @return true if browser startup should proceed, otherwise false. + */ +static bool +PostCreationSetup(HANDLE aChildProcess, HANDLE aChildMainThread, + const bool aIsSafeMode) +{ + return true; +} + +/** + * Any mitigation policies that should be set on the browser process should go + * here. + */ +static void +SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs, const bool aIsSafeMode) +{ +} + +static void +ShowError(DWORD aError = ::GetLastError()) +{ + if (aError == ERROR_SUCCESS) { + return; + } + + LPWSTR rawMsgBuf = nullptr; + DWORD result = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + aError, 0, reinterpret_cast(&rawMsgBuf), + 0, nullptr); + if (!result) { + return; + } + + ::MessageBoxW(nullptr, rawMsgBuf, L"Firefox", MB_OK | MB_ICONERROR); + ::LocalFree(rawMsgBuf); +} + +namespace mozilla { + +// Eventually we want to be able to set a build config flag such that, when set, +// this function will always return true. +bool +RunAsLauncherProcess(int& argc, wchar_t** argv) +{ + return CheckArg(argc, argv, L"launcher", + static_cast(nullptr), + CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); +} + +int +LauncherMain(int argc, wchar_t* argv[]) +{ + UniquePtr cmdLine(MakeCommandLine(argc, argv)); + if (!cmdLine) { + return 1; + } + + const Maybe isSafeMode = IsSafeModeRequested(argc, argv, + SafeModeFlag::None); + if (!isSafeMode) { + ShowError(ERROR_INVALID_PARAMETER); + return 1; + } + + ProcThreadAttributes attrs; + SetMitigationPolicies(attrs, isSafeMode.value()); + + HANDLE stdHandles[] = { + ::GetStdHandle(STD_INPUT_HANDLE), + ::GetStdHandle(STD_OUTPUT_HANDLE), + ::GetStdHandle(STD_ERROR_HANDLE) + }; + + attrs.AddInheritableHandles(stdHandles); + + DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; + + STARTUPINFOEXW siex; + Maybe attrsOk = attrs.AssignTo(siex); + if (!attrsOk) { + ShowError(); + return 1; + } + + BOOL inheritHandles = FALSE; + + if (attrsOk.value()) { + creationFlags |= EXTENDED_STARTUPINFO_PRESENT; + + siex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + siex.StartupInfo.hStdInput = stdHandles[0]; + siex.StartupInfo.hStdOutput = stdHandles[1]; + siex.StartupInfo.hStdError = stdHandles[2]; + + // Since attrsOk == true, we have successfully set the handle inheritance + // whitelist policy, so only the handles added to attrs will be inherited. + inheritHandles = TRUE; + } + + PROCESS_INFORMATION pi = {}; + if (!::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, inheritHandles, + creationFlags, nullptr, nullptr, &siex.StartupInfo, &pi)) { + ShowError(); + return 1; + } + + nsAutoHandle process(pi.hProcess); + nsAutoHandle mainThread(pi.hThread); + + if (!PostCreationSetup(process.get(), mainThread.get(), isSafeMode.value()) || + ::ResumeThread(mainThread.get()) == static_cast(-1)) { + ShowError(); + ::TerminateProcess(process.get(), 1); + return 1; + } + + return 0; +} + +} // namespace mozilla diff --git a/browser/app/LauncherProcessWin.h b/browser/app/LauncherProcessWin.h new file mode 100644 index 000000000000..b198d30724f6 --- /dev/null +++ b/browser/app/LauncherProcessWin.h @@ -0,0 +1,18 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_LauncherProcessWin_h +#define mozilla_LauncherProcessWin_h + +namespace mozilla { + +bool RunAsLauncherProcess(int& argc, wchar_t* argv[]); +int LauncherMain(int argc, wchar_t* argv[]); + +} // namespace mozilla + +#endif // mozilla_LauncherProcessWin_h + diff --git a/browser/app/ProcThreadAttributes.h b/browser/app/ProcThreadAttributes.h new file mode 100644 index 000000000000..6287e15b5691 --- /dev/null +++ b/browser/app/ProcThreadAttributes.h @@ -0,0 +1,153 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ProcThreadAttributes_h +#define mozilla_ProcThreadAttributes_h + +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" + +#include + +namespace mozilla { + +class MOZ_RAII ProcThreadAttributes final +{ + struct ProcThreadAttributeListDeleter + { + void operator()(LPPROC_THREAD_ATTRIBUTE_LIST aList) + { + ::DeleteProcThreadAttributeList(aList); + delete[] reinterpret_cast(aList); + } + }; + + using ProcThreadAttributeListPtr = + UniquePtr<_PROC_THREAD_ATTRIBUTE_LIST, ProcThreadAttributeListDeleter>; + +public: + ProcThreadAttributes() + : mMitigationPolicies(0) + { + } + + ~ProcThreadAttributes() = default; + + ProcThreadAttributes(const ProcThreadAttributes&) = delete; + ProcThreadAttributes(ProcThreadAttributes&&) = delete; + ProcThreadAttributes& operator=(const ProcThreadAttributes&) = delete; + ProcThreadAttributes& operator=(ProcThreadAttributes&&) = delete; + + void AddMitigationPolicy(DWORD64 aPolicy) + { + mMitigationPolicies |= aPolicy; + } + + bool AddInheritableHandle(HANDLE aHandle) + { + return mInheritableHandles.append(aHandle); + } + + template + bool AddInheritableHandles(HANDLE (&aHandles)[N]) + { + return mInheritableHandles.append(aHandles, N); + } + + /** + * @return Some(false) if the STARTUPINFOEXW::lpAttributeList was set to null + * as expected based on the state of |this|; + * Some(true) if the STARTUPINFOEXW::lpAttributeList was set to + * non-null; + * Nothing() if something went wrong in the assignment and we should + * not proceed. + */ + Maybe AssignTo(STARTUPINFOEXW& aSiex) + { + ZeroMemory(&aSiex, sizeof(STARTUPINFOEXW)); + + // We'll set the size to sizeof(STARTUPINFOW) until we determine whether the + // extended fields will be used. + aSiex.StartupInfo.cb = sizeof(STARTUPINFOW); + + DWORD numAttributes = 0; + if (mMitigationPolicies) { + ++numAttributes; + } + + if (!mInheritableHandles.empty()) { + ++numAttributes; + } + + if (!numAttributes) { + return Some(false); + } + + SIZE_T listSize = 0; + if (!::InitializeProcThreadAttributeList(nullptr, numAttributes, 0, + &listSize) && + ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return Nothing(); + } + + auto buf = MakeUnique(listSize); + + LPPROC_THREAD_ATTRIBUTE_LIST tmpList = + reinterpret_cast(buf.get()); + + if (!::InitializeProcThreadAttributeList(tmpList, numAttributes, 0, + &listSize)) { + return Nothing(); + } + + // Transfer buf to a ProcThreadAttributeListPtr - now that the list is + // initialized, we are no longer dealing with a plain old char array. We + // must now deinitialize the attribute list before deallocating the + // underlying buffer. + ProcThreadAttributeListPtr + attrList(reinterpret_cast(buf.release())); + + if (mMitigationPolicies) { + if (!::UpdateProcThreadAttribute(attrList.get(), 0, + PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, + &mMitigationPolicies, + sizeof(mMitigationPolicies), nullptr, + nullptr)) { + return Nothing(); + } + } + + if (!mInheritableHandles.empty()) { + if (!::UpdateProcThreadAttribute(attrList.get(), 0, + PROC_THREAD_ATTRIBUTE_HANDLE_LIST, + mInheritableHandles.begin(), + mInheritableHandles.length() * sizeof(HANDLE), + nullptr, nullptr)) { + return Nothing(); + } + } + + mAttrList = Move(attrList); + aSiex.lpAttributeList = mAttrList.get(); + aSiex.StartupInfo.cb = sizeof(STARTUPINFOEXW); + return Some(true); + } + +private: + static const uint32_t kNumInline = 3; // Inline storage for the std handles + + DWORD64 mMitigationPolicies; + Vector mInheritableHandles; + ProcThreadAttributeListPtr mAttrList; +}; + +} // namespace mozilla + +#endif // mozilla_ProcThreadAttributes_h + diff --git a/browser/app/moz.build b/browser/app/moz.build index 44613bd5b5a6..2befbc57c6ce 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -62,6 +62,9 @@ if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'): if CONFIG['OS_ARCH'] == 'WINNT': RCINCLUDE = 'splash.rc' DEFINES['MOZ_PHOENIX'] = True + SOURCES += [ + 'LauncherProcessWin.cpp', + ] if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': # For sandbox includes and the include dependencies those have diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index 022fbaed4586..f9491f43137b 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -23,6 +23,8 @@ #include "nsIFile.h" #ifdef XP_WIN +#include "LauncherProcessWin.h" + #define XRE_WANT_ENVIRON #define strcasecmp _stricmp #ifdef MOZ_SANDBOX diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index 7e1ff121278c..fce792afc9c8 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -2,6 +2,9 @@ * 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/. */ +#ifndef nsWindowsWMain_cpp +#define nsWindowsWMain_cpp + // This file is a .cpp file meant to be included in nsBrowserApp.cpp and other // similar bootstrap code. It converts wide-character windows wmain into UTF-8 // narrow-character strings. @@ -101,6 +104,14 @@ int wmain(int argc, WCHAR **argv) SanitizeEnvironmentVariables(); SetDllDirectoryW(L""); + // Only run this code if LauncherProcessWin.h was included beforehand, thus + // signalling that the hosting process should support launcher mode. +#if defined(mozilla_LauncherProcessWin_h) + if (mozilla::RunAsLauncherProcess(argc, argv)) { + return mozilla::LauncherMain(argc, argv); + } +#endif // defined(mozilla_LauncherProcessWin_h) + char **argvConverted = new char*[argc + 1]; if (!argvConverted) return 127; @@ -134,3 +145,5 @@ int wmain(int argc, WCHAR **argv) return result; } + +#endif // nsWindowsWMain_cpp From 92651e3581791ed4dae9902ca59659327a706ab8 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Mon, 7 May 2018 16:17:24 -0600 Subject: [PATCH 11/22] Bug 1457999: Follow-up - update Valgrind intentional leak whitelist to reflect updated name of mozilla::SaveToEnv; r=bustage --HG-- extra : amend_source : 437cd75dc2ea3d8b3b625b7f78dbe861c3f610c9 --- build/valgrind/cross-architecture.sup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/valgrind/cross-architecture.sup b/build/valgrind/cross-architecture.sup index c81e6558ed0b..b8ebc4c6dc12 100644 --- a/build/valgrind/cross-architecture.sup +++ b/build/valgrind/cross-architecture.sup @@ -8,7 +8,7 @@ PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534.) Memcheck:Leak ... - fun:_ZL9SaveToEnvPKc + fun:_ZN7mozilla9SaveToEnvEPKc ... } { From db0ca01e42de4123fa97cf15b04ed1c133c9d8d0 Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Wed, 2 May 2018 18:38:37 -0400 Subject: [PATCH 12/22] Bug 1457517 - Update Debugger Frontend v46. r=jdescottes --- devtools/client/debugger/new/README.mozilla | 6 +- devtools/client/debugger/new/debugger.css | 29 +- devtools/client/debugger/new/debugger.js | 16511 ++++++++-------- devtools/client/debugger/new/parser-worker.js | 6182 ++++-- .../new/test/mochitest/browser_dbg-scopes.js | 5 +- .../test/mochitest/browser_dbg-search-file.js | 3 +- .../debugger/new/test/mochitest/head.js | 3 +- .../client/shared/components/reps/reps.css | 181 +- .../client/shared/components/reps/reps.js | 5426 +++-- devtools/client/shared/source-map/index.js | 446 +- devtools/client/shared/source-map/worker.js | 1925 +- 11 files changed, 16797 insertions(+), 13920 deletions(-) diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index 37ecac02387e..4f632bcc0752 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,12 +1,12 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Version 45.1 +Version 46 -Comparison: https://github.com/devtools-html/debugger.html/compare/release-45...release-45.1 +Comparison: https://github.com/devtools-html/debugger.html/compare/release-45.1...release-46 Packages: -- babel-plugin-transform-es2015-modules-commonjs @6.26.0 +- babel-plugin-transform-es2015-modules-commonjs @6.26.2 - babel-preset-react @6.24.1 - react @16.2.0 - react-dom @16.2.0 diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css index c98c29a77fe5..accac7f95d07 100644 --- a/devtools/client/debugger/new/debugger.css +++ b/devtools/client/debugger/new/debugger.css @@ -1965,18 +1965,6 @@ html .toggle-button.end.vertical svg { --comment-node-color: var(--theme-comment); } -.theme-firebug { - --number-color: #000088; - --string-color: #FF0000; - --null-color: #787878; - --object-color: DarkGreen; - --caption-color: #444444; - --location-color: #555555; - --source-link-color: blue; - --node-color: rgb(0, 0, 136); - --reference-color: rgb(102, 102, 255); -} - /******************************************************************************/ .inline { @@ -2012,7 +2000,8 @@ html .toggle-button.end.vertical svg { color: var(--string-color); } -.objectBox-string a, .objectBox-string a:visited { +.objectBox-string a, +.objectBox-string a:visited { color: currentColor; text-decoration: none; font-style: italic; @@ -2205,7 +2194,7 @@ button.open-inspector { display: inline-block; background-color: var(--comment-node-color); height: 16px; - margin-left: .25em; + margin-left: 0.25em; vertical-align: middle; } @@ -2223,7 +2212,7 @@ button.jump-definition { display: inline-block; background-color: var(--comment-node-color); height: 16px; - margin-left: .25em; + margin-left: 0.25em; vertical-align: middle; } @@ -2278,6 +2267,16 @@ button.jump-definition { display: inline-block; vertical-align: middle; } + +/* Focused styles */ +.tree.object-inspector .tree-node.focused * { + color: inherit; +} + +.tree-node.focused button.jump-definition, +.tree-node.focused button.open-inspector { + background-color: currentColor; +} /* 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 . */ diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js index d84b5479da3b..744d16e64681 100644 --- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -1,13 +1,13 @@ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device")); + module.exports = factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device"), require("devtools/client/shared/vendor/react-prop-types"), require("devtools/client/shared/vendor/react-dom-factories")); else if(typeof define === 'function' && define.amd) - define(["devtools/client/shared/vendor/react", "devtools/client/shared/vendor/lodash", "devtools/client/shared/vendor/react-dom", "Services", "devtools/shared/flags", "devtools/client/sourceeditor/editor", "devtools/client/shared/vendor/WasmParser", "devtools/client/shared/vendor/WasmDis", "devtools/client/shared/vendor/react-redux", "devtools/client/shared/vendor/redux", "devtools/client/shared/vendor/immutable", "devtools/shared/fronts/device"], factory); + define(["devtools/client/shared/vendor/react", "devtools/client/shared/vendor/lodash", "devtools/client/shared/vendor/react-dom", "Services", "devtools/shared/flags", "devtools/client/sourceeditor/editor", "devtools/client/shared/vendor/WasmParser", "devtools/client/shared/vendor/WasmDis", "devtools/client/shared/vendor/react-redux", "devtools/client/shared/vendor/redux", "devtools/client/shared/vendor/immutable", "devtools/shared/fronts/device", "devtools/client/shared/vendor/react-prop-types", "devtools/client/shared/vendor/react-dom-factories"], factory); else { - var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device")) : factory(root["devtools/client/shared/vendor/react"], root["devtools/client/shared/vendor/lodash"], root["devtools/client/shared/vendor/react-dom"], root["Services"], root["devtools/shared/flags"], root["devtools/client/sourceeditor/editor"], root["devtools/client/shared/vendor/WasmParser"], root["devtools/client/shared/vendor/WasmDis"], root["devtools/client/shared/vendor/react-redux"], root["devtools/client/shared/vendor/redux"], root["devtools/client/shared/vendor/immutable"], root["devtools/shared/fronts/device"]); + var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device"), require("devtools/client/shared/vendor/react-prop-types"), require("devtools/client/shared/vendor/react-dom-factories")) : factory(root["devtools/client/shared/vendor/react"], root["devtools/client/shared/vendor/lodash"], root["devtools/client/shared/vendor/react-dom"], root["Services"], root["devtools/shared/flags"], root["devtools/client/sourceeditor/editor"], root["devtools/client/shared/vendor/WasmParser"], root["devtools/client/shared/vendor/WasmDis"], root["devtools/client/shared/vendor/react-redux"], root["devtools/client/shared/vendor/redux"], root["devtools/client/shared/vendor/immutable"], root["devtools/shared/fronts/device"], root["devtools/client/shared/vendor/react-prop-types"], root["devtools/client/shared/vendor/react-dom-factories"]); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_22__, __WEBPACK_EXTERNAL_MODULE_52__, __WEBPACK_EXTERNAL_MODULE_197__, __WEBPACK_EXTERNAL_MODULE_677__, __WEBPACK_EXTERNAL_MODULE_678__, __WEBPACK_EXTERNAL_MODULE_3592__, __WEBPACK_EXTERNAL_MODULE_3593__, __WEBPACK_EXTERNAL_MODULE_3594__, __WEBPACK_EXTERNAL_MODULE_3626__) { +})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_22__, __WEBPACK_EXTERNAL_MODULE_52__, __WEBPACK_EXTERNAL_MODULE_197__, __WEBPACK_EXTERNAL_MODULE_677__, __WEBPACK_EXTERNAL_MODULE_678__, __WEBPACK_EXTERNAL_MODULE_3592__, __WEBPACK_EXTERNAL_MODULE_3593__, __WEBPACK_EXTERNAL_MODULE_3594__, __WEBPACK_EXTERNAL_MODULE_3626__, __WEBPACK_EXTERNAL_MODULE_3642__, __WEBPACK_EXTERNAL_MODULE_3643__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -1573,20 +1573,6 @@ module.exports = "`); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(CommentNode), - supportsObject -}; - -/***/ }), - -/***/ 1578: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Utils -const { - isGrip, - wrapRender -} = __webpack_require__(1353); -const { rep: StringRep } = __webpack_require__(1447); -const { MODE } = __webpack_require__(1357); -const nodeConstants = __webpack_require__(1449); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders DOM element node. - */ -ElementNode.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function ElementNode(props) { - let { - object, - mode, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - let elements = getElements(object, mode); - - let isInTree = object.preview && object.preview.isConnected === true; - - let baseConfig = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-node" - }; - let inspectIcon; - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(object) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(object, e) - }); - } - } - - return span(baseConfig, ...elements, inspectIcon); -} - -function getElements(grip, mode) { - let { attributes, nodeName } = grip.preview; - const nodeNameElement = span({ - className: "tag-name" - }, nodeName); - - if (mode === MODE.TINY) { - let elements = [nodeNameElement]; - if (attributes.id) { - elements.push(span({ className: "attrName" }, `#${attributes.id}`)); - } - if (attributes.class) { - elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join(""))); - } - return elements; - } - let attributeKeys = Object.keys(attributes); - if (attributeKeys.includes("class")) { - attributeKeys.splice(attributeKeys.indexOf("class"), 1); - attributeKeys.unshift("class"); - } - if (attributeKeys.includes("id")) { - attributeKeys.splice(attributeKeys.indexOf("id"), 1); - attributeKeys.unshift("id"); - } - const attributeElements = attributeKeys.reduce((arr, name, i, keys) => { - let value = attributes[name]; - let attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); - - return arr.concat([" ", attribute]); - }, []); - - return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")]; -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ElementNode), - supportsObject -}; - -/***/ }), - -/***/ 1579: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - isGrip, - cropString, - wrapRender -} = __webpack_require__(1353); -const { MODE } = __webpack_require__(1357); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders DOM #text node. - */ -TextNode.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function TextNode(props) { - let { - object: grip, - mode = MODE.SHORT, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - - let baseConfig = { - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-textNode" - }; - let inspectIcon; - let isInTree = grip.preview && grip.preview.isConnected === true; - - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(grip) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - draggable: false, - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(grip, e) - }); - } - } - - if (mode === MODE.TINY) { - return span(baseConfig, getTitle(grip), inspectIcon); - } - - return span(baseConfig, getTitle(grip), span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); -} - -function getTextContent(grip) { - return cropString(grip.preview.textContent); -} - -function getTitle(grip) { - const title = "#text"; - return span({}, title); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.class == "Text"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(TextNode), - supportsObject -}; - -/***/ }), - -/***/ 1580: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); -// Utils -const { - getGripType, - isGrip, - wrapRender -} = __webpack_require__(1353); -const { cleanFunctionName } = __webpack_require__(1573); -const { isLongString } = __webpack_require__(1447); -const { MODE } = __webpack_require__(1357); - -const dom = __webpack_require__(1758); -const { span } = dom; -const IGNORED_SOURCE_URLS = ["debugger eval code"]; - -/** - * Renders Error objects. - */ -ErrorRep.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) -}; - -function ErrorRep(props) { - let object = props.object; - let preview = object.preview; - - let name; - if (preview && preview.name && preview.kind) { - switch (preview.kind) { - case "Error": - name = preview.name; - break; - case "DOMException": - name = preview.kind; - break; - default: - throw new Error("Unknown preview kind for the Error rep."); - } - } else { - name = "Error"; - } - - const content = []; - - if (props.mode === MODE.TINY) { - content.push(name); - } else { - content.push(`${name}: "${preview.message}"`); - } - - if (preview.stack && props.mode !== MODE.TINY) { - content.push("\n", getStacktraceElements(props, preview)); - } - - return span({ - "data-link-actor-id": object.actor, - className: "objectBox-stackTrace" - }, content); -} - -/** - * Returns a React element reprensenting the Error stacktrace, i.e. transform error.stack - * from: - * - * semicolon@debugger eval code:1:109 - * jkl@debugger eval code:1:63 - * asdf@debugger eval code:1:28 - * @debugger eval code:1:227 - * - * Into a column layout: - * - * semicolon (:8:10) - * jkl (:5:10) - * asdf (:2:10) - * (:11:1) - */ -function getStacktraceElements(props, preview) { - const stack = []; - if (!preview.stack) { - return stack; - } - - const isStacktraceALongString = isLongString(preview.stack); - const stackString = isStacktraceALongString ? preview.stack.initial : preview.stack; - - stackString.split("\n").forEach((frame, index) => { - if (!frame) { - // Skip any blank lines - return; - } - - let functionName; - let location; - - // Given the input: "functionName@scriptLocation:2:100" - // Result: - // ["functionName@scriptLocation:2:100", "functionName", "scriptLocation:2:100"] - const result = frame.match(/^(.*)@(.*)$/); - if (result && result.length === 3) { - functionName = result[1]; - - // If the resource was loaded by base-loader.js, the location looks like: - // resource://devtools/shared/base-loader.js -> resource://path/to/file.js . - // What's needed is only the last part after " -> ". - location = result[2].split(" -> ").pop(); - } - - if (!functionName) { - functionName = ""; - } - - let onLocationClick; - // Given the input: "scriptLocation:2:100" - // Result: - // ["scriptLocation:2:100", "scriptLocation", "2", "100"] - const locationParts = location.match(/^(.*):(\d+):(\d+)$/); - if (props.onViewSourceInDebugger && location && !IGNORED_SOURCE_URLS.includes(locationParts[1]) && locationParts) { - let [, url, line, column] = locationParts; - onLocationClick = e => { - // Don't trigger ObjectInspector expand/collapse. - e.stopPropagation(); - props.onViewSourceInDebugger({ - url, - line: Number(line), - column: Number(column) - }); - }; - } - - stack.push(span({ - key: "fn" + index, - className: "objectBox-stackTrace-fn" - }, cleanFunctionName(functionName)), span({ - key: "location" + index, - className: "objectBox-stackTrace-location", - onClick: onLocationClick, - title: onLocationClick ? "View source in debugger → " + location : undefined - }, location)); - }); - - if (isStacktraceALongString) { - // Remove the last frame (i.e. 2 last elements in the array, the function name and the - // location) which is certainly incomplete. - // Can be removed when https://bugzilla.mozilla.org/show_bug.cgi?id=1448833 is fixed. - stack.splice(-2); - } - - return span({ - key: "stack", - className: "objectBox-stackTrace-grid" - }, stack); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && getGripType(object, noGrip) === "Error" || object.class === "DOMException"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ErrorRep), - supportsObject -}; - -/***/ }), - -/***/ 1581: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - getGripType, - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(1353); - -const { MODE } = __webpack_require__(1357); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders a grip representing a window. - */ -WindowRep.propTypes = { - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - object: PropTypes.object.isRequired -}; - -function WindowRep(props) { - let { - mode, - object - } = props; - - const config = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-Window" - }; - - if (mode === MODE.TINY) { - return span(config, getTitle(object)); - } - - return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object))); -} - -function getTitle(object, trailingSpace) { - let title = object.displayClass || object.class || "Window"; - if (trailingSpace === true) { - title = `${title} `; - } - return span({ className: "objectTitle" }, title); -} - -function getLocation(object) { - return getURLDisplayString(object.preview.url); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - - return object.preview && getGripType(object, noGrip) == "Window"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(WindowRep), - supportsObject -}; - -/***/ }), - -/***/ 1582: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - isGrip, - wrapRender -} = __webpack_require__(1353); - -const String = __webpack_require__(1447).rep; - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders a grip object with textual data. - */ -ObjectWithText.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithText(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectTitle objectBox objectBox-" + getType(grip) - }, `${getType(grip)} `, getDescription(grip)); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return String({ - object: grip.preview.text - }); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithText"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithText), - supportsObject -}; - -/***/ }), - -/***/ 1583: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(1353); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders a grip object with URL data. - */ -ObjectWithURL.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithURL(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-" + getType(grip) - }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip))); -} - -function getTitle(grip) { - return span({ className: "objectTitle" }, getType(grip) + " "); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return getURLDisplayString(grip.preview.url); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithURL"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithURL), - supportsObject -}; - -/***/ }), - -/***/ 1584: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// Dependencies - -const { lengthBubble } = __webpack_require__(2249); -const PropTypes = __webpack_require__(20); -const { - interleave, - isGrip, - wrapRender, - ellipsisElement -} = __webpack_require__(1353); -const PropRep = __webpack_require__(1381); -const { MODE } = __webpack_require__(1357); -const { ModePropType } = __webpack_require__(1448); - -const { span } = __webpack_require__(1758); - -/** - * Renders an map. A map is represented by a list of its - * entries enclosed in curly brackets. - */ -GripMap.propTypes = { - object: PropTypes.object, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: ModePropType, - isInterestingEntry: PropTypes.func, - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func, - title: PropTypes.string -}; - -function GripMap(props) { - let { - mode, - object - } = props; - - const config = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-object" - }; - - const title = getTitle(props, object); - const isEmpty = getLength(object) === 0; - - if (isEmpty || mode === MODE.TINY) { - return span(config, title); - } - - const propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode)); - - return span(config, title, span({ - className: "objectLeftBrace" - }, " { "), ...interleave(propsArray, ", "), span({ - className: "objectRightBrace" - }, " }")); -} - -function getTitle(props, object) { - const title = props.title || (object && object.class ? object.class : "Map"); - return span({ - className: "objectTitle" }, title, lengthBubble({ - object, - mode: props.mode, - maxLengthMap, - getLength, - showZeroLength: true - })); -} - -function safeEntriesIterator(props, object, max) { - max = typeof max === "undefined" ? 3 : max; - try { - return entriesIterator(props, object, max); - } catch (err) { - console.error(err); - } - return []; -} - -function entriesIterator(props, object, max) { - // Entry filter. Show only interesting entries to the user. - let isInterestingEntry = props.isInterestingEntry || ((type, value) => { - return type == "boolean" || type == "number" || type == "string" && value.length != 0; - }); - - let mapEntries = object.preview && object.preview.entries ? object.preview.entries : []; - - let indexes = getEntriesIndexes(mapEntries, max, isInterestingEntry); - if (indexes.length < max && indexes.length < mapEntries.length) { - // There are not enough entries yet, so we add uninteresting entries. - indexes = indexes.concat(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => { - return !isInterestingEntry(t, value, name); - })); - } - - let entries = getEntries(props, mapEntries, indexes); - if (entries.length < getLength(object)) { - // There are some undisplayed entries. Then display "…". - entries.push(ellipsisElement); - } - - return entries; -} - -/** - * Get entries ordered by index. - * - * @param {Object} props Component props. - * @param {Array} entries Entries array. - * @param {Array} indexes Indexes of entries. - * @return {Array} Array of PropRep. - */ -function getEntries(props, entries, indexes) { - let { - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - - // Make indexes ordered by ascending. - indexes.sort(function (a, b) { - return a - b; - }); - - return indexes.map((index, i) => { - let [key, entryValue] = entries[index]; - let value = entryValue.value !== undefined ? entryValue.value : entryValue; - - return PropRep({ - name: key, - equal: " \u2192 ", - object: value, - mode: MODE.TINY, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - }); - }); -} - -/** - * Get the indexes of entries in the map. - * - * @param {Array} entries Entries array. - * @param {Number} max The maximum length of indexes array. - * @param {Function} filter Filter the entry you want. - * @return {Array} Indexes of filtered entries in the map. - */ -function getEntriesIndexes(entries, max, filter) { - return entries.reduce((indexes, [key, entry], i) => { - if (indexes.length < max) { - let value = entry && entry.value !== undefined ? entry.value : entry; - // Type is specified in grip's "class" field and for primitive - // values use typeof. - let type = (value && value.class ? value.class : typeof value).toLowerCase(); - - if (filter(type, value, key)) { - indexes.push(i); - } - } - - return indexes; - }, []); -} - -function getLength(grip) { - return grip.preview.size || 0; -} - -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - return grip.preview && grip.preview.kind == "MapLike"; -} - -const maxLengthMap = new Map(); -maxLengthMap.set(MODE.SHORT, 3); -maxLengthMap.set(MODE.LONG, 10); - -// Exports from this module -module.exports = { - rep: wrapRender(GripMap), - supportsObject, - maxLengthMap, - getLength -}; - -/***/ }), - -/***/ 1585: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -const { createElement, createFactory, PureComponent } = __webpack_require__(0); -const { Provider } = __webpack_require__(3592); -const ObjectInspector = createFactory(__webpack_require__(3615)); -const createStore = __webpack_require__(3618); -const Utils = __webpack_require__(1938); -const { - renderRep, - shouldRenderRootsInReps -} = Utils; - -class OI extends PureComponent { - - constructor(props) { - super(props); - this.store = createStore(props); - } - - getStore() { - return this.store; - } - - render() { - return createElement(Provider, { store: this.store }, ObjectInspector(this.props)); - } -} - -module.exports = props => { - let { roots } = props; - if (shouldRenderRootsInReps(roots)) { - return renderRep(roots[0], props); - } - return new OI(props); -}; - -/***/ }), - /***/ 1586: /***/ (function(module, exports, __webpack_require__) { @@ -21830,7 +16881,9 @@ function getCallSites(symbols, breakpoints) { } function findBreakpoint(callSite) { - const { location: { start, end } } = callSite; + const { + location: { start, end } + } = callSite; const breakpointId = (0, _lodash.range)(start.column - 1, end.column).map(column => locationKey({ line: start.line, column })).find(key => bpLocationMap[key]); @@ -22333,7 +17386,7 @@ var _reactRedux = __webpack_require__(3592); var _devtoolsContextmenu = __webpack_require__(1413); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _clipboard = __webpack_require__(1388); @@ -22443,7 +17496,9 @@ function getMenuItems(event, { accesskey: copyFunctionKey, disabled: !functionText, click: () => { - const { location: { start, end } } = getFunctionLocation(sourceLine); + const { + location: { start, end } + } = getFunctionLocation(sourceLine); flashLineRange({ start: start.line, end: end.line, @@ -22823,7 +17878,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _propTypes = __webpack_require__(20); +var _propTypes = __webpack_require__(3642); var _propTypes2 = _interopRequireDefault(_propTypes); @@ -22997,7 +18052,9 @@ class SecondaryPanes extends _react.Component { } getComponentItem() { - const { extra: { react } } = this.props; + const { + extra: { react } + } = this.props; return { header: react.displayName, @@ -23442,7 +18499,7 @@ var _classnames = __webpack_require__(175); var _classnames2 = _interopRequireDefault(_classnames); -var _devtoolsReps = __webpack_require__(1408); +var _devtoolsReps = __webpack_require__(3655); var _actions = __webpack_require__(1354); @@ -23558,7 +18615,7 @@ class Expressions extends _react.Component { roots: [root], autoExpandDepth: 0, disableWrap: true, - disabledFocus: true, + focusable: false, openLink: openLink, createObjectClient: grip => (0, _firefox.createObjectClient)(grip) }), @@ -24439,7 +19496,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _propTypes = __webpack_require__(20); +var _propTypes = __webpack_require__(3642); var _propTypes2 = _interopRequireDefault(_propTypes); @@ -24924,7 +19981,7 @@ var _selectors = __webpack_require__(3590); var _scopes = __webpack_require__(1792); -var _devtoolsReps = __webpack_require__(1408); +var _devtoolsReps = __webpack_require__(3655); __webpack_require__(1296); @@ -24983,7 +20040,7 @@ class Scopes extends _react.PureComponent { autoExpandAll: false, autoExpandDepth: 1, disableWrap: true, - disabledFocus: true, + focusable: false, dimTopLevelWindow: true, createObjectClient: grip => (0, _firefox.createObjectClient)(grip) }), @@ -25890,7 +20947,7 @@ var _prefs = __webpack_require__(226); var _log = __webpack_require__(2359); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } @@ -27103,7 +22160,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.paused = paused; -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _selectors = __webpack_require__(3590); @@ -27595,7 +22652,9 @@ class QuickOpenModal extends _react.Component { }; this.searchSymbols = query => { - const { symbols: { functions, variables } } = this.props; + const { + symbols: { functions, variables } + } = this.props; let results = functions; if (this.isVariableQuery()) { @@ -28797,341 +23856,6 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! }()); -/***/ }), - -/***/ 1758: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -(function(f) { - if (true) { - module.exports = f(__webpack_require__(0)); - /* global define */ - } else if (typeof define === 'function' && define.amd) { - define(['react'], f); - } else { - var g; - if (typeof window !== 'undefined') { - g = window; - } else if (typeof global !== 'undefined') { - g = global; - } else if (typeof self !== 'undefined') { - g = self; - } else { - g = this; - } - - if (typeof g.React === 'undefined') { - throw Error('React module should be required before ReactDOMFactories'); - } - - g.ReactDOMFactories = f(g.React); - } -})(function(React) { - /** - * Create a factory that creates HTML tag elements. - */ - function createDOMFactory(type) { - var factory = React.createElement.bind(null, type); - // Expose the type on the factory and the prototype so that it can be - // easily accessed on elements. E.g. `.type === Foo`. - // This should not be named `constructor` since this may not be the function - // that created the element, and it may not even be a constructor. - factory.type = type; - return factory; - }; - - /** - * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes. - */ - var ReactDOMFactories = { - a: createDOMFactory('a'), - abbr: createDOMFactory('abbr'), - address: createDOMFactory('address'), - area: createDOMFactory('area'), - article: createDOMFactory('article'), - aside: createDOMFactory('aside'), - audio: createDOMFactory('audio'), - b: createDOMFactory('b'), - base: createDOMFactory('base'), - bdi: createDOMFactory('bdi'), - bdo: createDOMFactory('bdo'), - big: createDOMFactory('big'), - blockquote: createDOMFactory('blockquote'), - body: createDOMFactory('body'), - br: createDOMFactory('br'), - button: createDOMFactory('button'), - canvas: createDOMFactory('canvas'), - caption: createDOMFactory('caption'), - cite: createDOMFactory('cite'), - code: createDOMFactory('code'), - col: createDOMFactory('col'), - colgroup: createDOMFactory('colgroup'), - data: createDOMFactory('data'), - datalist: createDOMFactory('datalist'), - dd: createDOMFactory('dd'), - del: createDOMFactory('del'), - details: createDOMFactory('details'), - dfn: createDOMFactory('dfn'), - dialog: createDOMFactory('dialog'), - div: createDOMFactory('div'), - dl: createDOMFactory('dl'), - dt: createDOMFactory('dt'), - em: createDOMFactory('em'), - embed: createDOMFactory('embed'), - fieldset: createDOMFactory('fieldset'), - figcaption: createDOMFactory('figcaption'), - figure: createDOMFactory('figure'), - footer: createDOMFactory('footer'), - form: createDOMFactory('form'), - h1: createDOMFactory('h1'), - h2: createDOMFactory('h2'), - h3: createDOMFactory('h3'), - h4: createDOMFactory('h4'), - h5: createDOMFactory('h5'), - h6: createDOMFactory('h6'), - head: createDOMFactory('head'), - header: createDOMFactory('header'), - hgroup: createDOMFactory('hgroup'), - hr: createDOMFactory('hr'), - html: createDOMFactory('html'), - i: createDOMFactory('i'), - iframe: createDOMFactory('iframe'), - img: createDOMFactory('img'), - input: createDOMFactory('input'), - ins: createDOMFactory('ins'), - kbd: createDOMFactory('kbd'), - keygen: createDOMFactory('keygen'), - label: createDOMFactory('label'), - legend: createDOMFactory('legend'), - li: createDOMFactory('li'), - link: createDOMFactory('link'), - main: createDOMFactory('main'), - map: createDOMFactory('map'), - mark: createDOMFactory('mark'), - menu: createDOMFactory('menu'), - menuitem: createDOMFactory('menuitem'), - meta: createDOMFactory('meta'), - meter: createDOMFactory('meter'), - nav: createDOMFactory('nav'), - noscript: createDOMFactory('noscript'), - object: createDOMFactory('object'), - ol: createDOMFactory('ol'), - optgroup: createDOMFactory('optgroup'), - option: createDOMFactory('option'), - output: createDOMFactory('output'), - p: createDOMFactory('p'), - param: createDOMFactory('param'), - picture: createDOMFactory('picture'), - pre: createDOMFactory('pre'), - progress: createDOMFactory('progress'), - q: createDOMFactory('q'), - rp: createDOMFactory('rp'), - rt: createDOMFactory('rt'), - ruby: createDOMFactory('ruby'), - s: createDOMFactory('s'), - samp: createDOMFactory('samp'), - script: createDOMFactory('script'), - section: createDOMFactory('section'), - select: createDOMFactory('select'), - small: createDOMFactory('small'), - source: createDOMFactory('source'), - span: createDOMFactory('span'), - strong: createDOMFactory('strong'), - style: createDOMFactory('style'), - sub: createDOMFactory('sub'), - summary: createDOMFactory('summary'), - sup: createDOMFactory('sup'), - table: createDOMFactory('table'), - tbody: createDOMFactory('tbody'), - td: createDOMFactory('td'), - textarea: createDOMFactory('textarea'), - tfoot: createDOMFactory('tfoot'), - th: createDOMFactory('th'), - thead: createDOMFactory('thead'), - time: createDOMFactory('time'), - title: createDOMFactory('title'), - tr: createDOMFactory('tr'), - track: createDOMFactory('track'), - u: createDOMFactory('u'), - ul: createDOMFactory('ul'), - var: createDOMFactory('var'), - video: createDOMFactory('video'), - wbr: createDOMFactory('wbr'), - - // SVG - circle: createDOMFactory('circle'), - clipPath: createDOMFactory('clipPath'), - defs: createDOMFactory('defs'), - ellipse: createDOMFactory('ellipse'), - g: createDOMFactory('g'), - image: createDOMFactory('image'), - line: createDOMFactory('line'), - linearGradient: createDOMFactory('linearGradient'), - mask: createDOMFactory('mask'), - path: createDOMFactory('path'), - pattern: createDOMFactory('pattern'), - polygon: createDOMFactory('polygon'), - polyline: createDOMFactory('polyline'), - radialGradient: createDOMFactory('radialGradient'), - rect: createDOMFactory('rect'), - stop: createDOMFactory('stop'), - svg: createDOMFactory('svg'), - text: createDOMFactory('text'), - tspan: createDOMFactory('tspan'), - }; - - // due to wrapper and conditionals at the top, this will either become - // `module.exports ReactDOMFactories` if that is available, - // otherwise it will be defined via `define(['react'], ReactDOMFactories)` - // if that is available, - // otherwise it will be defined as global variable. - return ReactDOMFactories; -}); - - - -/***/ }), - -/***/ 1759: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -var EventEmitter = function EventEmitter() {}; -module.exports = EventEmitter; - -const promise = __webpack_require__(1769); - -/** - * Decorate an object with event emitter functionality. - * - * @param Object aObjectToDecorate - * Bind all public methods of EventEmitter to - * the aObjectToDecorate object. - */ -EventEmitter.decorate = function EventEmitter_decorate(aObjectToDecorate) { - let emitter = new EventEmitter(); - aObjectToDecorate.on = emitter.on.bind(emitter); - aObjectToDecorate.off = emitter.off.bind(emitter); - aObjectToDecorate.once = emitter.once.bind(emitter); - aObjectToDecorate.emit = emitter.emit.bind(emitter); -}; - -EventEmitter.prototype = { - /** - * Connect a listener. - * - * @param string aEvent - * The event name to which we're connecting. - * @param function aListener - * Called when the event is fired. - */ - on: function EventEmitter_on(aEvent, aListener) { - if (!this._eventEmitterListeners) this._eventEmitterListeners = new Map(); - if (!this._eventEmitterListeners.has(aEvent)) { - this._eventEmitterListeners.set(aEvent, []); - } - this._eventEmitterListeners.get(aEvent).push(aListener); - }, - - /** - * Listen for the next time an event is fired. - * - * @param string aEvent - * The event name to which we're connecting. - * @param function aListener - * (Optional) Called when the event is fired. Will be called at most - * one time. - * @return promise - * A promise which is resolved when the event next happens. The - * resolution value of the promise is the first event argument. If - * you need access to second or subsequent event arguments (it's rare - * that this is needed) then use aListener - */ - once: function EventEmitter_once(aEvent, aListener) { - let deferred = promise.defer(); - - let handler = (aEvent, aFirstArg, ...aRest) => { - this.off(aEvent, handler); - if (aListener) { - aListener.apply(null, [aEvent, aFirstArg, ...aRest]); - } - deferred.resolve(aFirstArg); - }; - - handler._originalListener = aListener; - this.on(aEvent, handler); - - return deferred.promise; - }, - - /** - * Remove a previously-registered event listener. Works for events - * registered with either on or once. - * - * @param string aEvent - * The event name whose listener we're disconnecting. - * @param function aListener - * The listener to remove. - */ - off: function EventEmitter_off(aEvent, aListener) { - if (!this._eventEmitterListeners) return; - let listeners = this._eventEmitterListeners.get(aEvent); - if (listeners) { - this._eventEmitterListeners.set(aEvent, listeners.filter(l => { - return l !== aListener && l._originalListener !== aListener; - })); - } - }, - - /** - * Emit an event. All arguments to this method will - * be sent to listener functions. - */ - emit: function EventEmitter_emit(aEvent) { - if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(aEvent)) { - return; - } - - let originalListeners = this._eventEmitterListeners.get(aEvent); - for (let listener of this._eventEmitterListeners.get(aEvent)) { - // If the object was destroyed during event emission, stop - // emitting. - if (!this._eventEmitterListeners) { - break; - } - - // If listeners were removed during emission, make sure the - // event handler we're going to fire wasn't removed. - if (originalListeners === this._eventEmitterListeners.get(aEvent) || this._eventEmitterListeners.get(aEvent).some(l => l === listener)) { - try { - listener.apply(null, arguments); - } catch (ex) { - // Prevent a bad listener from interfering with the others. - let msg = ex + ": " + ex.stack; - //console.error(msg); - console.log(msg); - } - } - } - } -}; - /***/ }), /***/ 1763: @@ -29152,7 +23876,7 @@ var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -var _propTypes = __webpack_require__(20); +var _propTypes = __webpack_require__(3642); var _util = __webpack_require__(1777); @@ -29400,863 +24124,6 @@ function getThisVariable(this_, path) { /***/ }), -/***/ 1767: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -const Menu = __webpack_require__(1768); -const MenuItem = __webpack_require__(1770); -const { PrefsHelper } = __webpack_require__(1771); -const Services = __webpack_require__(22); -const KeyShortcuts = __webpack_require__(1772); -const { ZoomKeys } = __webpack_require__(1773); -const EventEmitter = __webpack_require__(1759); - -module.exports = { - KeyShortcuts, - Menu, - MenuItem, - PrefsHelper, - Services, - ZoomKeys, - EventEmitter -}; - -/***/ }), - -/***/ 1768: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -const EventEmitter = __webpack_require__(1759); - -function inToolbox() { - return window.parent.document.documentURI == "about:devtools-toolbox"; -} - -/** - * A partial implementation of the Menu API provided by electron: - * https://github.com/electron/electron/blob/master/docs/api/menu.md. - * - * Extra features: - * - Emits an 'open' and 'close' event when the menu is opened/closed - - * @param String id (non standard) - * Needed so tests can confirm the XUL implementation is working - */ -function Menu({ id = null } = {}) { - this.menuitems = []; - this.id = id; - - Object.defineProperty(this, "items", { - get() { - return this.menuitems; - } - }); - - EventEmitter.decorate(this); -} - -/** - * Add an item to the end of the Menu - * - * @param {MenuItem} menuItem - */ -Menu.prototype.append = function (menuItem) { - this.menuitems.push(menuItem); -}; - -/** - * Add an item to a specified position in the menu - * - * @param {int} pos - * @param {MenuItem} menuItem - */ -Menu.prototype.insert = function (pos, menuItem) { - throw Error("Not implemented"); -}; - -/** - * Show the Menu at a specified location on the screen - * - * Missing features: - * - browserWindow - BrowserWindow (optional) - Default is null. - * - positioningItem Number - (optional) OS X - * - * @param {int} screenX - * @param {int} screenY - * @param Toolbox toolbox (non standard) - * Needed so we in which window to inject XUL - */ -Menu.prototype.popup = function (screenX, screenY, toolbox) { - let doc = toolbox.doc; - let popupset = doc.querySelector("popupset"); - // See bug 1285229, on Windows, opening the same popup multiple times in a - // row ends up duplicating the popup. The newly inserted popup doesn't - // dismiss the old one. So remove any previously displayed popup before - // opening a new one. - let popup = popupset.querySelector("menupopup[menu-api=\"true\"]"); - if (popup) { - popup.hidePopup(); - } - - popup = this.createPopup(doc); - popup.setAttribute("menu-api", "true"); - - if (this.id) { - popup.id = this.id; - } - this._createMenuItems(popup); - - // Remove the menu from the DOM once it's hidden. - popup.addEventListener("popuphidden", e => { - if (e.target === popup) { - popup.remove(); - this.emit("close", popup); - } - }); - - popup.addEventListener("popupshown", e => { - if (e.target === popup) { - this.emit("open", popup); - } - }); - - popupset.appendChild(popup); - popup.openPopupAtScreen(screenX, screenY, true); -}; - -Menu.prototype.createPopup = function (doc) { - return doc.createElement("menupopup"); -}; - -Menu.prototype._createMenuItems = function (parent) { - let doc = parent.ownerDocument; - this.menuitems.forEach(item => { - if (!item.visible) { - return; - } - - if (item.submenu) { - let menupopup = doc.createElement("menupopup"); - item.submenu._createMenuItems(menupopup); - - let menuitem = doc.createElement("menuitem"); - menuitem.setAttribute("label", item.label); - if (!inToolbox()) { - menuitem.textContent = item.label; - } - - let menu = doc.createElement("menu"); - menu.appendChild(menuitem); - menu.appendChild(menupopup); - if (item.disabled) { - menu.setAttribute("disabled", "true"); - } - if (item.accesskey) { - menu.setAttribute("accesskey", item.accesskey); - } - if (item.id) { - menu.id = item.id; - } - parent.appendChild(menu); - } else if (item.type === "separator") { - let menusep = doc.createElement("menuseparator"); - parent.appendChild(menusep); - } else { - let menuitem = doc.createElement("menuitem"); - menuitem.setAttribute("label", item.label); - - if (!inToolbox()) { - menuitem.textContent = item.label; - } - - menuitem.addEventListener("command", () => item.click()); - - if (item.type === "checkbox") { - menuitem.setAttribute("type", "checkbox"); - } - if (item.type === "radio") { - menuitem.setAttribute("type", "radio"); - } - if (item.disabled) { - menuitem.setAttribute("disabled", "true"); - } - if (item.checked) { - menuitem.setAttribute("checked", "true"); - } - if (item.accesskey) { - menuitem.setAttribute("accesskey", item.accesskey); - } - if (item.id) { - menuitem.id = item.id; - } - - parent.appendChild(menuitem); - } - }); -}; - -Menu.setApplicationMenu = () => { - throw Error("Not implemented"); -}; - -Menu.sendActionToFirstResponder = () => { - throw Error("Not implemented"); -}; - -Menu.buildFromTemplate = () => { - throw Error("Not implemented"); -}; - -module.exports = Menu; - -/***/ }), - -/***/ 1769: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -/* - * A sham for https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/Promise.jsm - */ - -/** - * Promise.jsm is mostly the Promise web API with a `defer` method. Just drop this in here, - * and use the native web API (although building with webpack/babel, it may replace this - * with it's own version if we want to target environments that do not have `Promise`. - */ - -let p = typeof window != "undefined" ? window.Promise : Promise; -p.defer = function defer() { - var resolve, reject; - var promise = new Promise(function () { - resolve = arguments[0]; - reject = arguments[1]; - }); - return { - resolve: resolve, - reject: reject, - promise: promise - }; -}; - -module.exports = p; - -/***/ }), - -/***/ 177: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - - - -var emptyFunction = __webpack_require__(178); -var invariant = __webpack_require__(180); -var ReactPropTypesSecret = __webpack_require__(187); - -module.exports = function() { - function shim(props, propName, componentName, location, propFullName, secret) { - if (secret === ReactPropTypesSecret) { - // It is still safe when called from React. - return; - } - invariant( - false, - 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + - 'Use PropTypes.checkPropTypes() to call them. ' + - 'Read more at http://fb.me/use-check-prop-types' - ); - }; - shim.isRequired = shim; - function getShim() { - return shim; - }; - // Important! - // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. - var ReactPropTypes = { - array: shim, - bool: shim, - func: shim, - number: shim, - object: shim, - string: shim, - symbol: shim, - - any: shim, - arrayOf: getShim, - element: shim, - instanceOf: getShim, - node: shim, - objectOf: getShim, - oneOf: getShim, - oneOfType: getShim, - shape: getShim, - exact: getShim - }; - - ReactPropTypes.checkPropTypes = emptyFunction; - ReactPropTypes.PropTypes = ReactPropTypes; - - return ReactPropTypes; -}; - - -/***/ }), - -/***/ 1770: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -/** - * A partial implementation of the MenuItem API provided by electron: - * https://github.com/electron/electron/blob/master/docs/api/menu-item.md. - * - * Missing features: - * - id String - Unique within a single menu. If defined then it can be used - * as a reference to this item by the position attribute. - * - role String - Define the action of the menu item; when specified the - * click property will be ignored - * - sublabel String - * - accelerator Accelerator - * - icon NativeImage - * - position String - This field allows fine-grained definition of the - * specific location within a given menu. - * - * Implemented features: - * @param Object options - * Function click - * Will be called with click(menuItem, browserWindow) when the menu item - * is clicked - * String type - * Can be normal, separator, submenu, checkbox or radio - * String label - * Boolean enabled - * If false, the menu item will be greyed out and unclickable. - * Boolean checked - * Should only be specified for checkbox or radio type menu items. - * Menu submenu - * Should be specified for submenu type menu items. If submenu is specified, - * the type: 'submenu' can be omitted. If the value is not a Menu then it - * will be automatically converted to one using Menu.buildFromTemplate. - * Boolean visible - * If false, the menu item will be entirely hidden. - */ -function MenuItem({ - accesskey = null, - checked = false, - click = () => {}, - disabled = false, - label = "", - id = null, - submenu = null, - type = "normal", - visible = true -} = {}) { - this.accesskey = accesskey; - this.checked = checked; - this.click = click; - this.disabled = disabled; - this.id = id; - this.label = label; - this.submenu = submenu; - this.type = type; - this.visible = visible; -} - -module.exports = MenuItem; - -/***/ }), - -/***/ 1771: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -const Services = __webpack_require__(22); -const EventEmitter = __webpack_require__(1759); - -/** - * Shortcuts for lazily accessing and setting various preferences. - * Usage: - * let prefs = new Prefs("root.path.to.branch", { - * myIntPref: ["Int", "leaf.path.to.my-int-pref"], - * myCharPref: ["Char", "leaf.path.to.my-char-pref"], - * myJsonPref: ["Json", "leaf.path.to.my-json-pref"], - * myFloatPref: ["Float", "leaf.path.to.my-float-pref"] - * ... - * }); - * - * Get/set: - * prefs.myCharPref = "foo"; - * let aux = prefs.myCharPref; - * - * Observe: - * prefs.registerObserver(); - * prefs.on("pref-changed", (prefName, prefValue) => { - * ... - * }); - * - * @param string prefsRoot - * The root path to the required preferences branch. - * @param object prefsBlueprint - * An object containing { accessorName: [prefType, prefName, prefDefault] } keys. - */ -function PrefsHelper(prefsRoot = "", prefsBlueprint = {}) { - EventEmitter.decorate(this); - - let cache = new Map(); - - for (let accessorName in prefsBlueprint) { - let [prefType, prefName, prefDefault] = prefsBlueprint[accessorName]; - map(this, cache, accessorName, prefType, prefsRoot, prefName, prefDefault); - } - - let observer = makeObserver(this, cache, prefsRoot, prefsBlueprint); - this.registerObserver = () => observer.register(); - this.unregisterObserver = () => observer.unregister(); -} - -/** - * Helper method for getting a pref value. - * - * @param Map cache - * @param string prefType - * @param string prefsRoot - * @param string prefName - * @return any - */ -function get(cache, prefType, prefsRoot, prefName) { - let cachedPref = cache.get(prefName); - if (cachedPref !== undefined) { - return cachedPref; - } - let value = Services.prefs["get" + prefType + "Pref"]([prefsRoot, prefName].join(".")); - cache.set(prefName, value); - return value; -} - -/** - * Helper method for setting a pref value. - * - * @param Map cache - * @param string prefType - * @param string prefsRoot - * @param string prefName - * @param any value - */ -function set(cache, prefType, prefsRoot, prefName, value) { - Services.prefs["set" + prefType + "Pref"]([prefsRoot, prefName].join("."), value); - cache.set(prefName, value); -} - -/** - * Maps a property name to a pref, defining lazy getters and setters. - * Supported types are "Bool", "Char", "Int", "Float" (sugar around "Char" - * type and casting), and "Json" (which is basically just sugar for "Char" - * using the standard JSON serializer). - * - * @param PrefsHelper self - * @param Map cache - * @param string accessorName - * @param string prefType - * @param string prefsRoot - * @param string prefName - * @param string prefDefault - * @param array serializer [optional] - */ -function map(self, cache, accessorName, prefType, prefsRoot, prefName, prefDefault, serializer = { in: e => e, out: e => e }) { - if (prefName in self) { - throw new Error(`Can't use ${prefName} because it overrides a property` + "on the instance."); - } - if (prefType == "Json") { - map(self, cache, accessorName, "String", prefsRoot, prefName, prefDefault, { - in: JSON.parse, - out: JSON.stringify - }); - return; - } - if (prefType == "Float") { - map(self, cache, accessorName, "Char", prefsRoot, prefName, prefDefault, { - in: Number.parseFloat, - out: n => n + "" - }); - return; - } - - Object.defineProperty(self, accessorName, { - get: () => { - try { - return serializer.in(get(cache, prefType, prefsRoot, prefName)); - } catch (e) { - if (typeof prefDefault !== 'undefined') { - return prefDefault; - } - throw e; - } - }, - set: e => set(cache, prefType, prefsRoot, prefName, serializer.out(e)) - }); -} - -/** - * Finds the accessor for the provided pref, based on the blueprint object - * used in the constructor. - * - * @param PrefsHelper self - * @param object prefsBlueprint - * @return string - */ -function accessorNameForPref(somePrefName, prefsBlueprint) { - for (let accessorName in prefsBlueprint) { - let [, prefName] = prefsBlueprint[accessorName]; - if (somePrefName == prefName) { - return accessorName; - } - } - return ""; -} - -/** - * Creates a pref observer for `self`. - * - * @param PrefsHelper self - * @param Map cache - * @param string prefsRoot - * @param object prefsBlueprint - * @return object - */ -function makeObserver(self, cache, prefsRoot, prefsBlueprint) { - return { - register: function () { - this._branch = Services.prefs.getBranch(prefsRoot + "."); - this._branch.addObserver("", this); - }, - unregister: function () { - this._branch.removeObserver("", this); - }, - observe: function (subject, topic, prefName) { - // If this particular pref isn't handled by the blueprint object, - // even though it's in the specified branch, ignore it. - let accessorName = accessorNameForPref(prefName, prefsBlueprint); - if (!(accessorName in self)) { - return; - } - cache.delete(prefName); - self.emit("pref-changed", accessorName, self[accessorName]); - } - }; -} - -exports.PrefsHelper = PrefsHelper; - -/***/ }), - -/***/ 1772: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -const { appinfo } = __webpack_require__(22); -const EventEmitter = __webpack_require__(1759); -const isOSX = appinfo.OS === "Darwin"; - -// List of electron keys mapped to DOM API (DOM_VK_*) key code -const ElectronKeysMapping = { - "F1": "DOM_VK_F1", - "F2": "DOM_VK_F2", - "F3": "DOM_VK_F3", - "F4": "DOM_VK_F4", - "F5": "DOM_VK_F5", - "F6": "DOM_VK_F6", - "F7": "DOM_VK_F7", - "F8": "DOM_VK_F8", - "F9": "DOM_VK_F9", - "F10": "DOM_VK_F10", - "F11": "DOM_VK_F11", - "F12": "DOM_VK_F12", - "F13": "DOM_VK_F13", - "F14": "DOM_VK_F14", - "F15": "DOM_VK_F15", - "F16": "DOM_VK_F16", - "F17": "DOM_VK_F17", - "F18": "DOM_VK_F18", - "F19": "DOM_VK_F19", - "F20": "DOM_VK_F20", - "F21": "DOM_VK_F21", - "F22": "DOM_VK_F22", - "F23": "DOM_VK_F23", - "F24": "DOM_VK_F24", - "Space": "DOM_VK_SPACE", - "Backspace": "DOM_VK_BACK_SPACE", - "Delete": "DOM_VK_DELETE", - "Insert": "DOM_VK_INSERT", - "Return": "DOM_VK_RETURN", - "Enter": "DOM_VK_RETURN", - "Up": "DOM_VK_UP", - "Down": "DOM_VK_DOWN", - "Left": "DOM_VK_LEFT", - "Right": "DOM_VK_RIGHT", - "Home": "DOM_VK_HOME", - "End": "DOM_VK_END", - "PageUp": "DOM_VK_PAGE_UP", - "PageDown": "DOM_VK_PAGE_DOWN", - "Escape": "DOM_VK_ESCAPE", - "Esc": "DOM_VK_ESCAPE", - "Tab": "DOM_VK_TAB", - "VolumeUp": "DOM_VK_VOLUME_UP", - "VolumeDown": "DOM_VK_VOLUME_DOWN", - "VolumeMute": "DOM_VK_VOLUME_MUTE", - "PrintScreen": "DOM_VK_PRINTSCREEN" -}; - -/** - * Helper to listen for keyboard events decribed in .properties file. - * - * let shortcuts = new KeyShortcuts({ - * window - * }); - * shortcuts.on("Ctrl+F", event => { - * // `event` is the KeyboardEvent which relates to the key shortcuts - * }); - * - * @param DOMWindow window - * The window object of the document to listen events from. - * @param DOMElement target - * Optional DOM Element on which we should listen events from. - * If omitted, we listen for all events fired on `window`. - */ -function KeyShortcuts({ window, target }) { - this.window = window; - this.target = target || window; - this.keys = new Map(); - this.eventEmitter = new EventEmitter(); - this.target.addEventListener("keydown", this); -} - -/* - * Parse an electron-like key string and return a normalized object which - * allow efficient match on DOM key event. The normalized object matches DOM - * API. - * - * @param DOMWindow window - * Any DOM Window object, just to fetch its `KeyboardEvent` object - * @param String str - * The shortcut string to parse, following this document: - * https://github.com/electron/electron/blob/master/docs/api/accelerator.md - */ -KeyShortcuts.parseElectronKey = function (window, str) { - let modifiers = str.split("+"); - let key = modifiers.pop(); - - let shortcut = { - ctrl: false, - meta: false, - alt: false, - shift: false, - // Set for character keys - key: undefined, - // Set for non-character keys - keyCode: undefined - }; - for (let mod of modifiers) { - if (mod === "Alt") { - shortcut.alt = true; - } else if (["Command", "Cmd"].includes(mod)) { - shortcut.meta = true; - } else if (["CommandOrControl", "CmdOrCtrl"].includes(mod)) { - if (isOSX) { - shortcut.meta = true; - } else { - shortcut.ctrl = true; - } - } else if (["Control", "Ctrl"].includes(mod)) { - shortcut.ctrl = true; - } else if (mod === "Shift") { - shortcut.shift = true; - } else { - console.error("Unsupported modifier:", mod, "from key:", str); - return null; - } - } - - // Plus is a special case. It's a character key and shouldn't be matched - // against a keycode as it is only accessible via Shift/Capslock - if (key === "Plus") { - key = "+"; - } - - if (typeof key === "string" && key.length === 1) { - // Match any single character - shortcut.key = key.toLowerCase(); - } else if (key in ElectronKeysMapping) { - // Maps the others manually to DOM API DOM_VK_* - key = ElectronKeysMapping[key]; - shortcut.keyCode = window.KeyboardEvent[key]; - // Used only to stringify the shortcut - shortcut.keyCodeString = key; - shortcut.key = key; - } else { - console.error("Unsupported key:", key); - return null; - } - - return shortcut; -}; - -KeyShortcuts.stringify = function (shortcut) { - let list = []; - if (shortcut.alt) { - list.push("Alt"); - } - if (shortcut.ctrl) { - list.push("Ctrl"); - } - if (shortcut.meta) { - list.push("Cmd"); - } - if (shortcut.shift) { - list.push("Shift"); - } - let key; - if (shortcut.key) { - key = shortcut.key.toUpperCase(); - } else { - key = shortcut.keyCodeString; - } - list.push(key); - return list.join("+"); -}; - -KeyShortcuts.prototype = { - destroy() { - this.target.removeEventListener("keydown", this); - this.keys.clear(); - }, - - doesEventMatchShortcut(event, shortcut) { - if (shortcut.meta != event.metaKey) { - return false; - } - if (shortcut.ctrl != event.ctrlKey) { - return false; - } - if (shortcut.alt != event.altKey) { - return false; - } - // Shift is a special modifier, it may implicitely be required if the - // expected key is a special character accessible via shift. - if (shortcut.shift != event.shiftKey && event.key && event.key.match(/[a-zA-Z]/)) { - return false; - } - if (shortcut.keyCode) { - return event.keyCode == shortcut.keyCode; - } else if (event.key in ElectronKeysMapping) { - return ElectronKeysMapping[event.key] === shortcut.key; - } - - // get the key from the keyCode if key is not provided. - let key = event.key || String.fromCharCode(event.keyCode); - - // For character keys, we match if the final character is the expected one. - // But for digits we also accept indirect match to please azerty keyboard, - // which requires Shift to be pressed to get digits. - return key.toLowerCase() == shortcut.key || shortcut.key.match(/^[0-9]$/) && event.keyCode == shortcut.key.charCodeAt(0); - }, - - handleEvent(event) { - for (let [key, shortcut] of this.keys) { - if (this.doesEventMatchShortcut(event, shortcut)) { - this.eventEmitter.emit(key, event); - } - } - }, - - on(key, listener) { - if (typeof listener !== "function") { - throw new Error("KeyShortcuts.on() expects a function as " + "second argument"); - } - if (!this.keys.has(key)) { - let shortcut = KeyShortcuts.parseElectronKey(this.window, key); - // The key string is wrong and we were unable to compute the key shortcut - if (!shortcut) { - return; - } - this.keys.set(key, shortcut); - } - this.eventEmitter.on(key, listener); - }, - - off(key, listener) { - this.eventEmitter.off(key, listener); - } -}; -module.exports = KeyShortcuts; - -/***/ }), - -/***/ 1773: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* 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/. */ - - - -/** - * Empty shim for "devtools/client/shared/zoom-keys" module - * - * Based on nsIMarkupDocumentViewer.fullZoom API - * https://developer.mozilla.org/en-US/Firefox/Releases/3/Full_page_zoom - */ - -exports.register = function (window) {}; - -/***/ }), - /***/ 1777: /***/ (function(module, exports, __webpack_require__) { @@ -30400,7 +24267,7 @@ var _pause = __webpack_require__(1394); var _frames = __webpack_require__(3605); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _lodash = __webpack_require__(2); @@ -30437,49 +24304,6 @@ const getCallStackFrames = exports.getCallStackFrames = (0, _reselect.createSele /***/ }), -/***/ 178: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ - -function makeEmptyFunction(arg) { - return function () { - return arg; - }; -} - -/** - * This function accepts and discards inputs; it has no side effects. This is - * primarily useful idiomatically for overridable function endpoints which - * always need to be callable, since JS lacks a null-call idiom ala Cocoa. - */ -var emptyFunction = function emptyFunction() {}; - -emptyFunction.thatReturns = makeEmptyFunction; -emptyFunction.thatReturnsFalse = makeEmptyFunction(false); -emptyFunction.thatReturnsTrue = makeEmptyFunction(true); -emptyFunction.thatReturnsNull = makeEmptyFunction(null); -emptyFunction.thatReturnsThis = function () { - return this; -}; -emptyFunction.thatReturnsArgument = function (arg) { - return arg; -}; - -module.exports = emptyFunction; - -/***/ }), - /***/ 1780: /***/ (function(module, exports, __webpack_require__) { @@ -30495,7 +24319,7 @@ var _sources = __webpack_require__(1369); var _pause = __webpack_require__(1394); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _reselect = __webpack_require__(993); @@ -30627,7 +24451,7 @@ var _ast = __webpack_require__(1638); var _editor = __webpack_require__(1358); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _promise = __webpack_require__(1653); @@ -30840,7 +24664,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument exports.getScope = getScope; -var _devtoolsReps = __webpack_require__(1408); +var _devtoolsReps = __webpack_require__(3655); var _getVariables = __webpack_require__(1765); @@ -31380,66 +25204,6 @@ function closeTabs(urls) { /***/ }), -/***/ 180: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - - - -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var validateFormat = function validateFormat(format) {}; - -if (false) { - validateFormat = function validateFormat(format) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - }; -} - -function invariant(condition, format, a, b, c, d, e, f) { - validateFormat(format); - - if (!condition) { - var error; - if (format === undefined) { - error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error(format.replace(/%s/g, function () { - return args[argIndex++]; - })); - error.name = 'Invariant Violation'; - } - - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -} - -module.exports = invariant; - -/***/ }), - /***/ 1800: /***/ (function(module, exports, __webpack_require__) { @@ -31489,7 +25253,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument exports.newSource = newSource; exports.newSources = newSources; -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _lodash = __webpack_require__(2); @@ -31722,7 +25486,7 @@ exports.selectSpecificSource = selectSpecificSource; exports.jumpToMappedLocation = jumpToMappedLocation; exports.jumpToMappedSelectedLocation = jumpToMappedSelectedLocation; -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _ast = __webpack_require__(1399); @@ -32316,907 +26080,6 @@ module.exports = "`); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; +} + +// Exports from this module +module.exports = { + rep: wrapRender(CommentNode), + supportsObject +}; + +/***/ }), + /***/ 369: /***/ (function(module, exports) { @@ -40086,6 +38344,1066 @@ module.exports = "`); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(CommentNode), - supportsObject -}; - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Utils -const { - isGrip, - wrapRender -} = __webpack_require__(0); -const { rep: StringRep } = __webpack_require__(5); -const { MODE } = __webpack_require__(3); -const nodeConstants = __webpack_require__(12); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders DOM element node. - */ -ElementNode.propTypes = { - object: PropTypes.object.isRequired, - inspectIconTitle: PropTypes.string, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeClick: PropTypes.func, - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function ElementNode(props) { - let { - object, - inspectIconTitle, - mode, - onDOMNodeClick, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - let elements = getElements(object, mode); - - let isInTree = object.preview && object.preview.isConnected === true; - - let baseConfig = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-node" - }; - let inspectIcon; - if (isInTree) { - if (onDOMNodeClick) { - Object.assign(baseConfig, { - onClick: _ => onDOMNodeClick(object) - }); - } - - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(object) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: inspectIconTitle || "Click to select the node in the inspector", - onClick: e => { - if (onDOMNodeClick) { - e.stopPropagation(); - } - - onInspectIconClick(object, e); - } - }); - } - } - - return span(baseConfig, ...elements, inspectIcon); -} - -function getElements(grip, mode) { - let { - attributes, - nodeName, - isAfterPseudoElement, - isBeforePseudoElement - } = grip.preview; - const nodeNameElement = span({ - className: "tag-name" - }, nodeName); - - if (isAfterPseudoElement || isBeforePseudoElement) { - return [span({ className: "attrName" }, `::${isAfterPseudoElement ? "after" : "before"}`)]; - } - - if (mode === MODE.TINY) { - let elements = [nodeNameElement]; - if (attributes.id) { - elements.push(span({ className: "attrName" }, `#${attributes.id}`)); - } - if (attributes.class) { - elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join(""))); - } - return elements; - } - - let attributeKeys = Object.keys(attributes); - if (attributeKeys.includes("class")) { - attributeKeys.splice(attributeKeys.indexOf("class"), 1); - attributeKeys.unshift("class"); - } - if (attributeKeys.includes("id")) { - attributeKeys.splice(attributeKeys.indexOf("id"), 1); - attributeKeys.unshift("id"); - } - const attributeElements = attributeKeys.reduce((arr, name, i, keys) => { - let value = attributes[name]; - let attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); - - return arr.concat([" ", attribute]); - }, []); - - return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")]; -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ElementNode), - supportsObject -}; - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - isGrip, - cropString, - wrapRender -} = __webpack_require__(0); -const { MODE } = __webpack_require__(3); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders DOM #text node. - */ -TextNode.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function TextNode(props) { - let { - object: grip, - mode = MODE.SHORT, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - - let baseConfig = { - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-textNode" - }; - let inspectIcon; - let isInTree = grip.preview && grip.preview.isConnected === true; - - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(grip) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - draggable: false, - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(grip, e) - }); - } - } - - if (mode === MODE.TINY) { - return span(baseConfig, getTitle(grip), inspectIcon); - } - - return span(baseConfig, getTitle(grip), span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); -} - -function getTextContent(grip) { - return cropString(grip.preview.textContent); -} - -function getTitle(grip) { - const title = "#text"; - return span({}, title); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.class == "Text"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(TextNode), - supportsObject -}; - -/***/ }), -/* 44 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - getGripType, - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(0); - -const { MODE } = __webpack_require__(3); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders a grip representing a window. - */ -WindowRep.propTypes = { - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - object: PropTypes.object.isRequired -}; - -function WindowRep(props) { - let { - mode, - object - } = props; - - const config = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-Window" - }; - - if (mode === MODE.TINY) { - return span(config, getTitle(object)); - } - - return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object))); -} - -function getTitle(object, trailingSpace) { - let title = object.displayClass || object.class || "Window"; - if (trailingSpace === true) { - title = `${title} `; - } - return span({ className: "objectTitle" }, title); -} - -function getLocation(object) { - return getURLDisplayString(object.preview.url); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - - return object.preview && getGripType(object, noGrip) == "Window"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(WindowRep), - supportsObject -}; - -/***/ }), -/* 45 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - isGrip, - wrapRender -} = __webpack_require__(0); - -const String = __webpack_require__(5).rep; - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders a grip object with textual data. - */ -ObjectWithText.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithText(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectTitle objectBox objectBox-" + getType(grip) - }, `${getType(grip)} `, getDescription(grip)); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return String({ - object: grip.preview.text - }); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithText"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithText), - supportsObject -}; - -/***/ }), -/* 46 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(0); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders a grip object with URL data. - */ -ObjectWithURL.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithURL(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-" + getType(grip) - }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip))); -} - -function getTitle(grip) { - return span({ className: "objectTitle" }, getType(grip) + " "); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return getURLDisplayString(grip.preview.url); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithURL"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithURL), - supportsObject -}; - -/***/ }), -/* 47 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* 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/. */ - -const { createElement, createFactory, PureComponent } = __webpack_require__(9); -const { Provider } = __webpack_require__(18); -const ObjectInspector = createFactory(__webpack_require__(48)); -const createStore = __webpack_require__(56); -const Utils = __webpack_require__(10); -const { - renderRep, - shouldRenderRootsInReps -} = Utils; - -class OI extends PureComponent { - - constructor(props) { - super(props); - this.store = createStore(props); - } - - getStore() { - return this.store; - } - - render() { - return createElement(Provider, { store: this.store }, ObjectInspector(this.props)); - } -} - -module.exports = props => { - let { roots } = props; - if (shouldRenderRootsInReps(roots)) { - return renderRep(roots[0], props); - } - return new OI(props); -}; - -/***/ }), -/* 48 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _devtoolsComponents = __webpack_require__(49); - -var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/* 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/. */ - -const { - Component, - createFactory -} = __webpack_require__(9); -const dom = __webpack_require__(1); -const { connect } = __webpack_require__(18); -const { bindActionCreators } = __webpack_require__(19); - -const Tree = createFactory(_devtoolsComponents2.default.Tree); -__webpack_require__(52); - -const classnames = __webpack_require__(53); -const { - MODE -} = __webpack_require__(3); - -const Utils = __webpack_require__(10); - -const { - getChildren, - getClosestGripNode, - getParent, - getValue, - nodeHasAccessors, - nodeHasProperties, - nodeIsBlock, - nodeIsDefaultProperties, - nodeIsFunction, - nodeIsGetter, - nodeIsMapEntry, - nodeIsMissingArguments, - nodeIsOptimizedOut, - nodeIsPrimitive, - nodeIsPrototype, - nodeIsSetter, - nodeIsUninitializedBinding, - nodeIsUnmappedBinding, - nodeIsUnscopedBinding, - nodeIsWindow, - nodeIsLongString, - nodeHasFullText -} = Utils.node; - -// This implements a component that renders an interactive inspector -// for looking at JavaScript objects. It expects descriptions of -// objects from the protocol, and will dynamically fetch children -// properties as objects are expanded. -// -// If you want to inspect a single object, pass the name and the -// protocol descriptor of it: -// -// ObjectInspector({ -// name: "foo", -// desc: { writable: true, ..., { value: { actor: "1", ... }}}, -// ... -// }) -// -// If you want multiple top-level objects (like scopes), you can pass -// an array of manually constructed nodes as `roots`: -// -// ObjectInspector({ -// roots: [{ name: ... }, ...], -// ... -// }); - -// There are 3 types of nodes: a simple node with a children array, an -// object that has properties that should be children when they are -// fetched, and a primitive value that should be displayed with no -// children. - -class ObjectInspector extends Component { - constructor(props) { - super(); - this.cachedNodes = new Map(); - - const self = this; - - self.getItemChildren = this.getItemChildren.bind(this); - self.renderTreeItem = this.renderTreeItem.bind(this); - self.setExpanded = this.setExpanded.bind(this); - self.focusItem = this.focusItem.bind(this); - self.getRoots = this.getRoots.bind(this); - } - - shouldComponentUpdate(nextProps) { - const { - expandedPaths, - focusedItem, - loadedProperties, - roots - } = this.props; - - if (roots !== nextProps.roots) { - // Since the roots changed, we assume the properties did as well, so we need to - // cleanup the component internal state. - - // We can clear the cachedNodes to avoid bugs and memory leaks. - this.cachedNodes.clear(); - // The rootsChanged action will be handled in a middleware to release the actors - // of the old roots, as well as cleanup the state properties (expandedPaths, - // loadedProperties, …). - this.props.rootsChanged(nextProps); - // We don't render right away since the state is going to be changed by the - // rootsChanged action. The `state.forceUpdate` flag will be set to `true` so we - // can execute a new render cycle with the cleaned state. - return false; - } - - if (nextProps.forceUpdate === true) { - return true; - } - - // We should update if: - // - there are new loaded properties - // - OR the expanded paths number changed, and all of them have properties loaded - // - OR the expanded paths number did not changed, but old and new sets differ - // - OR the focused node changed. - return loadedProperties.size !== nextProps.loadedProperties.size || expandedPaths.size !== nextProps.expandedPaths.size && [...nextProps.expandedPaths].every(path => nextProps.loadedProperties.has(path)) || expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key)) || focusedItem !== nextProps.focusedItem; - } - - componentDidUpdate(prevProps) { - if (this.props.forceUpdate) { - // If the component was updated, we can then reset the forceUpdate flag. - this.props.forceUpdated(); - } - } - - componentWillUnmount() { - const { releaseActor } = this.props; - if (typeof releaseActor !== "function") { - return; - } - - const { actors } = this.props; - for (let actor of actors) { - releaseActor(actor); - } - } - - getItemChildren(item) { - const { - loadedProperties - } = this.props; - const { cachedNodes } = this; - - return getChildren({ - loadedProperties, - cachedNodes, - item - }); - } - - getRoots() { - return this.props.roots; - } - - getNodeKey(item) { - return item.path && typeof item.path.toString === "function" ? item.path.toString() : JSON.stringify(item); - } - - setExpanded(item, expand) { - if (nodeIsPrimitive(item)) { - return; - } - - const { - createObjectClient, - createLongStringClient, - loadedProperties, - nodeExpand, - nodeCollapse, - roots - } = this.props; - - if (expand === true) { - const gripItem = getClosestGripNode(item); - const value = getValue(gripItem); - const isRoot = value && roots.some(root => { - const rootValue = getValue(root); - return rootValue && rootValue.actor === value.actor; - }); - const actor = isRoot || !value ? null : value.actor; - nodeExpand(item, actor, loadedProperties, createObjectClient, createLongStringClient); - } else { - nodeCollapse(item); - } - } - - focusItem(item) { - const { - focusable = true, - focusedItem, - nodeFocus, - onFocus - } = this.props; - - if (focusable && focusedItem !== item) { - nodeFocus(item); - if (focusedItem !== item && onFocus) { - onFocus(item); - } - } - } - - getTreeItemLabelAndValue(item, depth, expanded) { - const label = item.name; - const isPrimitive = nodeIsPrimitive(item); - - if (nodeIsOptimizedOut(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(optimized away)") - }; - } - - if (nodeIsUninitializedBinding(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(uninitialized)") - }; - } - - if (nodeIsUnmappedBinding(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(unmapped)") - }; - } - - if (nodeIsUnscopedBinding(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(unscoped)") - }; - } - - if (nodeIsOptimizedOut(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(optimized away)") - }; - } - - const itemValue = getValue(item); - const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable"); - - if (nodeIsMissingArguments(item) || unavailable) { - return { - label, - value: dom.span({ className: "unavailable" }, "(unavailable)") - }; - } - - if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) { - return { - label: Utils.renderRep(item, { - ...this.props, - functionName: label - }) - }; - } - - if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || nodeIsLongString(item) || isPrimitive) { - let repProps = { ...this.props }; - if (depth > 0) { - repProps.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY; - } - if (expanded) { - repProps.mode = MODE.TINY; - } - - if (nodeIsLongString(item)) { - repProps.member = { - open: nodeHasFullText(item) && expanded - }; - } - - return { - label, - value: Utils.renderRep(item, repProps) - }; - } - - return { - label - }; - } - - renderTreeItemLabel(label, item, depth, focused, expanded) { - if (label === null || typeof label === "undefined") { - return null; - } - - const { - onLabelClick - } = this.props; - - return dom.span({ - className: "object-label", - onClick: onLabelClick ? event => { - event.stopPropagation(); - - // If the user selected text, bail out. - if (Utils.selection.documentHasSelection()) { - return; - } - - onLabelClick(item, { - depth, - focused, - expanded, - setExpanded: this.setExpanded - }); - } : undefined - }, label); - } - - getTreeTopElementProps(item, depth, focused, expanded) { - const { - onCmdCtrlClick, - onDoubleClick, - dimTopLevelWindow - } = this.props; - - let parentElementProps = { - className: classnames("node object-node", { - focused, - lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0), - block: nodeIsBlock(item) - }), - onClick: e => { - if (e.metaKey && onCmdCtrlClick) { - onCmdCtrlClick(item, { - depth, - event: e, - focused, - expanded - }); - e.stopPropagation(); - return; - } - - // If this click happened because the user selected some text, bail out. - // Note that if the user selected some text before and then clicks here, - // the previously selected text will be first unselected, unless the user - // clicked on the arrow itself. Indeed because the arrow is an image, clicking on - // it does not remove any existing text selection. So we need to also check if - // teh arrow was clicked. - if (Utils.selection.documentHasSelection() && !(e.target && e.target.matches && e.target.matches(".arrow"))) { - e.stopPropagation(); - } - } - }; - - if (onDoubleClick) { - parentElementProps.onDoubleClick = e => { - e.stopPropagation(); - onDoubleClick(item, { - depth, - focused, - expanded - }); - }; - } - - return parentElementProps; - } - - renderTreeItem(item, depth, focused, arrow, expanded) { - const { label, value } = this.getTreeItemLabelAndValue(item, depth, expanded); - const labelElement = this.renderTreeItemLabel(label, item, depth, focused, expanded); - const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null; - - return dom.div(this.getTreeTopElementProps(item, depth, focused, expanded), arrow, labelElement, delimiter, value); - } - - render() { - const { - autoExpandAll = true, - autoExpandDepth = 1, - focusable = true, - disableWrap = false, - expandedPaths, - focusedItem, - inline - } = this.props; - - return Tree({ - className: classnames({ - inline, - nowrap: disableWrap, - "object-inspector": true - }), - autoExpandAll, - autoExpandDepth, - - isExpanded: item => expandedPaths && expandedPaths.has(item.path), - isExpandable: item => nodeIsPrimitive(item) === false, - focused: focusedItem, - - getRoots: this.getRoots, - getParent, - getChildren: this.getItemChildren, - getKey: this.getNodeKey, - - onExpand: item => this.setExpanded(item, true), - onCollapse: item => this.setExpanded(item, false), - onFocus: focusable ? this.focusItem : null, - - renderItem: this.renderTreeItem - }); - } -} - -function mapStateToProps(state, props) { - return { - actors: state.actors, - expandedPaths: state.expandedPaths, - // If the root changes, we want to pass a possibly new focusedItem property - focusedItem: state.roots !== props.roots ? props.focusedItem : state.focusedItem, - loadedProperties: state.loadedProperties, - forceUpdate: state.forceUpdate - }; -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators(__webpack_require__(55), dispatch); -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(ObjectInspector); - -/***/ }), -/* 49 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _tree = __webpack_require__(50); +var _tree = __webpack_require__(3670); var _tree2 = _interopRequireDefault(_tree); @@ -5762,7 +3626,8 @@ module.exports = { * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /***/ }), -/* 50 */ + +/***/ 3670: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5772,15 +3637,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _react = __webpack_require__(9); +var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -var _reactDomFactories = __webpack_require__(1); +var _reactDomFactories = __webpack_require__(3643); var _reactDomFactories2 = _interopRequireDefault(_reactDomFactories); -var _propTypes = __webpack_require__(2); +var _propTypes = __webpack_require__(3642); var _propTypes2 = _interopRequireDefault(_propTypes); @@ -5788,11 +3653,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const { Component, createFactory } = _react2.default; /* 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/. */ + * file, You can obtain one at . */ -__webpack_require__(51); +__webpack_require__(3671); -const AUTO_EXPAND_DEPTH = 0; // depth +// depth +const AUTO_EXPAND_DEPTH = 0; /** * An arrow that displays whether its node is expanded (▼) or collapsed @@ -5810,9 +3676,7 @@ class ArrowExpander extends Component { } render() { - const { - expanded - } = this.props; + const { expanded } = this.props; const classNames = ["arrow"]; if (expanded) { @@ -5870,11 +3734,11 @@ class TreeNode extends Component { } const indents = Array.from({ length: depth }).fill(treeIndent); - let items = indents.concat(renderItem(item, depth, focused, arrow, expanded)); + const items = indents.concat(renderItem(item, depth, focused, arrow, expanded)); return _reactDomFactories2.default.div({ id, - className: "tree-node" + (focused ? " focused" : ""), + className: `tree-node${focused ? " focused" : ""}`, onClick: this.props.onClick, role: "treeitem", "aria-level": depth + 1, @@ -5930,8 +3794,8 @@ function oncePerAnimationFrame(fn) { * "traditional" tree or as rows in a table or anything else. It doesn't * restrict you to only one certain kind of tree. * - * The tree comes with basic styling for the indent, the arrow, as well as hovered - * and focused styles which can be override in CSS. + * The tree comes with basic styling for the indent, the arrow, as well as + * hovered and focused styles which can be override in CSS. * * ### Example Usage * @@ -6087,15 +3951,15 @@ class Tree extends Component { // Note: the two properties below are mutually exclusive. Only one of the // label properties is necessary. - // ID of an element whose textual content serves as an accessible label for - // a tree. + // ID of an element whose textual content serves as an accessible label + // for a tree. labelledby: _propTypes2.default.string, // Accessibility label for a tree widget. label: _propTypes2.default.string, - // Optional event handlers for when items are expanded or collapsed. Useful - // for dispatching redux events and updating application state, maybe lazily - // loading subtrees from a worker, etc. + // Optional event handlers for when items are expanded or collapsed. + // Useful for dispatching redux events and updating application state, + // maybe lazily loading subtrees from a worker, etc. // // Type: // onExpand(item: Item) @@ -6106,8 +3970,9 @@ class Tree extends Component { // onExpand: item => dispatchExpandActionToRedux(item) onExpand: _propTypes2.default.func, onCollapse: _propTypes2.default.func, - // Optional event handler called with the current focused node when the Enter key - // is pressed. Can be useful to allow further keyboard actions within the tree node. + // Optional event handler called with the current focused node when the + // Enter key is pressed. Can be useful to allow further keyboard actions + // within the tree node. onActivate: _propTypes2.default.func, isExpandable: _propTypes2.default.func, // Additional classes to add to the root element. @@ -6165,7 +4030,7 @@ class Tree extends Component { } componentDidUpdate(prevProps, prevState) { - if (prevProps.focused !== this.props.focused) { + if (this.props.focused && prevProps.focused !== this.props.focused) { this._scrollNodeIntoView(this.props.focused); // Always keep the focus on the tree itself. this.treeRef.focus(); @@ -6304,9 +4169,9 @@ class Tree extends Component { * * @param {Object|undefined} options * An options object which can contain: - * - dir: "up" or "down" to indicate if we should scroll the element to the - * top or the bottom of the scrollable container when the element is - * off canvas. + * - dir: "up" or "down" to indicate if we should scroll the element + * to the top or the bottom of the scrollable container when + * the element is off canvas. */ _focus(item, options = {}) { const { preventAutoScroll } = options; @@ -6326,9 +4191,9 @@ class Tree extends Component { * * @param {Object|undefined} options * An options object which can contain: - * - dir: "up" or "down" to indicate if we should scroll the element to the - * top or the bottom of the scrollable container when the element is - * off canvas. + * - dir: "up" or "down" to indicate if we should scroll the element + * to the top or the bottom of the scrollable container when + * the element is off canvas. */ _scrollNodeIntoView(item, options = {}) { if (item !== undefined) { @@ -6353,7 +4218,7 @@ class Tree extends Component { if (!isVisible) { const { alignTo } = options; - let scrollToTop = alignTo ? alignTo === "top" : !scrolledParentRect || top < scrolledParentRect.top; + const scrollToTop = alignTo ? alignTo === "top" : !scrolledParentRect || top < scrolledParentRect.top; element.scrollIntoView(scrollToTop); } } @@ -6518,9 +4383,7 @@ class Tree extends Component { render() { const traversal = this._dfsFromRoots(); - const { - focused - } = this.props; + const { focused } = this.props; const nodes = traversal.map((v, i) => { const { item, depth } = traversal[i]; @@ -6538,8 +4401,8 @@ class Tree extends Component { onExpand: this._onExpand, onCollapse: this._onCollapse, onClick: e => { - // Since the user just clicked the node, there's no need to check if it should - // be scrolled into view. + // Since the user just clicked the node, there's no need to check if + // it should be scrolled into view. this._focus(item, { preventAutoScroll: true }); if (this.props.isExpanded(item)) { this.props.onCollapse(item); @@ -6570,7 +4433,7 @@ class Tree extends Component { return; } - let { explicitOriginalTarget } = nativeEvent; + const { explicitOriginalTarget } = nativeEvent; // Only set default focus to the first tree node if the focus came // from outside the tree (e.g. by tabbing to the tree from other // external elements). @@ -6579,10 +4442,6 @@ class Tree extends Component { } }, onBlur: this._onBlur, - onClick: () => { - // Focus should always remain on the tree container itself. - this.treeRef.focus(); - }, "aria-label": this.props.label, "aria-labelledby": this.props.labelledby, "aria-activedescendant": focused && this.props.getKey(focused), @@ -6594,74 +4453,22 @@ class Tree extends Component { exports.default = Tree; /***/ }), -/* 51 */ + +/***/ 3671: /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), -/* 52 */ + +/***/ 3672: /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), -/* 53 */ -/***/ (function(module, exports, __webpack_require__) { -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! - Copyright (c) 2016 Jed Watson. - Licensed under the MIT License (MIT), see - http://jedwatson.github.io/classnames -*/ -/* global define */ - -(function () { - 'use strict'; - - var hasOwn = {}.hasOwnProperty; - - function classNames () { - var classes = []; - - for (var i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - if (!arg) continue; - - var argType = typeof arg; - - if (argType === 'string' || argType === 'number') { - classes.push(arg); - } else if (Array.isArray(arg)) { - classes.push(classNames.apply(null, arg)); - } else if (argType === 'object') { - for (var key in arg) { - if (hasOwn.call(arg, key) && arg[key]) { - classes.push(key); - } - } - } - } - - return classes.join(' '); - } - - if (typeof module !== 'undefined' && module.exports) { - module.exports = classNames; - } else if (true) { - // register as 'classnames', consistent with npm package name - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () { - return classNames; - }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else { - window.classNames = classNames; - } -}()); - - -/***/ }), -/* 54 */ +/***/ 3673: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -6669,7 +4476,2084 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! /* 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/. */ + * file, You can obtain one at . */ + +// Dependencies +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders undefined value + */ +const Undefined = function () { + return span({ className: "objectBox objectBox-undefined" }, "undefined"); +}; + +function supportsObject(object, noGrip = false) { + if (noGrip === true) { + return object === undefined; + } + + return object && object.type && object.type == "undefined" || getGripType(object, noGrip) == "undefined"; +} + +// Exports from this module + +module.exports = { + rep: wrapRender(Undefined), + supportsObject +}; + +/***/ }), + +/***/ 3674: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const { wrapRender } = __webpack_require__(3644); +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders null value + */ +function Null(props) { + return span({ className: "objectBox objectBox-null" }, "null"); +} + +function supportsObject(object, noGrip = false) { + if (noGrip === true) { + return object === null; + } + + if (object && object.type && object.type == "null") { + return true; + } + + return object == null; +} + +// Exports from this module + +module.exports = { + rep: wrapRender(Null), + supportsObject +}; + +/***/ }), + +/***/ 3675: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); + +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a number + */ +Number.propTypes = { + object: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.bool]).isRequired +}; + +function Number(props) { + const value = props.object; + + return span({ className: "objectBox objectBox-number" }, stringify(value)); +} + +function stringify(object) { + const isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0"; + + return isNegativeZero ? "-0" : String(object); +} + +function supportsObject(object, noGrip = false) { + return ["boolean", "number", "-0"].includes(getGripType(object, noGrip)); +} + +// Exports from this module + +module.exports = { + rep: wrapRender(Number), + supportsObject +}; + +/***/ }), + +/***/ 3676: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +/* 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 . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); +const { wrapRender, ellipsisElement } = __webpack_require__(3644); +const PropRep = __webpack_require__(3650); +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +const DEFAULT_TITLE = "Object"; + +/** + * Renders an object. An object is represented by a list of its + * properties enclosed in curly brackets. + */ +ObjectRep.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + title: PropTypes.string +}; + +function ObjectRep(props) { + const object = props.object; + const propsArray = safePropIterator(props, object); + + if (props.mode === MODE.TINY) { + const tinyModeItems = []; + if (getTitle(props, object) !== DEFAULT_TITLE) { + tinyModeItems.push(getTitleElement(props, object)); + } else { + tinyModeItems.push(span({ + className: "objectLeftBrace" + }, "{"), propsArray.length > 0 ? ellipsisElement : null, span({ + className: "objectRightBrace" + }, "}")); + } + + return span({ className: "objectBox objectBox-object" }, ...tinyModeItems); + } + + return span({ className: "objectBox objectBox-object" }, getTitleElement(props, object), span({ + className: "objectLeftBrace" + }, " { "), ...propsArray, span({ + className: "objectRightBrace" + }, " }")); +} + +function getTitleElement(props, object) { + return span({ className: "objectTitle" }, getTitle(props, object)); +} + +function getTitle(props, object) { + return props.title || DEFAULT_TITLE; +} + +function safePropIterator(props, object, max) { + max = typeof max === "undefined" ? 3 : max; + try { + return propIterator(props, object, max); + } catch (err) { + console.error(err); + } + return []; +} + +function propIterator(props, object, max) { + // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377 + if (Object.prototype.toString.call(object) === "[object Generator]") { + object = Object.getPrototypeOf(object); + } + + const elements = []; + const unimportantProperties = []; + let propertiesNumber = 0; + const propertiesNames = Object.keys(object); + + const pushPropRep = (name, value) => { + elements.push(PropRep(_extends({}, props, { + key: name, + mode: MODE.TINY, + name, + object: value, + equal: ": " + }))); + propertiesNumber++; + + if (propertiesNumber < propertiesNames.length) { + elements.push(", "); + } + }; + + try { + for (const name of propertiesNames) { + if (propertiesNumber >= max) { + break; + } + + let value; + try { + value = object[name]; + } catch (exc) { + continue; + } + + // Object members with non-empty values are preferred since it gives the + // user a better overview of the object. + if (isInterestingProp(value)) { + pushPropRep(name, value); + } else { + // If the property is not important, put its name on an array for later + // use. + unimportantProperties.push(name); + } + } + } catch (err) { + console.error(err); + } + + if (propertiesNumber < max) { + for (const name of unimportantProperties) { + if (propertiesNumber >= max) { + break; + } + + let value; + try { + value = object[name]; + } catch (exc) { + continue; + } + + pushPropRep(name, value); + } + } + + if (propertiesNumber < propertiesNames.length) { + elements.push(ellipsisElement); + } + + return elements; +} + +function isInterestingProp(value) { + const type = typeof value; + return type == "boolean" || type == "number" || type == "string" && value; +} + +function supportsObject(object) { + return true; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ObjectRep), + supportsObject +}; + +/***/ }), + +/***/ 3677: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); + +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a symbol. + */ +SymbolRep.propTypes = { + object: PropTypes.object.isRequired +}; + +function SymbolRep(props) { + const { className = "objectBox objectBox-symbol", object } = props; + const { name } = object; + + return span({ + className, + "data-link-actor-id": object.actor + }, `Symbol(${name || ""})`); +} + +function supportsObject(object, noGrip = false) { + return getGripType(object, noGrip) == "symbol"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(SymbolRep), + supportsObject +}; + +/***/ }), + +/***/ 3678: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); + +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a Infinity object + */ +InfinityRep.propTypes = { + object: PropTypes.object.isRequired +}; + +function InfinityRep(props) { + const { object } = props; + + return span({ className: "objectBox objectBox-number" }, object.type); +} + +function supportsObject(object, noGrip = false) { + const type = getGripType(object, noGrip); + return type == "Infinity" || type == "-Infinity"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(InfinityRep), + supportsObject +}; + +/***/ }), + +/***/ 3679: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a NaN object + */ +function NaNRep(props) { + return span({ className: "objectBox objectBox-nan" }, "NaN"); +} + +function supportsObject(object, noGrip = false) { + return getGripType(object, noGrip) == "NaN"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(NaNRep), + supportsObject +}; + +/***/ }), + +/***/ 3680: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const dom = __webpack_require__(3643); +const PropTypes = __webpack_require__(3642); +const { wrapRender } = __webpack_require__(3644); +const { MODE } = __webpack_require__(3645); +const { span } = dom; + +/** + * Renders an object. An object is represented by a list of its + * properties enclosed in curly brackets. + */ +Accessor.propTypes = { + object: PropTypes.object.isRequired, + mode: PropTypes.oneOf(Object.values(MODE)) +}; + +function Accessor(props) { + const { object } = props; + + const accessors = []; + if (hasGetter(object)) { + accessors.push("Getter"); + } + if (hasSetter(object)) { + accessors.push("Setter"); + } + const title = accessors.join(" & "); + + return span({ className: "objectBox objectBox-accessor objectTitle" }, title); +} + +function hasGetter(object) { + return object && object.get && object.get.type !== "undefined"; +} + +function hasSetter(object) { + return object && object.set && object.set.type !== "undefined"; +} + +function supportsObject(object, noGrip = false) { + if (noGrip !== true && (hasGetter(object) || hasSetter(object))) { + return true; + } + + return false; +} + +// Exports from this module +module.exports = { + rep: wrapRender(Accessor), + supportsObject +}; + +/***/ }), + +/***/ 3681: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); +const dom = __webpack_require__(3643); +const { span } = dom; + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); +const { rep: StringRep } = __webpack_require__(3648); + +/** + * Renders DOM attribute + */ +Attribute.propTypes = { + object: PropTypes.object.isRequired +}; + +function Attribute(props) { + const { object } = props; + const value = object.preview.value; + + return span({ + "data-link-actor-id": object.actor, + className: "objectBox-Attr" + }, span({ className: "attrName" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); +} + +function getTitle(grip) { + return grip.preview.nodeName; +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return getGripType(grip, noGrip) == "Attr" && grip.preview; +} + +module.exports = { + rep: wrapRender(Attribute), + supportsObject +}; + +/***/ }), + +/***/ 3682: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Used to render JS built-in Date() object. + */ +DateTime.propTypes = { + object: PropTypes.object.isRequired +}; + +function DateTime(props) { + const grip = props.object; + let date; + try { + date = span({ + "data-link-actor-id": grip.actor, + className: "objectBox" + }, getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString())); + } catch (e) { + date = span({ className: "objectBox" }, "Invalid Date"); + } + + return date; +} + +function getTitle(grip) { + return span({ + className: "objectTitle" + }, `${grip.class} `); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return getGripType(grip, noGrip) == "Date" && grip.preview; +} + +// Exports from this module +module.exports = { + rep: wrapRender(DateTime), + supportsObject +}; + +/***/ }), + +/***/ 3683: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { + getGripType, + isGrip, + getURLDisplayString, + wrapRender +} = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM document object. + */ +Document.propTypes = { + object: PropTypes.object.isRequired +}; + +function Document(props) { + const grip = props.object; + const location = getLocation(grip); + return span({ + "data-link-actor-id": grip.actor, + className: "objectBox objectBox-document" + }, getTitle(grip), location ? span({ className: "location" }, ` ${location}`) : null); +} + +function getLocation(grip) { + const location = grip.preview.location; + return location ? getURLDisplayString(location) : null; +} + +function getTitle(grip) { + return span({ + className: "objectTitle" + }, grip.class); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + const type = getGripType(object, noGrip); + return object.preview && (type === "HTMLDocument" || type === "XULDocument"); +} + +// Exports from this module +module.exports = { + rep: wrapRender(Document), + supportsObject +}; + +/***/ }), + +/***/ 3684: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM documentType object. + */ +DocumentType.propTypes = { + object: PropTypes.object.isRequired +}; + +function DocumentType(props) { + const { object } = props; + const name = object && object.preview && object.preview.nodeName ? ` ${object.preview.nodeName}` : ""; + return span({ + "data-link-actor-id": props.object.actor, + className: "objectBox objectBox-document" + }, ``); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + const type = getGripType(object, noGrip); + return object.preview && type === "DocumentType"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(DocumentType), + supportsObject +}; + +/***/ }), + +/***/ 3685: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, wrapRender } = __webpack_require__(3644); + +const { MODE } = __webpack_require__(3645); +const { rep } = __webpack_require__(3656); + +/** + * Renders DOM event objects. + */ +Event.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function Event(props) { + const gripProps = _extends({}, props, { + title: getTitle(props), + object: _extends({}, props.object, { + preview: _extends({}, props.object.preview, { + ownProperties: {} + }) + }) + }); + + if (gripProps.object.preview.target) { + Object.assign(gripProps.object.preview.ownProperties, { + target: gripProps.object.preview.target + }); + } + Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties); + + delete gripProps.object.preview.properties; + gripProps.object.ownPropertyLength = Object.keys(gripProps.object.preview.ownProperties).length; + + switch (gripProps.object.class) { + case "MouseEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name); + }; + break; + case "KeyboardEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "key", "charCode", "keyCode"].includes(name); + }; + break; + case "MessageEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "isTrusted", "data"].includes(name); + }; + break; + default: + gripProps.isInterestingProp = (type, value, name) => { + // We want to show the properties in the order they are declared. + return Object.keys(gripProps.object.preview.ownProperties).includes(name); + }; + } + + return rep(gripProps); +} + +function getTitle(props) { + const preview = props.object.preview; + let title = preview.type; + + if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) { + title = `${title} ${preview.modifiers.join("-")}`; + } + return title; +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.preview.kind == "DOMEvent"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(Event), + supportsObject +}; + +/***/ }), + +/***/ 3686: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); +// Dependencies +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); + +const PropRep = __webpack_require__(3650); +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a DOM Promise object. + */ +PromiseRep.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function PromiseRep(props) { + const object = props.object; + const { promiseState } = object; + + const config = { + "data-link-actor-id": object.actor, + className: "objectBox objectBox-object" + }; + + if (props.mode === MODE.TINY) { + const { Rep } = __webpack_require__(3647); + + return span(config, getTitle(object), span({ + className: "objectLeftBrace" + }, " { "), Rep({ object: promiseState.state }), span({ + className: "objectRightBrace" + }, " }")); + } + + const propsArray = getProps(props, promiseState); + return span(config, getTitle(object), span({ + className: "objectLeftBrace" + }, " { "), ...propsArray, span({ + className: "objectRightBrace" + }, " }")); +} + +function getTitle(object) { + return span({ + className: "objectTitle" + }, object.class); +} + +function getProps(props, promiseState) { + const keys = ["state"]; + if (Object.keys(promiseState).includes("value")) { + keys.push("value"); + } + + return keys.reduce((res, key, i) => { + const object = promiseState[key]; + res = res.concat(PropRep(_extends({}, props, { + mode: MODE.TINY, + name: `<${key}>`, + object, + equal: ": ", + suppressQuotes: true + }))); + + // Interleave commas between elements + if (i !== keys.length - 1) { + res.push(", "); + } + + return res; + }, []); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return getGripType(object, noGrip) == "Promise"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(PromiseRep), + supportsObject +}; + +/***/ }), + +/***/ 3687: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip object with regular expression. + */ +RegExp.propTypes = { + object: PropTypes.object.isRequired +}; + +function RegExp(props) { + const { object } = props; + + return span({ + "data-link-actor-id": object.actor, + className: "objectBox objectBox-regexp regexpSource" + }, getSource(object)); +} + +function getSource(grip) { + return grip.displayString; +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + return getGripType(object, noGrip) == "RegExp"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(RegExp), + supportsObject +}; + +/***/ }), + +/***/ 3688: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { + getGripType, + isGrip, + getURLDisplayString, + wrapRender +} = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip representing CSSStyleSheet + */ +StyleSheet.propTypes = { + object: PropTypes.object.isRequired +}; + +function StyleSheet(props) { + const grip = props.object; + + return span({ + "data-link-actor-id": grip.actor, + className: "objectBox objectBox-object" + }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip))); +} + +function getTitle(grip) { + const title = "StyleSheet "; + return span({ className: "objectBoxTitle" }, title); +} + +function getLocation(grip) { + // Embedded stylesheets don't have URL and so, no preview. + const url = grip.preview ? grip.preview.url : ""; + return url ? getURLDisplayString(url) : ""; +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + return getGripType(object, noGrip) == "CSSStyleSheet"; +} + +// Exports from this module + +module.exports = { + rep: wrapRender(StyleSheet), + supportsObject +}; + +/***/ }), + +/***/ 3689: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); +const { + isGrip, + cropString, + cropMultipleLines, + wrapRender +} = __webpack_require__(3644); +const { MODE } = __webpack_require__(3645); +const nodeConstants = __webpack_require__(3659); +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM comment node. + */ +CommentNode.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) +}; + +function CommentNode(props) { + const { object, mode = MODE.SHORT } = props; + + let { textContent } = object.preview; + if (mode === MODE.TINY) { + textContent = cropMultipleLines(textContent, 30); + } else if (mode === MODE.SHORT) { + textContent = cropString(textContent, 50); + } + + return span({ + className: "objectBox theme-comment", + "data-link-actor-id": object.actor + }, ``); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; +} + +// Exports from this module +module.exports = { + rep: wrapRender(CommentNode), + supportsObject +}; + +/***/ }), + +/***/ 3690: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Utils +const { isGrip, wrapRender } = __webpack_require__(3644); +const { rep: StringRep } = __webpack_require__(3648); +const { MODE } = __webpack_require__(3645); +const nodeConstants = __webpack_require__(3659); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM element node. + */ +ElementNode.propTypes = { + object: PropTypes.object.isRequired, + inspectIconTitle: PropTypes.string, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeClick: PropTypes.func, + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function ElementNode(props) { + const { + object, + inspectIconTitle, + mode, + onDOMNodeClick, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; + const elements = getElements(object, mode); + + const isInTree = object.preview && object.preview.isConnected === true; + + const baseConfig = { + "data-link-actor-id": object.actor, + className: "objectBox objectBox-node" + }; + let inspectIcon; + if (isInTree) { + if (onDOMNodeClick) { + Object.assign(baseConfig, { + onClick: _ => onDOMNodeClick(object) + }); + } + + if (onDOMNodeMouseOver) { + Object.assign(baseConfig, { + onMouseOver: _ => onDOMNodeMouseOver(object) + }); + } + + if (onDOMNodeMouseOut) { + Object.assign(baseConfig, { + onMouseOut: onDOMNodeMouseOut + }); + } + + if (onInspectIconClick) { + inspectIcon = dom.button({ + className: "open-inspector", + // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands + title: inspectIconTitle || "Click to select the node in the inspector", + onClick: e => { + if (onDOMNodeClick) { + e.stopPropagation(); + } + + onInspectIconClick(object, e); + } + }); + } + } + + return span(baseConfig, ...elements, inspectIcon); +} + +function getElements(grip, mode) { + const { + attributes, + nodeName, + isAfterPseudoElement, + isBeforePseudoElement + } = grip.preview; + const nodeNameElement = span({ + className: "tag-name" + }, nodeName); + + if (isAfterPseudoElement || isBeforePseudoElement) { + return [span({ className: "attrName" }, `::${isAfterPseudoElement ? "after" : "before"}`)]; + } + + if (mode === MODE.TINY) { + const elements = [nodeNameElement]; + if (attributes.id) { + elements.push(span({ className: "attrName" }, `#${attributes.id}`)); + } + if (attributes.class) { + elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join(""))); + } + return elements; + } + + const attributeKeys = Object.keys(attributes); + if (attributeKeys.includes("class")) { + attributeKeys.splice(attributeKeys.indexOf("class"), 1); + attributeKeys.unshift("class"); + } + if (attributeKeys.includes("id")) { + attributeKeys.splice(attributeKeys.indexOf("id"), 1); + attributeKeys.unshift("id"); + } + const attributeElements = attributeKeys.reduce((arr, name, i, keys) => { + const value = attributes[name]; + const attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); + + return arr.concat([" ", attribute]); + }, []); + + return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")]; +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ElementNode), + supportsObject +}; + +/***/ }), + +/***/ 3691: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, cropString, wrapRender } = __webpack_require__(3644); +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM #text node. + */ +TextNode.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function TextNode(props) { + const { + object: grip, + mode = MODE.SHORT, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; + + const baseConfig = { + "data-link-actor-id": grip.actor, + className: "objectBox objectBox-textNode" + }; + let inspectIcon; + const isInTree = grip.preview && grip.preview.isConnected === true; + + if (isInTree) { + if (onDOMNodeMouseOver) { + Object.assign(baseConfig, { + onMouseOver: _ => onDOMNodeMouseOver(grip) + }); + } + + if (onDOMNodeMouseOut) { + Object.assign(baseConfig, { + onMouseOut: onDOMNodeMouseOut + }); + } + + if (onInspectIconClick) { + inspectIcon = dom.button({ + className: "open-inspector", + draggable: false, + // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands + title: "Click to select the node in the inspector", + onClick: e => onInspectIconClick(grip, e) + }); + } + } + + if (mode === MODE.TINY) { + return span(baseConfig, getTitle(grip), inspectIcon); + } + + return span(baseConfig, getTitle(grip), span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); +} + +function getTextContent(grip) { + return cropString(grip.preview.textContent); +} + +function getTitle(grip) { + const title = "#text"; + return span({}, title); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.class == "Text"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(TextNode), + supportsObject +}; + +/***/ }), + +/***/ 3692: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { + getGripType, + isGrip, + getURLDisplayString, + wrapRender +} = __webpack_require__(3644); + +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip representing a window. + */ +WindowRep.propTypes = { + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + object: PropTypes.object.isRequired +}; + +function WindowRep(props) { + const { mode, object } = props; + + const config = { + "data-link-actor-id": object.actor, + className: "objectBox objectBox-Window" + }; + + if (mode === MODE.TINY) { + return span(config, getTitle(object)); + } + + return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object))); +} + +function getTitle(object, trailingSpace) { + let title = object.displayClass || object.class || "Window"; + if (trailingSpace === true) { + title = `${title} `; + } + return span({ className: "objectTitle" }, title); +} + +function getLocation(object) { + return getURLDisplayString(object.preview.url); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + return object.preview && getGripType(object, noGrip) == "Window"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(WindowRep), + supportsObject +}; + +/***/ }), + +/***/ 3693: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, wrapRender } = __webpack_require__(3644); + +const String = __webpack_require__(3648).rep; + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip object with textual data. + */ +ObjectWithText.propTypes = { + object: PropTypes.object.isRequired +}; + +function ObjectWithText(props) { + const grip = props.object; + return span({ + "data-link-actor-id": grip.actor, + className: `objectTitle objectBox objectBox-${getType(grip)}` + }, `${getType(grip)} `, getDescription(grip)); +} + +function getType(grip) { + return grip.class; +} + +function getDescription(grip) { + return String({ + object: grip.preview.text + }); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.preview.kind == "ObjectWithText"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ObjectWithText), + supportsObject +}; + +/***/ }), + +/***/ 3694: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, getURLDisplayString, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip object with URL data. + */ +ObjectWithURL.propTypes = { + object: PropTypes.object.isRequired +}; + +function ObjectWithURL(props) { + const grip = props.object; + return span({ + "data-link-actor-id": grip.actor, + className: `objectBox objectBox-${getType(grip)}` + }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip))); +} + +function getTitle(grip) { + return span({ className: "objectTitle" }, `${getType(grip)} `); +} + +function getType(grip) { + return grip.class; +} + +function getDescription(grip) { + return getURLDisplayString(grip.preview.url); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.preview.kind == "ObjectWithURL"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ObjectWithURL), + supportsObject +}; + +/***/ }), + +/***/ 3695: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +const { createElement, createFactory, PureComponent } = __webpack_require__(0); +const { Provider } = __webpack_require__(3592); +const ObjectInspector = createFactory(__webpack_require__(3696)); +const createStore = __webpack_require__(3700); +const Utils = __webpack_require__(3657); +const { renderRep, shouldRenderRootsInReps } = Utils; + +class OI extends PureComponent { + constructor(props) { + super(props); + this.store = createStore(props); + } + + getStore() { + return this.store; + } + + render() { + return createElement(Provider, { store: this.store }, ObjectInspector(this.props)); + } +} + +module.exports = props => { + const { roots } = props; + if (shouldRenderRootsInReps(roots)) { + return renderRep(roots[0], props); + } + return new OI(props); +}; + +/***/ }), + +/***/ 3696: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _devtoolsComponents = __webpack_require__(3669); + +var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* 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 . */ + +const { Component, createFactory } = __webpack_require__(0); +const dom = __webpack_require__(3643); +const { connect } = __webpack_require__(3592); +const { bindActionCreators } = __webpack_require__(3593); + +const Tree = createFactory(_devtoolsComponents2.default.Tree); +__webpack_require__(3697); + +const classnames = __webpack_require__(175); +const { MODE } = __webpack_require__(3645); + +const Utils = __webpack_require__(3657); + +const { + getChildren, + getClosestGripNode, + getParent, + getValue, + nodeHasAccessors, + nodeHasProperties, + nodeIsBlock, + nodeIsDefaultProperties, + nodeIsFunction, + nodeIsGetter, + nodeIsMapEntry, + nodeIsMissingArguments, + nodeIsOptimizedOut, + nodeIsPrimitive, + nodeIsPrototype, + nodeIsSetter, + nodeIsUninitializedBinding, + nodeIsUnmappedBinding, + nodeIsUnscopedBinding, + nodeIsWindow, + nodeIsLongString, + nodeHasFullText +} = Utils.node; + +// This implements a component that renders an interactive inspector +// for looking at JavaScript objects. It expects descriptions of +// objects from the protocol, and will dynamically fetch children +// properties as objects are expanded. +// +// If you want to inspect a single object, pass the name and the +// protocol descriptor of it: +// +// ObjectInspector({ +// name: "foo", +// desc: { writable: true, ..., { value: { actor: "1", ... }}}, +// ... +// }) +// +// If you want multiple top-level objects (like scopes), you can pass +// an array of manually constructed nodes as `roots`: +// +// ObjectInspector({ +// roots: [{ name: ... }, ...], +// ... +// }); + +// There are 3 types of nodes: a simple node with a children array, an +// object that has properties that should be children when they are +// fetched, and a primitive value that should be displayed with no +// children. + +class ObjectInspector extends Component { + constructor(props) { + super(); + this.cachedNodes = new Map(); + + const self = this; + + self.getItemChildren = this.getItemChildren.bind(this); + self.renderTreeItem = this.renderTreeItem.bind(this); + self.setExpanded = this.setExpanded.bind(this); + self.focusItem = this.focusItem.bind(this); + self.getRoots = this.getRoots.bind(this); + } + + shouldComponentUpdate(nextProps) { + const { expandedPaths, focusedItem, loadedProperties, roots } = this.props; + + if (roots !== nextProps.roots) { + // Since the roots changed, we assume the properties did as well, + // so we need to cleanup the component internal state. + + // We can clear the cachedNodes to avoid bugs and memory leaks. + this.cachedNodes.clear(); + // The rootsChanged action will be handled in a middleware to release the + // actors of the old roots, as well as cleanup the state properties + // (expandedPaths, loadedProperties, …). + this.props.rootsChanged(nextProps); + // We don't render right away since the state is going to be changed by + // the rootsChanged action. The `state.forceUpdate` flag will be set + // to `true` so we can execute a new render cycle with the cleaned state. + return false; + } + + if (nextProps.forceUpdate === true) { + return true; + } + + // We should update if: + // - there are new loaded properties + // - OR the expanded paths number changed, and all of them have properties + // loaded + // - OR the expanded paths number did not changed, but old and new sets + // differ + // - OR the focused node changed. + return loadedProperties.size !== nextProps.loadedProperties.size || expandedPaths.size !== nextProps.expandedPaths.size && [...nextProps.expandedPaths].every(path => nextProps.loadedProperties.has(path)) || expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key)) || focusedItem !== nextProps.focusedItem; + } + + componentDidUpdate(prevProps) { + if (this.props.forceUpdate) { + // If the component was updated, we can then reset the forceUpdate flag. + this.props.forceUpdated(); + } + } + + componentWillUnmount() { + const { releaseActor } = this.props; + if (typeof releaseActor !== "function") { + return; + } + + const { actors } = this.props; + for (const actor of actors) { + releaseActor(actor); + } + } + + getItemChildren(item) { + const { loadedProperties } = this.props; + const { cachedNodes } = this; + + return getChildren({ + loadedProperties, + cachedNodes, + item + }); + } + + getRoots() { + return this.props.roots; + } + + getNodeKey(item) { + return item.path && typeof item.path.toString === "function" ? item.path.toString() : JSON.stringify(item); + } + + setExpanded(item, expand) { + if (nodeIsPrimitive(item)) { + return; + } + + const { + createObjectClient, + createLongStringClient, + loadedProperties, + nodeExpand, + nodeCollapse, + roots + } = this.props; + + if (expand === true) { + const gripItem = getClosestGripNode(item); + const value = getValue(gripItem); + const isRoot = value && roots.some(root => { + const rootValue = getValue(root); + return rootValue && rootValue.actor === value.actor; + }); + const actor = isRoot || !value ? null : value.actor; + nodeExpand(item, actor, loadedProperties, createObjectClient, createLongStringClient); + } else { + nodeCollapse(item); + } + } + + focusItem(item) { + const { focusable = true, focusedItem, nodeFocus, onFocus } = this.props; + + if (focusable && focusedItem !== item) { + nodeFocus(item); + if (focusedItem !== item && onFocus) { + onFocus(item); + } + } + } + + // eslint-disable-next-line complexity + getTreeItemLabelAndValue(item, depth, expanded) { + const label = item.name; + const isPrimitive = nodeIsPrimitive(item); + + if (nodeIsOptimizedOut(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(optimized away)") + }; + } + + if (nodeIsUninitializedBinding(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(uninitialized)") + }; + } + + if (nodeIsUnmappedBinding(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(unmapped)") + }; + } + + if (nodeIsUnscopedBinding(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(unscoped)") + }; + } + + const itemValue = getValue(item); + const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable"); + + if (nodeIsMissingArguments(item) || unavailable) { + return { + label, + value: dom.span({ className: "unavailable" }, "(unavailable)") + }; + } + + if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) { + return { + label: Utils.renderRep(item, _extends({}, this.props, { + functionName: label + })) + }; + } + + if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || nodeIsLongString(item) || isPrimitive) { + const repProps = _extends({}, this.props); + if (depth > 0) { + repProps.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY; + } + if (expanded) { + repProps.mode = MODE.TINY; + } + + if (nodeIsLongString(item)) { + repProps.member = { + open: nodeHasFullText(item) && expanded + }; + } + + return { + label, + value: Utils.renderRep(item, repProps) + }; + } + + return { + label + }; + } + + renderTreeItemLabel(label, item, depth, focused, expanded) { + if (label === null || typeof label === "undefined") { + return null; + } + + const { onLabelClick } = this.props; + + return dom.span({ + className: "object-label", + onClick: onLabelClick ? event => { + event.stopPropagation(); + + // If the user selected text, bail out. + if (Utils.selection.documentHasSelection()) { + return; + } + + onLabelClick(item, { + depth, + focused, + expanded, + setExpanded: this.setExpanded + }); + } : undefined + }, label); + } + + getTreeTopElementProps(item, depth, focused, expanded) { + const { onCmdCtrlClick, onDoubleClick, dimTopLevelWindow } = this.props; + + const parentElementProps = { + className: classnames("node object-node", { + focused, + lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0), + block: nodeIsBlock(item) + }), + onClick: e => { + if (e.metaKey && onCmdCtrlClick) { + onCmdCtrlClick(item, { + depth, + event: e, + focused, + expanded + }); + e.stopPropagation(); + return; + } + + // If this click happened because the user selected some text, bail out. + // Note that if the user selected some text before and then clicks here, + // the previously selected text will be first unselected, unless the + // user clicked on the arrow itself. Indeed because the arrow is an + // image, clicking on it does not remove any existing text selection. + // So we need to also check if the arrow was clicked. + if (Utils.selection.documentHasSelection() && !(e.target && e.target.matches && e.target.matches(".arrow"))) { + e.stopPropagation(); + } + } + }; + + if (onDoubleClick) { + parentElementProps.onDoubleClick = e => { + e.stopPropagation(); + onDoubleClick(item, { + depth, + focused, + expanded + }); + }; + } + + return parentElementProps; + } + + renderTreeItem(item, depth, focused, arrow, expanded) { + const { label, value } = this.getTreeItemLabelAndValue(item, depth, expanded); + const labelElement = this.renderTreeItemLabel(label, item, depth, focused, expanded); + const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null; + + return dom.div(this.getTreeTopElementProps(item, depth, focused, expanded), arrow, labelElement, delimiter, value); + } + + render() { + const { + autoExpandAll = true, + autoExpandDepth = 1, + focusable = true, + disableWrap = false, + expandedPaths, + focusedItem, + inline + } = this.props; + + return Tree({ + className: classnames({ + inline, + nowrap: disableWrap, + "object-inspector": true + }), + autoExpandAll, + autoExpandDepth, + + isExpanded: item => expandedPaths && expandedPaths.has(item.path), + isExpandable: item => nodeIsPrimitive(item) === false, + focused: focusedItem, + + getRoots: this.getRoots, + getParent, + getChildren: this.getItemChildren, + getKey: this.getNodeKey, + + onExpand: item => this.setExpanded(item, true), + onCollapse: item => this.setExpanded(item, false), + onFocus: focusable ? this.focusItem : null, + + renderItem: this.renderTreeItem + }); + } +} + +function mapStateToProps(state, props) { + return { + actors: state.actors, + expandedPaths: state.expandedPaths, + // If the root changes, we want to pass a possibly new focusedItem property + focusedItem: state.roots !== props.roots ? props.focusedItem : state.focusedItem, + loadedProperties: state.loadedProperties, + forceUpdate: state.forceUpdate + }; +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(__webpack_require__(3699), dispatch); +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(ObjectInspector); + +/***/ }), + +/***/ 3697: +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), + +/***/ 3698: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ function documentHasSelection() { const selection = getSelection(); @@ -6685,21 +6569,20 @@ module.exports = { }; /***/ }), -/* 55 */ + +/***/ 3699: /***/ (function(module, exports, __webpack_require__) { "use strict"; -const { - loadItemProperties -} = __webpack_require__(21); /* 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/. */ +const { loadItemProperties } = __webpack_require__(3666); /* 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 . */ /** - * This action is responsible for expanding a given node, - * which also means that it will call the action responsible to fetch properties. + * This action is responsible for expanding a given node, which also means that + * it will call the action responsible to fetch properties. */ function nodeExpand(node, actor, loadedProperties, createObjectClient, createLongStringClient) { return async ({ dispatch }) => { @@ -6728,8 +6611,9 @@ function nodeFocus(node) { }; } /* - * This action checks if we need to fetch properties, entries, prototype and symbols - * for a given node. If we do, it will call the appropriate ObjectClient functions. + * This action checks if we need to fetch properties, entries, prototype and + * symbols for a given node. If we do, it will call the appropriate ObjectClient + * functions. */ function nodeLoadProperties(item, actor, loadedProperties, createObjectClient, createLongStringClient) { return async ({ dispatch }) => { @@ -6750,11 +6634,12 @@ function nodePropertiesLoaded(node, actor, properties) { } /* - * This action is dispatched when the `roots` prop, provided by a consumer of the - * ObjectInspector (inspector, console, …), is modified. It will clean the internal - * state properties (expandedPaths, loadedProperties, …) and release the actors consumed - * with the previous roots. - * It takes a props argument which reflects what is passed by the upper-level consumer. + * This action is dispatched when the `roots` prop, provided by a consumer of + * the ObjectInspector (inspector, console, …), is modified. It will clean the + * internal state properties (expandedPaths, loadedProperties, …) and release + * the actors consumed with the previous roots. + * It takes a props argument which reflects what is passed by the upper-level + * consumer. */ function rootsChanged(props) { return { @@ -6783,30 +6668,34 @@ module.exports = { }; /***/ }), -/* 56 */ + +/***/ 3700: /***/ (function(module, exports, __webpack_require__) { "use strict"; +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + /* 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/. */ + * file, You can obtain one at . */ -const { applyMiddleware, createStore, compose } = __webpack_require__(19); -const { thunk } = __webpack_require__(57); -const { waitUntilService } = __webpack_require__(58); -const reducer = __webpack_require__(59); +const { applyMiddleware, createStore, compose } = __webpack_require__(3593); +const { thunk } = __webpack_require__(3701); +const { + waitUntilService +} = __webpack_require__(3702); +const reducer = __webpack_require__(3703); function createInitialState(overrides) { - return { + return _extends({ actors: new Set(), expandedPaths: new Set(), focusedItem: null, loadedProperties: new Map(), - forceUpdated: false, - ...overrides - }; + forceUpdated: false + }, overrides); } function enableStateReinitializer(props) { @@ -6820,14 +6709,14 @@ function enableStateReinitializer(props) { initialState.actors.forEach(props.releaseActor); } - return { - ...action.data, + return _extends({}, action.data, { actors: new Set(), expandedPaths: new Set(), loadedProperties: new Map(), - // Indicates to the component that we do want to render on the next render cycle. + // Indicates to the component that we do want to render on the next + // render cycle. forceUpdate: true - }; + }); } return next(reinitializerEnhancer, initialState, enhancer); }; @@ -6844,7 +6733,8 @@ module.exports = props => { }; /***/ }), -/* 57 */ + +/***/ 3701: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -6852,7 +6742,7 @@ module.exports = props => { /* 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/. */ + * file, You can obtain one at . */ /** * A middleware that allows thunks (functions) to be dispatched. @@ -6868,7 +6758,8 @@ function thunk({ dispatch, getState }) { exports.thunk = thunk; /***/ }), -/* 58 */ + +/***/ 3702: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -6876,7 +6767,7 @@ exports.thunk = thunk; /* 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/. */ + * file, You can obtain one at . */ const WAIT_UNTIL_TYPE = "@@service/waitUntil"; /** @@ -6942,19 +6833,19 @@ module.exports = { }; /***/ }), -/* 59 */ + +/***/ 3703: /***/ (function(module, exports, __webpack_require__) { "use strict"; -function reducer(state = {}, action) { - const { - type, - data - } = action; +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - const cloneState = overrides => ({ ...state, ...overrides }); +function reducer(state = {}, action) { + const { type, data } = action; + + const cloneState = overrides => _extends({}, state, overrides); if (type === "NODE_EXPAND") { return cloneState({ @@ -6994,11 +6885,12 @@ function reducer(state = {}, action) { return state; } /* 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/. */ + * file, You can obtain one at . */ module.exports = reducer; /***/ }) -/******/ ]); + +/******/ }); }); \ No newline at end of file diff --git a/devtools/client/shared/source-map/index.js b/devtools/client/shared/source-map/index.js index a92b3a661642..f0b233417146 100644 --- a/devtools/client/shared/source-map/index.js +++ b/devtools/client/shared/source-map/index.js @@ -7,7 +7,7 @@ var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(this, function() { +})(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -67,158 +67,22 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; +/******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 15); +/******/ return __webpack_require__(__webpack_require__.s = 3646); /******/ }) /************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { +/******/ ({ -var charenc = { - // UTF-8 encoding - utf8: { - // Convert a string to a byte array - stringToBytes: function(str) { - return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); - }, - - // Convert a byte array to a string - bytesToString: function(bytes) { - return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); - } - }, - - // Binary encoding - bin: { - // Convert a string to a byte array - stringToBytes: function(str) { - for (var bytes = [], i = 0; i < str.length; i++) - bytes.push(str.charCodeAt(i) & 0xFF); - return bytes; - }, - - // Convert a byte array to a string - bytesToString: function(bytes) { - for (var str = [], i = 0; i < bytes.length; i++) - str.push(String.fromCharCode(bytes[i])); - return str.join(''); - } - } -}; - -module.exports = charenc; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* 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/. */ - -const networkRequest = __webpack_require__(7); -const workerUtils = __webpack_require__(8); - -module.exports = { - networkRequest, - workerUtils -}; - -/***/ }), -/* 2 */, -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* 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/. */ - -const md5 = __webpack_require__(4); - -function originalToGeneratedId(originalId) { - const match = originalId.match(/(.*)\/originalSource/); - return match ? match[1] : ""; -} - -function generatedToOriginalId(generatedId, url) { - return `${generatedId}/originalSource-${md5(url)}`; -} - -function isOriginalId(id) { - return !!id.match(/\/originalSource/); -} - -function isGeneratedId(id) { - return !isOriginalId(id); -} - -/** - * Trims the query part or reference identifier of a URL string, if necessary. - */ -function trimUrlQuery(url) { - let length = url.length; - let q1 = url.indexOf("?"); - let q2 = url.indexOf("&"); - let q3 = url.indexOf("#"); - let q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); - - return url.slice(0, q); -} - -// Map suffix to content type. -const contentMap = { - "js": "text/javascript", - "jsm": "text/javascript", - "mjs": "text/javascript", - "ts": "text/typescript", - "tsx": "text/typescript-jsx", - "jsx": "text/jsx", - "coffee": "text/coffeescript", - "elm": "text/elm", - "cljs": "text/x-clojure" -}; - -/** - * Returns the content type for the specified URL. If no specific - * content type can be determined, "text/plain" is returned. - * - * @return String - * The content type. - */ -function getContentType(url) { - url = trimUrlQuery(url); - let dot = url.lastIndexOf("."); - if (dot >= 0) { - let name = url.substring(dot + 1); - if (name in contentMap) { - return contentMap[name]; - } - } - return "text/plain"; -} - -module.exports = { - originalToGeneratedId, - generatedToOriginalId, - isOriginalId, - isGeneratedId, - getContentType, - contentMapForTesting: contentMap -}; - -/***/ }), -/* 4 */ +/***/ 248: /***/ (function(module, exports, __webpack_require__) { (function(){ - var crypt = __webpack_require__(5), - utf8 = __webpack_require__(0).utf8, - isBuffer = __webpack_require__(6), - bin = __webpack_require__(0).bin, + var crypt = __webpack_require__(249), + utf8 = __webpack_require__(250).utf8, + isBuffer = __webpack_require__(251), + bin = __webpack_require__(250).bin, // The core md5 = function (message, options) { @@ -377,7 +241,8 @@ module.exports = { /***/ }), -/* 5 */ + +/***/ 249: /***/ (function(module, exports) { (function() { @@ -479,13 +344,54 @@ module.exports = { /***/ }), -/* 6 */ + +/***/ 250: +/***/ (function(module, exports) { + +var charenc = { + // UTF-8 encoding + utf8: { + // Convert a string to a byte array + stringToBytes: function(str) { + return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); + }, + + // Convert a byte array to a string + bytesToString: function(bytes) { + return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); + } + }, + + // Binary encoding + bin: { + // Convert a string to a byte array + stringToBytes: function(str) { + for (var bytes = [], i = 0; i < str.length; i++) + bytes.push(str.charCodeAt(i) & 0xFF); + return bytes; + }, + + // Convert a byte array to a string + bytesToString: function(bytes) { + for (var str = [], i = 0; i < bytes.length; i++) + str.push(String.fromCharCode(bytes[i])); + return str.join(''); + } + } +}; + +module.exports = charenc; + + +/***/ }), + +/***/ 251: /***/ (function(module, exports) { /*! * Determine if an object is a Buffer * - * @author Feross Aboukhadijeh + * @author Feross Aboukhadijeh * @license MIT */ @@ -506,13 +412,177 @@ function isSlowBuffer (obj) { /***/ }), -/* 7 */ -/***/ (function(module, exports) { + +/***/ 3646: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +const { + originalToGeneratedId, + generatedToOriginalId, + isGeneratedId, + isOriginalId +} = __webpack_require__(3652); + +const { + workerUtils: { WorkerDispatcher } +} = __webpack_require__(3651); + +const dispatcher = new WorkerDispatcher(); + +const getOriginalURLs = dispatcher.task("getOriginalURLs"); +const getGeneratedRanges = dispatcher.task("getGeneratedRanges", { + queue: true +}); +const getGeneratedLocation = dispatcher.task("getGeneratedLocation", { + queue: true +}); +const getAllGeneratedLocations = dispatcher.task("getAllGeneratedLocations", { + queue: true +}); +const getOriginalLocation = dispatcher.task("getOriginalLocation"); +const getLocationScopes = dispatcher.task("getLocationScopes"); +const getOriginalSourceText = dispatcher.task("getOriginalSourceText"); +const applySourceMap = dispatcher.task("applySourceMap"); +const clearSourceMaps = dispatcher.task("clearSourceMaps"); +const hasMappedSource = dispatcher.task("hasMappedSource"); + +module.exports = { + originalToGeneratedId, + generatedToOriginalId, + isGeneratedId, + isOriginalId, + hasMappedSource, + getOriginalURLs, + getGeneratedRanges, + getGeneratedLocation, + getAllGeneratedLocations, + getOriginalLocation, + getLocationScopes, + getOriginalSourceText, + applySourceMap, + clearSourceMaps, + startSourceMapWorker: dispatcher.start.bind(dispatcher), + stopSourceMapWorker: dispatcher.stop.bind(dispatcher) +}; + +/***/ }), + +/***/ 3651: +/***/ (function(module, exports, __webpack_require__) { /* 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/. */ +const networkRequest = __webpack_require__(3653); +const workerUtils = __webpack_require__(3654); + +module.exports = { + networkRequest, + workerUtils +}; + +/***/ }), + +/***/ 3652: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +const md5 = __webpack_require__(248); + +function originalToGeneratedId(originalId) { + const match = originalId.match(/(.*)\/originalSource/); + return match ? match[1] : ""; +} + +function generatedToOriginalId(generatedId, url) { + return `${generatedId}/originalSource-${md5(url)}`; +} + +function isOriginalId(id) { + return !!id.match(/\/originalSource/); +} + +function isGeneratedId(id) { + return !isOriginalId(id); +} + +/** + * Trims the query part or reference identifier of a URL string, if necessary. + */ +function trimUrlQuery(url) { + const length = url.length; + const q1 = url.indexOf("?"); + const q2 = url.indexOf("&"); + const q3 = url.indexOf("#"); + const q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); + + return url.slice(0, q); +} + +// Map suffix to content type. +const contentMap = { + js: "text/javascript", + jsm: "text/javascript", + mjs: "text/javascript", + ts: "text/typescript", + tsx: "text/typescript-jsx", + jsx: "text/jsx", + coffee: "text/coffeescript", + elm: "text/elm", + cljs: "text/x-clojure" +}; + +/** + * Returns the content type for the specified URL. If no specific + * content type can be determined, "text/plain" is returned. + * + * @return String + * The content type. + */ +function getContentType(url) { + url = trimUrlQuery(url); + const dot = url.lastIndexOf("."); + if (dot >= 0) { + const name = url.substring(dot + 1); + if (name in contentMap) { + return contentMap[name]; + } + } + return "text/plain"; +} + +module.exports = { + originalToGeneratedId, + generatedToOriginalId, + isOriginalId, + isGeneratedId, + getContentType, + contentMapForTesting: contentMap +}; + +/***/ }), + +/***/ 3653: +/***/ (function(module, exports) { + +/* 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 . */ + function networkRequest(url, opts) { return fetch(url, { cache: opts.loadFromCache ? "default" : "no-cache" @@ -527,7 +597,8 @@ function networkRequest(url, opts) { module.exports = networkRequest; /***/ }), -/* 8 */ + +/***/ 3654: /***/ (function(module, exports) { function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } @@ -537,7 +608,7 @@ function WorkerDispatcher() { this.worker = null; } /* 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/. */ + * file, You can obtain one at . */ WorkerDispatcher.prototype = { start(url) { @@ -577,7 +648,11 @@ WorkerDispatcher.prototype = { calls.length = 0; const id = this.msgId++; - this.worker.postMessage({ id, method, calls: items.map(item => item[0]) }); + this.worker.postMessage({ + id, + method, + calls: items.map(item => item[0]) + }); const listener = ({ data: result }) => { if (result.id !== id) { @@ -620,9 +695,8 @@ function workerHandler(publicInterface) { // Error can't be sent via postMessage, so be sure to // convert to string. err => ({ error: err.toString() })); - } else { - return { response }; } + return { response }; } catch (error) { // Error can't be sent via postMessage, so be sure to convert to // string. @@ -639,7 +713,7 @@ function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker var _ref = _asyncToGenerator(function* (id, tasks) { let isWorking = true; - const intervalId = setTimeout(function () { + const timeoutId = setTimeout(function () { isWorking = false; }, timeout); @@ -650,7 +724,7 @@ function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker results.push(result); } worker.postMessage({ id, status: "pending", data: results }); - clearInterval(intervalId); + clearTimeout(timeoutId); if (tasks.length !== 0) { yield streamingWorker(id, tasks); @@ -692,61 +766,7 @@ module.exports = { streamingWorkerHandler }; -/***/ }), -/* 9 */, -/* 10 */, -/* 11 */, -/* 12 */, -/* 13 */, -/* 14 */, -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* 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/. */ - -const { - originalToGeneratedId, - generatedToOriginalId, - isGeneratedId, - isOriginalId -} = __webpack_require__(3); - -const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1); - -const dispatcher = new WorkerDispatcher(); - -const getOriginalURLs = dispatcher.task("getOriginalURLs"); -const getGeneratedRanges = dispatcher.task("getGeneratedRanges", { queue: true }); -const getGeneratedLocation = dispatcher.task("getGeneratedLocation", { queue: true }); -const getAllGeneratedLocations = dispatcher.task("getAllGeneratedLocations", { queue: true }); -const getOriginalLocation = dispatcher.task("getOriginalLocation"); -const getLocationScopes = dispatcher.task("getLocationScopes"); -const getOriginalSourceText = dispatcher.task("getOriginalSourceText"); -const applySourceMap = dispatcher.task("applySourceMap"); -const clearSourceMaps = dispatcher.task("clearSourceMaps"); -const hasMappedSource = dispatcher.task("hasMappedSource"); - -module.exports = { - originalToGeneratedId, - generatedToOriginalId, - isGeneratedId, - isOriginalId, - hasMappedSource, - getOriginalURLs, - getGeneratedRanges, - getGeneratedLocation, - getAllGeneratedLocations, - getOriginalLocation, - getLocationScopes, - getOriginalSourceText, - applySourceMap, - clearSourceMaps, - startSourceMapWorker: dispatcher.start.bind(dispatcher), - stopSourceMapWorker: dispatcher.stop.bind(dispatcher) -}; - /***/ }) -/******/ ]); + +/******/ }); }); \ No newline at end of file diff --git a/devtools/client/shared/source-map/worker.js b/devtools/client/shared/source-map/worker.js index e95904bcfca8..0db44a6bdd2c 100644 --- a/devtools/client/shared/source-map/worker.js +++ b/devtools/client/shared/source-map/worker.js @@ -7,7 +7,7 @@ var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(this, function() { +})(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -67,14 +67,285 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; +/******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 16); +/******/ return __webpack_require__(__webpack_require__.s = 3709); /******/ }) /************************************************************************/ -/******/ ([ -/* 0 */ +/******/ ({ + +/***/ 248: +/***/ (function(module, exports, __webpack_require__) { + +(function(){ + var crypt = __webpack_require__(249), + utf8 = __webpack_require__(250).utf8, + isBuffer = __webpack_require__(251), + bin = __webpack_require__(250).bin, + + // The core + md5 = function (message, options) { + // Convert to byte array + if (message.constructor == String) + if (options && options.encoding === 'binary') + message = bin.stringToBytes(message); + else + message = utf8.stringToBytes(message); + else if (isBuffer(message)) + message = Array.prototype.slice.call(message, 0); + else if (!Array.isArray(message)) + message = message.toString(); + // else, assume byte array already + + var m = crypt.bytesToWords(message), + l = message.length * 8, + a = 1732584193, + b = -271733879, + c = -1732584194, + d = 271733878; + + // Swap endian + for (var i = 0; i < m.length; i++) { + m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF | + ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00; + } + + // Padding + m[l >>> 5] |= 0x80 << (l % 32); + m[(((l + 64) >>> 9) << 4) + 14] = l; + + // Method shortcuts + var FF = md5._ff, + GG = md5._gg, + HH = md5._hh, + II = md5._ii; + + for (var i = 0; i < m.length; i += 16) { + + var aa = a, + bb = b, + cc = c, + dd = d; + + a = FF(a, b, c, d, m[i+ 0], 7, -680876936); + d = FF(d, a, b, c, m[i+ 1], 12, -389564586); + c = FF(c, d, a, b, m[i+ 2], 17, 606105819); + b = FF(b, c, d, a, m[i+ 3], 22, -1044525330); + a = FF(a, b, c, d, m[i+ 4], 7, -176418897); + d = FF(d, a, b, c, m[i+ 5], 12, 1200080426); + c = FF(c, d, a, b, m[i+ 6], 17, -1473231341); + b = FF(b, c, d, a, m[i+ 7], 22, -45705983); + a = FF(a, b, c, d, m[i+ 8], 7, 1770035416); + d = FF(d, a, b, c, m[i+ 9], 12, -1958414417); + c = FF(c, d, a, b, m[i+10], 17, -42063); + b = FF(b, c, d, a, m[i+11], 22, -1990404162); + a = FF(a, b, c, d, m[i+12], 7, 1804603682); + d = FF(d, a, b, c, m[i+13], 12, -40341101); + c = FF(c, d, a, b, m[i+14], 17, -1502002290); + b = FF(b, c, d, a, m[i+15], 22, 1236535329); + + a = GG(a, b, c, d, m[i+ 1], 5, -165796510); + d = GG(d, a, b, c, m[i+ 6], 9, -1069501632); + c = GG(c, d, a, b, m[i+11], 14, 643717713); + b = GG(b, c, d, a, m[i+ 0], 20, -373897302); + a = GG(a, b, c, d, m[i+ 5], 5, -701558691); + d = GG(d, a, b, c, m[i+10], 9, 38016083); + c = GG(c, d, a, b, m[i+15], 14, -660478335); + b = GG(b, c, d, a, m[i+ 4], 20, -405537848); + a = GG(a, b, c, d, m[i+ 9], 5, 568446438); + d = GG(d, a, b, c, m[i+14], 9, -1019803690); + c = GG(c, d, a, b, m[i+ 3], 14, -187363961); + b = GG(b, c, d, a, m[i+ 8], 20, 1163531501); + a = GG(a, b, c, d, m[i+13], 5, -1444681467); + d = GG(d, a, b, c, m[i+ 2], 9, -51403784); + c = GG(c, d, a, b, m[i+ 7], 14, 1735328473); + b = GG(b, c, d, a, m[i+12], 20, -1926607734); + + a = HH(a, b, c, d, m[i+ 5], 4, -378558); + d = HH(d, a, b, c, m[i+ 8], 11, -2022574463); + c = HH(c, d, a, b, m[i+11], 16, 1839030562); + b = HH(b, c, d, a, m[i+14], 23, -35309556); + a = HH(a, b, c, d, m[i+ 1], 4, -1530992060); + d = HH(d, a, b, c, m[i+ 4], 11, 1272893353); + c = HH(c, d, a, b, m[i+ 7], 16, -155497632); + b = HH(b, c, d, a, m[i+10], 23, -1094730640); + a = HH(a, b, c, d, m[i+13], 4, 681279174); + d = HH(d, a, b, c, m[i+ 0], 11, -358537222); + c = HH(c, d, a, b, m[i+ 3], 16, -722521979); + b = HH(b, c, d, a, m[i+ 6], 23, 76029189); + a = HH(a, b, c, d, m[i+ 9], 4, -640364487); + d = HH(d, a, b, c, m[i+12], 11, -421815835); + c = HH(c, d, a, b, m[i+15], 16, 530742520); + b = HH(b, c, d, a, m[i+ 2], 23, -995338651); + + a = II(a, b, c, d, m[i+ 0], 6, -198630844); + d = II(d, a, b, c, m[i+ 7], 10, 1126891415); + c = II(c, d, a, b, m[i+14], 15, -1416354905); + b = II(b, c, d, a, m[i+ 5], 21, -57434055); + a = II(a, b, c, d, m[i+12], 6, 1700485571); + d = II(d, a, b, c, m[i+ 3], 10, -1894986606); + c = II(c, d, a, b, m[i+10], 15, -1051523); + b = II(b, c, d, a, m[i+ 1], 21, -2054922799); + a = II(a, b, c, d, m[i+ 8], 6, 1873313359); + d = II(d, a, b, c, m[i+15], 10, -30611744); + c = II(c, d, a, b, m[i+ 6], 15, -1560198380); + b = II(b, c, d, a, m[i+13], 21, 1309151649); + a = II(a, b, c, d, m[i+ 4], 6, -145523070); + d = II(d, a, b, c, m[i+11], 10, -1120210379); + c = II(c, d, a, b, m[i+ 2], 15, 718787259); + b = II(b, c, d, a, m[i+ 9], 21, -343485551); + + a = (a + aa) >>> 0; + b = (b + bb) >>> 0; + c = (c + cc) >>> 0; + d = (d + dd) >>> 0; + } + + return crypt.endian([a, b, c, d]); + }; + + // Auxiliary functions + md5._ff = function (a, b, c, d, x, s, t) { + var n = a + (b & c | ~b & d) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + md5._gg = function (a, b, c, d, x, s, t) { + var n = a + (b & d | c & ~d) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + md5._hh = function (a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + md5._ii = function (a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + + // Package private blocksize + md5._blocksize = 16; + md5._digestsize = 16; + + module.exports = function (message, options) { + if (message === undefined || message === null) + throw new Error('Illegal argument ' + message); + + var digestbytes = crypt.wordsToBytes(md5(message, options)); + return options && options.asBytes ? digestbytes : + options && options.asString ? bin.bytesToString(digestbytes) : + crypt.bytesToHex(digestbytes); + }; + +})(); + + +/***/ }), + +/***/ 249: +/***/ (function(module, exports) { + +(function() { + var base64map + = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + + crypt = { + // Bit-wise rotation left + rotl: function(n, b) { + return (n << b) | (n >>> (32 - b)); + }, + + // Bit-wise rotation right + rotr: function(n, b) { + return (n << (32 - b)) | (n >>> b); + }, + + // Swap big-endian to little-endian and vice versa + endian: function(n) { + // If number given, swap endian + if (n.constructor == Number) { + return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00; + } + + // Else, assume array and swap all items + for (var i = 0; i < n.length; i++) + n[i] = crypt.endian(n[i]); + return n; + }, + + // Generate an array of any length of random bytes + randomBytes: function(n) { + for (var bytes = []; n > 0; n--) + bytes.push(Math.floor(Math.random() * 256)); + return bytes; + }, + + // Convert a byte array to big-endian 32-bit words + bytesToWords: function(bytes) { + for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) + words[b >>> 5] |= bytes[i] << (24 - b % 32); + return words; + }, + + // Convert big-endian 32-bit words to a byte array + wordsToBytes: function(words) { + for (var bytes = [], b = 0; b < words.length * 32; b += 8) + bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); + return bytes; + }, + + // Convert a byte array to a hex string + bytesToHex: function(bytes) { + for (var hex = [], i = 0; i < bytes.length; i++) { + hex.push((bytes[i] >>> 4).toString(16)); + hex.push((bytes[i] & 0xF).toString(16)); + } + return hex.join(''); + }, + + // Convert a hex string to a byte array + hexToBytes: function(hex) { + for (var bytes = [], c = 0; c < hex.length; c += 2) + bytes.push(parseInt(hex.substr(c, 2), 16)); + return bytes; + }, + + // Convert a byte array to a base-64 string + bytesToBase64: function(bytes) { + for (var base64 = [], i = 0; i < bytes.length; i += 3) { + var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + for (var j = 0; j < 4; j++) + if (i * 8 + j * 6 <= bytes.length * 8) + base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); + else + base64.push('='); + } + return base64.join(''); + }, + + // Convert a base-64 string to a byte array + base64ToBytes: function(base64) { + // Remove non-base-64 characters + base64 = base64.replace(/[^A-Z0-9+\/]/ig, ''); + + for (var bytes = [], i = 0, imod4 = 0; i < base64.length; + imod4 = ++i % 4) { + if (imod4 == 0) continue; + bytes.push(((base64map.indexOf(base64.charAt(i - 1)) + & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) + | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); + } + return bytes; + } + }; + + module.exports = crypt; +})(); + + +/***/ }), + +/***/ 250: /***/ (function(module, exports) { var charenc = { @@ -113,15 +384,44 @@ module.exports = charenc; /***/ }), -/* 1 */ + +/***/ 251: +/***/ (function(module, exports) { + +/*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ + +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually +module.exports = function (obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) +} + +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} + +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) +} + + +/***/ }), + +/***/ 3651: /***/ (function(module, exports, __webpack_require__) { /* 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/. */ -const networkRequest = __webpack_require__(7); -const workerUtils = __webpack_require__(8); +const networkRequest = __webpack_require__(3653); +const workerUtils = __webpack_require__(3654); module.exports = { networkRequest, @@ -129,7 +429,285 @@ module.exports = { }; /***/ }), -/* 2 */ + +/***/ 3652: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +const md5 = __webpack_require__(248); + +function originalToGeneratedId(originalId) { + const match = originalId.match(/(.*)\/originalSource/); + return match ? match[1] : ""; +} + +function generatedToOriginalId(generatedId, url) { + return `${generatedId}/originalSource-${md5(url)}`; +} + +function isOriginalId(id) { + return !!id.match(/\/originalSource/); +} + +function isGeneratedId(id) { + return !isOriginalId(id); +} + +/** + * Trims the query part or reference identifier of a URL string, if necessary. + */ +function trimUrlQuery(url) { + const length = url.length; + const q1 = url.indexOf("?"); + const q2 = url.indexOf("&"); + const q3 = url.indexOf("#"); + const q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); + + return url.slice(0, q); +} + +// Map suffix to content type. +const contentMap = { + js: "text/javascript", + jsm: "text/javascript", + mjs: "text/javascript", + ts: "text/typescript", + tsx: "text/typescript-jsx", + jsx: "text/jsx", + coffee: "text/coffeescript", + elm: "text/elm", + cljs: "text/x-clojure" +}; + +/** + * Returns the content type for the specified URL. If no specific + * content type can be determined, "text/plain" is returned. + * + * @return String + * The content type. + */ +function getContentType(url) { + url = trimUrlQuery(url); + const dot = url.lastIndexOf("."); + if (dot >= 0) { + const name = url.substring(dot + 1); + if (name in contentMap) { + return contentMap[name]; + } + } + return "text/plain"; +} + +module.exports = { + originalToGeneratedId, + generatedToOriginalId, + isOriginalId, + isGeneratedId, + getContentType, + contentMapForTesting: contentMap +}; + +/***/ }), + +/***/ 3653: +/***/ (function(module, exports) { + +/* 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 . */ + +function networkRequest(url, opts) { + return fetch(url, { + cache: opts.loadFromCache ? "default" : "no-cache" + }).then(res => { + if (res.status >= 200 && res.status < 300) { + return res.text().then(text => ({ content: text })); + } + return Promise.reject(`request failed with status ${res.status}`); + }); +} + +module.exports = networkRequest; + +/***/ }), + +/***/ 3654: +/***/ (function(module, exports) { + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + +function WorkerDispatcher() { + this.msgId = 1; + this.worker = null; +} /* 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 . */ + +WorkerDispatcher.prototype = { + start(url) { + this.worker = new Worker(url); + this.worker.onerror = () => { + console.error(`Error in worker ${url}`); + }; + }, + + stop() { + if (!this.worker) { + return; + } + + this.worker.terminate(); + this.worker = null; + }, + + task(method, { queue = false } = {}) { + const calls = []; + const push = args => { + return new Promise((resolve, reject) => { + if (queue && calls.length === 0) { + Promise.resolve().then(flush); + } + + calls.push([args, resolve, reject]); + + if (!queue) { + flush(); + } + }); + }; + + const flush = () => { + const items = calls.slice(); + calls.length = 0; + + const id = this.msgId++; + this.worker.postMessage({ + id, + method, + calls: items.map(item => item[0]) + }); + + const listener = ({ data: result }) => { + if (result.id !== id) { + return; + } + + if (!this.worker) { + return; + } + + this.worker.removeEventListener("message", listener); + + result.results.forEach((resultData, i) => { + const [, resolve, reject] = items[i]; + + if (resultData.error) { + reject(resultData.error); + } else { + resolve(resultData.response); + } + }); + }; + + this.worker.addEventListener("message", listener); + }; + + return (...args) => push(args); + } +}; + +function workerHandler(publicInterface) { + return function (msg) { + const { id, method, calls } = msg.data; + + Promise.all(calls.map(args => { + try { + const response = publicInterface[method].apply(undefined, args); + if (response instanceof Promise) { + return response.then(val => ({ response: val }), + // Error can't be sent via postMessage, so be sure to + // convert to string. + err => ({ error: err.toString() })); + } + return { response }; + } catch (error) { + // Error can't be sent via postMessage, so be sure to convert to + // string. + return { error: error.toString() }; + } + })).then(results => { + self.postMessage({ id, results }); + }); + }; +} + +function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker = self) { + let streamingWorker = (() => { + var _ref = _asyncToGenerator(function* (id, tasks) { + let isWorking = true; + + const timeoutId = setTimeout(function () { + isWorking = false; + }, timeout); + + const results = []; + while (tasks.length !== 0 && isWorking) { + const { callback, context, args } = tasks.shift(); + const result = yield callback.call(context, args); + results.push(result); + } + worker.postMessage({ id, status: "pending", data: results }); + clearTimeout(timeoutId); + + if (tasks.length !== 0) { + yield streamingWorker(id, tasks); + } + }); + + return function streamingWorker(_x, _x2) { + return _ref.apply(this, arguments); + }; + })(); + + return (() => { + var _ref2 = _asyncToGenerator(function* (msg) { + const { id, method, args } = msg.data; + const workerMethod = publicInterface[method]; + if (!workerMethod) { + console.error(`Could not find ${method} defined in worker.`); + } + worker.postMessage({ id, status: "start" }); + + try { + const tasks = workerMethod(args); + yield streamingWorker(id, tasks); + worker.postMessage({ id, status: "done" }); + } catch (error) { + worker.postMessage({ id, status: "error", error }); + } + }); + + return function (_x3) { + return _ref2.apply(this, arguments); + }; + })(); +} + +module.exports = { + WorkerDispatcher, + workerHandler, + streamingWorkerHandler +}; + +/***/ }), + +/***/ 3668: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -623,575 +1201,18 @@ exports.computeSourceURL = computeSourceURL; /***/ }), -/* 3 */ + +/***/ 3704: /***/ (function(module, exports, __webpack_require__) { +"use strict"; + + /* 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/. */ + * file, You can obtain one at . */ -const md5 = __webpack_require__(4); - -function originalToGeneratedId(originalId) { - const match = originalId.match(/(.*)\/originalSource/); - return match ? match[1] : ""; -} - -function generatedToOriginalId(generatedId, url) { - return `${generatedId}/originalSource-${md5(url)}`; -} - -function isOriginalId(id) { - return !!id.match(/\/originalSource/); -} - -function isGeneratedId(id) { - return !isOriginalId(id); -} - -/** - * Trims the query part or reference identifier of a URL string, if necessary. - */ -function trimUrlQuery(url) { - let length = url.length; - let q1 = url.indexOf("?"); - let q2 = url.indexOf("&"); - let q3 = url.indexOf("#"); - let q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); - - return url.slice(0, q); -} - -// Map suffix to content type. -const contentMap = { - "js": "text/javascript", - "jsm": "text/javascript", - "mjs": "text/javascript", - "ts": "text/typescript", - "tsx": "text/typescript-jsx", - "jsx": "text/jsx", - vue: "text/vue", - "coffee": "text/coffeescript", - "elm": "text/elm", - "cljs": "text/x-clojure" -}; - -/** - * Returns the content type for the specified URL. If no specific - * content type can be determined, "text/plain" is returned. - * - * @return String - * The content type. - */ -function getContentType(url) { - url = trimUrlQuery(url); - let dot = url.lastIndexOf("."); - if (dot >= 0) { - let name = url.substring(dot + 1); - if (name in contentMap) { - return contentMap[name]; - } - } - return "text/plain"; -} - -module.exports = { - originalToGeneratedId, - generatedToOriginalId, - isOriginalId, - isGeneratedId, - getContentType, - contentMapForTesting: contentMap -}; - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -(function(){ - var crypt = __webpack_require__(5), - utf8 = __webpack_require__(0).utf8, - isBuffer = __webpack_require__(6), - bin = __webpack_require__(0).bin, - - // The core - md5 = function (message, options) { - // Convert to byte array - if (message.constructor == String) - if (options && options.encoding === 'binary') - message = bin.stringToBytes(message); - else - message = utf8.stringToBytes(message); - else if (isBuffer(message)) - message = Array.prototype.slice.call(message, 0); - else if (!Array.isArray(message)) - message = message.toString(); - // else, assume byte array already - - var m = crypt.bytesToWords(message), - l = message.length * 8, - a = 1732584193, - b = -271733879, - c = -1732584194, - d = 271733878; - - // Swap endian - for (var i = 0; i < m.length; i++) { - m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF | - ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00; - } - - // Padding - m[l >>> 5] |= 0x80 << (l % 32); - m[(((l + 64) >>> 9) << 4) + 14] = l; - - // Method shortcuts - var FF = md5._ff, - GG = md5._gg, - HH = md5._hh, - II = md5._ii; - - for (var i = 0; i < m.length; i += 16) { - - var aa = a, - bb = b, - cc = c, - dd = d; - - a = FF(a, b, c, d, m[i+ 0], 7, -680876936); - d = FF(d, a, b, c, m[i+ 1], 12, -389564586); - c = FF(c, d, a, b, m[i+ 2], 17, 606105819); - b = FF(b, c, d, a, m[i+ 3], 22, -1044525330); - a = FF(a, b, c, d, m[i+ 4], 7, -176418897); - d = FF(d, a, b, c, m[i+ 5], 12, 1200080426); - c = FF(c, d, a, b, m[i+ 6], 17, -1473231341); - b = FF(b, c, d, a, m[i+ 7], 22, -45705983); - a = FF(a, b, c, d, m[i+ 8], 7, 1770035416); - d = FF(d, a, b, c, m[i+ 9], 12, -1958414417); - c = FF(c, d, a, b, m[i+10], 17, -42063); - b = FF(b, c, d, a, m[i+11], 22, -1990404162); - a = FF(a, b, c, d, m[i+12], 7, 1804603682); - d = FF(d, a, b, c, m[i+13], 12, -40341101); - c = FF(c, d, a, b, m[i+14], 17, -1502002290); - b = FF(b, c, d, a, m[i+15], 22, 1236535329); - - a = GG(a, b, c, d, m[i+ 1], 5, -165796510); - d = GG(d, a, b, c, m[i+ 6], 9, -1069501632); - c = GG(c, d, a, b, m[i+11], 14, 643717713); - b = GG(b, c, d, a, m[i+ 0], 20, -373897302); - a = GG(a, b, c, d, m[i+ 5], 5, -701558691); - d = GG(d, a, b, c, m[i+10], 9, 38016083); - c = GG(c, d, a, b, m[i+15], 14, -660478335); - b = GG(b, c, d, a, m[i+ 4], 20, -405537848); - a = GG(a, b, c, d, m[i+ 9], 5, 568446438); - d = GG(d, a, b, c, m[i+14], 9, -1019803690); - c = GG(c, d, a, b, m[i+ 3], 14, -187363961); - b = GG(b, c, d, a, m[i+ 8], 20, 1163531501); - a = GG(a, b, c, d, m[i+13], 5, -1444681467); - d = GG(d, a, b, c, m[i+ 2], 9, -51403784); - c = GG(c, d, a, b, m[i+ 7], 14, 1735328473); - b = GG(b, c, d, a, m[i+12], 20, -1926607734); - - a = HH(a, b, c, d, m[i+ 5], 4, -378558); - d = HH(d, a, b, c, m[i+ 8], 11, -2022574463); - c = HH(c, d, a, b, m[i+11], 16, 1839030562); - b = HH(b, c, d, a, m[i+14], 23, -35309556); - a = HH(a, b, c, d, m[i+ 1], 4, -1530992060); - d = HH(d, a, b, c, m[i+ 4], 11, 1272893353); - c = HH(c, d, a, b, m[i+ 7], 16, -155497632); - b = HH(b, c, d, a, m[i+10], 23, -1094730640); - a = HH(a, b, c, d, m[i+13], 4, 681279174); - d = HH(d, a, b, c, m[i+ 0], 11, -358537222); - c = HH(c, d, a, b, m[i+ 3], 16, -722521979); - b = HH(b, c, d, a, m[i+ 6], 23, 76029189); - a = HH(a, b, c, d, m[i+ 9], 4, -640364487); - d = HH(d, a, b, c, m[i+12], 11, -421815835); - c = HH(c, d, a, b, m[i+15], 16, 530742520); - b = HH(b, c, d, a, m[i+ 2], 23, -995338651); - - a = II(a, b, c, d, m[i+ 0], 6, -198630844); - d = II(d, a, b, c, m[i+ 7], 10, 1126891415); - c = II(c, d, a, b, m[i+14], 15, -1416354905); - b = II(b, c, d, a, m[i+ 5], 21, -57434055); - a = II(a, b, c, d, m[i+12], 6, 1700485571); - d = II(d, a, b, c, m[i+ 3], 10, -1894986606); - c = II(c, d, a, b, m[i+10], 15, -1051523); - b = II(b, c, d, a, m[i+ 1], 21, -2054922799); - a = II(a, b, c, d, m[i+ 8], 6, 1873313359); - d = II(d, a, b, c, m[i+15], 10, -30611744); - c = II(c, d, a, b, m[i+ 6], 15, -1560198380); - b = II(b, c, d, a, m[i+13], 21, 1309151649); - a = II(a, b, c, d, m[i+ 4], 6, -145523070); - d = II(d, a, b, c, m[i+11], 10, -1120210379); - c = II(c, d, a, b, m[i+ 2], 15, 718787259); - b = II(b, c, d, a, m[i+ 9], 21, -343485551); - - a = (a + aa) >>> 0; - b = (b + bb) >>> 0; - c = (c + cc) >>> 0; - d = (d + dd) >>> 0; - } - - return crypt.endian([a, b, c, d]); - }; - - // Auxiliary functions - md5._ff = function (a, b, c, d, x, s, t) { - var n = a + (b & c | ~b & d) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - md5._gg = function (a, b, c, d, x, s, t) { - var n = a + (b & d | c & ~d) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - md5._hh = function (a, b, c, d, x, s, t) { - var n = a + (b ^ c ^ d) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - md5._ii = function (a, b, c, d, x, s, t) { - var n = a + (c ^ (b | ~d)) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - - // Package private blocksize - md5._blocksize = 16; - md5._digestsize = 16; - - module.exports = function (message, options) { - if (message === undefined || message === null) - throw new Error('Illegal argument ' + message); - - var digestbytes = crypt.wordsToBytes(md5(message, options)); - return options && options.asBytes ? digestbytes : - options && options.asString ? bin.bytesToString(digestbytes) : - crypt.bytesToHex(digestbytes); - }; - -})(); - - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - -(function() { - var base64map - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - - crypt = { - // Bit-wise rotation left - rotl: function(n, b) { - return (n << b) | (n >>> (32 - b)); - }, - - // Bit-wise rotation right - rotr: function(n, b) { - return (n << (32 - b)) | (n >>> b); - }, - - // Swap big-endian to little-endian and vice versa - endian: function(n) { - // If number given, swap endian - if (n.constructor == Number) { - return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00; - } - - // Else, assume array and swap all items - for (var i = 0; i < n.length; i++) - n[i] = crypt.endian(n[i]); - return n; - }, - - // Generate an array of any length of random bytes - randomBytes: function(n) { - for (var bytes = []; n > 0; n--) - bytes.push(Math.floor(Math.random() * 256)); - return bytes; - }, - - // Convert a byte array to big-endian 32-bit words - bytesToWords: function(bytes) { - for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) - words[b >>> 5] |= bytes[i] << (24 - b % 32); - return words; - }, - - // Convert big-endian 32-bit words to a byte array - wordsToBytes: function(words) { - for (var bytes = [], b = 0; b < words.length * 32; b += 8) - bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); - return bytes; - }, - - // Convert a byte array to a hex string - bytesToHex: function(bytes) { - for (var hex = [], i = 0; i < bytes.length; i++) { - hex.push((bytes[i] >>> 4).toString(16)); - hex.push((bytes[i] & 0xF).toString(16)); - } - return hex.join(''); - }, - - // Convert a hex string to a byte array - hexToBytes: function(hex) { - for (var bytes = [], c = 0; c < hex.length; c += 2) - bytes.push(parseInt(hex.substr(c, 2), 16)); - return bytes; - }, - - // Convert a byte array to a base-64 string - bytesToBase64: function(bytes) { - for (var base64 = [], i = 0; i < bytes.length; i += 3) { - var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; - for (var j = 0; j < 4; j++) - if (i * 8 + j * 6 <= bytes.length * 8) - base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); - else - base64.push('='); - } - return base64.join(''); - }, - - // Convert a base-64 string to a byte array - base64ToBytes: function(base64) { - // Remove non-base-64 characters - base64 = base64.replace(/[^A-Z0-9+\/]/ig, ''); - - for (var bytes = [], i = 0, imod4 = 0; i < base64.length; - imod4 = ++i % 4) { - if (imod4 == 0) continue; - bytes.push(((base64map.indexOf(base64.charAt(i - 1)) - & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) - | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); - } - return bytes; - } - }; - - module.exports = crypt; -})(); - - -/***/ }), -/* 6 */ -/***/ (function(module, exports) { - -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ - -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} - -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} - -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} - - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -/* 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/. */ - -function networkRequest(url, opts) { - return fetch(url, { - cache: opts.loadFromCache ? "default" : "no-cache" - }).then(res => { - if (res.status >= 200 && res.status < 300) { - return res.text().then(text => ({ content: text })); - } - return Promise.reject(`request failed with status ${res.status}`); - }); -} - -module.exports = networkRequest; - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } - -function WorkerDispatcher() { - this.msgId = 1; - this.worker = null; -} /* 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/. */ - -WorkerDispatcher.prototype = { - start(url) { - this.worker = new Worker(url); - this.worker.onerror = () => { - console.error(`Error in worker ${url}`); - }; - }, - - stop() { - if (!this.worker) { - return; - } - - this.worker.terminate(); - this.worker = null; - }, - - task(method, { queue = false } = {}) { - const calls = []; - const push = args => { - return new Promise((resolve, reject) => { - if (queue && calls.length === 0) { - Promise.resolve().then(flush); - } - - calls.push([args, resolve, reject]); - - if (!queue) { - flush(); - } - }); - }; - - const flush = () => { - const items = calls.slice(); - calls.length = 0; - - const id = this.msgId++; - this.worker.postMessage({ id, method, calls: items.map(item => item[0]) }); - - const listener = ({ data: result }) => { - if (result.id !== id) { - return; - } - - if (!this.worker) { - return; - } - - this.worker.removeEventListener("message", listener); - - result.results.forEach((resultData, i) => { - const [, resolve, reject] = items[i]; - - if (resultData.error) { - reject(resultData.error); - } else { - resolve(resultData.response); - } - }); - }; - - this.worker.addEventListener("message", listener); - }; - - return (...args) => push(args); - } -}; - -function workerHandler(publicInterface) { - return function (msg) { - const { id, method, calls } = msg.data; - - Promise.all(calls.map(args => { - try { - const response = publicInterface[method].apply(undefined, args); - if (response instanceof Promise) { - return response.then(val => ({ response: val }), - // Error can't be sent via postMessage, so be sure to - // convert to string. - err => ({ error: err.toString() })); - } else { - return { response }; - } - } catch (error) { - // Error can't be sent via postMessage, so be sure to convert to - // string. - return { error: error.toString() }; - } - })).then(results => { - self.postMessage({ id, results }); - }); - }; -} - -function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker = self) { - let streamingWorker = (() => { - var _ref = _asyncToGenerator(function* (id, tasks) { - let isWorking = true; - - const intervalId = setTimeout(function () { - isWorking = false; - }, timeout); - - const results = []; - while (tasks.length !== 0 && isWorking) { - const { callback, context, args } = tasks.shift(); - const result = yield callback.call(context, args); - results.push(result); - } - worker.postMessage({ id, status: "pending", data: results }); - clearInterval(intervalId); - - if (tasks.length !== 0) { - yield streamingWorker(id, tasks); - } - }); - - return function streamingWorker(_x, _x2) { - return _ref.apply(this, arguments); - }; - })(); - - return (() => { - var _ref2 = _asyncToGenerator(function* (msg) { - const { id, method, args } = msg.data; - const workerMethod = publicInterface[method]; - if (!workerMethod) { - console.error(`Could not find ${method} defined in worker.`); - } - worker.postMessage({ id, status: "start" }); - - try { - const tasks = workerMethod(args); - yield streamingWorker(id, tasks); - worker.postMessage({ id, status: "done" }); - } catch (error) { - worker.postMessage({ id, status: "error", error }); - } - }); - - return function (_x3) { - return _ref2.apply(this, arguments); - }; - })(); -} - -module.exports = { - WorkerDispatcher, - workerHandler, - streamingWorkerHandler -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - - -let sourceMapRequests = new Map(); +const sourceMapRequests = new Map(); function clearSourceMaps() { sourceMapRequests.clear(); @@ -1212,7 +1233,8 @@ module.exports = { }; /***/ }), -/* 10 */ + +/***/ 3705: /***/ (function(module, exports, __webpack_require__) { /* @@ -1220,13 +1242,14 @@ module.exports = { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(11).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(20).SourceMapConsumer; -exports.SourceNode = __webpack_require__(23).SourceNode; +exports.SourceMapGenerator = __webpack_require__(3706).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(3713).SourceMapConsumer; +exports.SourceNode = __webpack_require__(3716).SourceNode; /***/ }), -/* 11 */ + +/***/ 3706: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -1236,10 +1259,10 @@ exports.SourceNode = __webpack_require__(23).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(12); -var util = __webpack_require__(2); -var ArraySet = __webpack_require__(13).ArraySet; -var MappingList = __webpack_require__(19).MappingList; +var base64VLQ = __webpack_require__(3707); +var util = __webpack_require__(3668); +var ArraySet = __webpack_require__(3708).ArraySet; +var MappingList = __webpack_require__(3712).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -1657,7 +1680,8 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 12 */ + +/***/ 3707: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -1697,7 +1721,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(18); +var base64 = __webpack_require__(3711); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -1803,7 +1827,8 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 13 */ + +/***/ 3708: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -1813,7 +1838,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(2); +var util = __webpack_require__(3668); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -1930,127 +1955,16 @@ exports.ArraySet = ArraySet; /***/ }), -/* 14 */ + +/***/ 3709: /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* 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/. */ - -/** - * SourceMapConsumer for WebAssembly source maps. It transposes columns with - * lines, which allows mapping data to be used with SpiderMonkey Debugger API. - */ - -class WasmRemap { - /** - * @param map SourceMapConsumer - */ - constructor(map) { - this._map = map; - this.version = map.version; - this.file = map.file; - this._computeColumnSpans = false; - } - - get sources() { - return this._map.sources; - } - - get sourceRoot() { - return this._map.sourceRoot; - } - - get names() { - return this._map.names; - } - - get sourcesContent() { - return this._map.sourcesContent; - } - - get mappings() { - throw new Error("not supported"); - } - - computeColumnSpans() { - this._computeColumnSpans = true; - } - - originalPositionFor(generatedPosition) { - let result = this._map.originalPositionFor({ - line: 1, - column: generatedPosition.line, - bias: generatedPosition.bias - }); - return result; - } - - _remapGeneratedPosition(position) { - let generatedPosition = { - line: position.column, - column: 0 - }; - if (this._computeColumnSpans) { - generatedPosition.lastColumn = Infinity; - } - return generatedPosition; - } - - generatedPositionFor(originalPosition) { - let position = this._map.generatedPositionFor(originalPosition); - return this._remapGeneratedPosition(position); - } - - allGeneratedPositionsFor(originalPosition) { - let positions = this._map.allGeneratedPositionsFor(originalPosition); - return positions.map(position => { - return this._remapGeneratedPosition(position); - }); - } - - hasContentsOfAllSources() { - return this._map.hasContentsOfAllSources(); - } - - sourceContentFor(source, returnNullOnMissing) { - return this._map.sourceContentFor(source, returnNullOnMissing); - } - - eachMapping(callback, context, order) { - this._map.eachMapping(entry => { - let { - source, - generatedColumn, - originalLine, - originalColumn, - name - } = entry; - callback({ - source, - generatedLine: generatedColumn, - generatedColumn: 0, - originalLine, - originalColumn, - name - }); - }, context, order); - } -} - -exports.WasmRemap = WasmRemap; - -/***/ }), -/* 15 */, -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - /* 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/. */ + * file, You can obtain one at . */ const { getOriginalURLs, @@ -2062,11 +1976,13 @@ const { getLocationScopes, hasMappedSource, applySourceMap -} = __webpack_require__(17); +} = __webpack_require__(3710); -const { clearSourceMaps } = __webpack_require__(9); +const { clearSourceMaps } = __webpack_require__(3704); -const { workerUtils: { workerHandler } } = __webpack_require__(1); +const { + workerUtils: { workerHandler } +} = __webpack_require__(3651); // The interface is implemented in source-map to be // easier to unit test. @@ -2084,248 +2000,204 @@ self.onmessage = workerHandler({ }); /***/ }), -/* 17 */ + +/***/ 3710: /***/ (function(module, exports, __webpack_require__) { -let getOriginalURLs = (() => { - var _ref = _asyncToGenerator(function* (generatedSource) { - const map = yield fetchSourceMap(generatedSource); - return map && map.sources; - }); +"use strict"; - return function getOriginalURLs(_x) { - return _ref.apply(this, arguments); - }; -})(); - -/** - * Given an original location, find the ranges on the generated file that - * are mapped from the original range containing the location. - */ -let getGeneratedRanges = (() => { - var _ref2 = _asyncToGenerator(function* (location, originalSource) { - if (!isOriginalId(location.sourceId)) { - return []; - } - - const generatedSourceId = originalToGeneratedId(location.sourceId); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return []; - } - - if (!COMPUTED_SPANS.has(map)) { - COMPUTED_SPANS.add(map); - map.computeColumnSpans(); - } - - // We want to use 'allGeneratedPositionsFor' to get the _first_ generated - // location, but it hard-codes SourceMapConsumer.LEAST_UPPER_BOUND as the - // bias, making it search in the wrong direction for this usecase. - // To work around this, we use 'generatedPositionFor' and then look up the - // exact original location, making any bias value unnecessary, and then - // use that location for the call to 'allGeneratedPositionsFor'. - const genPos = map.generatedPositionFor({ - source: originalSource.url, - line: location.line, - column: location.column == null ? 0 : location.column, - bias: SourceMapConsumer.GREATEST_LOWER_BOUND - }); - if (genPos.line === null) return []; - - const positions = map.allGeneratedPositionsFor(map.originalPositionFor({ - line: genPos.line, - column: genPos.column - })); - - return positions.map(function (mapping) { - return { - line: mapping.line, - columnStart: mapping.column, - columnEnd: mapping.lastColumn - }; - }).sort(function (a, b) { - const line = a.line - b.line; - return line === 0 ? a.column - b.column : line; - }); - }); - - return function getGeneratedRanges(_x2, _x3) { - return _ref2.apply(this, arguments); - }; -})(); - -let getGeneratedLocation = (() => { - var _ref3 = _asyncToGenerator(function* (location, originalSource) { - if (!isOriginalId(location.sourceId)) { - return location; - } - - const generatedSourceId = originalToGeneratedId(location.sourceId); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return location; - } - - const { line, column } = map.generatedPositionFor({ - source: originalSource.url, - line: location.line, - column: location.column == null ? 0 : location.column, - bias: SourceMapConsumer.LEAST_UPPER_BOUND - }); - - return { - sourceId: generatedSourceId, - line, - column - }; - }); - - return function getGeneratedLocation(_x4, _x5) { - return _ref3.apply(this, arguments); - }; -})(); - -let getAllGeneratedLocations = (() => { - var _ref4 = _asyncToGenerator(function* (location, originalSource) { - if (!isOriginalId(location.sourceId)) { - return []; - } - - const generatedSourceId = originalToGeneratedId(location.sourceId); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return []; - } - - const positions = map.allGeneratedPositionsFor({ - source: originalSource.url, - line: location.line, - column: location.column == null ? 0 : location.column - }); - - return positions.map(function ({ line, column }) { - return { - sourceId: generatedSourceId, - line, - column - }; - }); - }); - - return function getAllGeneratedLocations(_x6, _x7) { - return _ref4.apply(this, arguments); - }; -})(); - -let getOriginalLocation = (() => { - var _ref5 = _asyncToGenerator(function* (location) { - if (!isGeneratedId(location.sourceId)) { - return location; - } - - const map = yield getSourceMap(location.sourceId); - if (!map) { - return location; - } - - const { source: sourceUrl, line, column } = map.originalPositionFor({ - line: location.line, - column: location.column == null ? 0 : location.column - }); - - if (sourceUrl == null) { - // No url means the location didn't map. - return location; - } - - return { - sourceId: generatedToOriginalId(location.sourceId, sourceUrl), - sourceUrl, - line, - column - }; - }); - - return function getOriginalLocation(_x8) { - return _ref5.apply(this, arguments); - }; -})(); - -let getOriginalSourceText = (() => { - var _ref6 = _asyncToGenerator(function* (originalSource) { - assert(isOriginalId(originalSource.id), "Source is not an original source"); - - const generatedSourceId = originalToGeneratedId(originalSource.id); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return null; - } - - let text = map.sourceContentFor(originalSource.url); - if (!text) { - text = (yield networkRequest(originalSource.url, { loadFromCache: false })).content; - } - - return { - text, - contentType: getContentType(originalSource.url || "") - }; - }); - - return function getOriginalSourceText(_x9) { - return _ref6.apply(this, arguments); - }; -})(); - -let hasMappedSource = (() => { - var _ref7 = _asyncToGenerator(function* (location) { - if (isOriginalId(location.sourceId)) { - return true; - } - - const loc = yield getOriginalLocation(location); - return loc.sourceId !== location.sourceId; - }); - - return function hasMappedSource(_x10) { - return _ref7.apply(this, arguments); - }; -})(); - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /* 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/. */ + * file, You can obtain one at . */ /** * Source Map Worker * @module utils/source-map-worker */ -const { networkRequest } = __webpack_require__(1); -const { SourceMapConsumer, SourceMapGenerator } = __webpack_require__(10); +const { networkRequest } = __webpack_require__(3651); +const { SourceMapConsumer, SourceMapGenerator } = __webpack_require__(3705); -const assert = __webpack_require__(24); -const { fetchSourceMap } = __webpack_require__(25); +const assert = __webpack_require__(3717); +const { fetchSourceMap } = __webpack_require__(3718); const { getSourceMap, setSourceMap, clearSourceMaps -} = __webpack_require__(9); +} = __webpack_require__(3704); const { originalToGeneratedId, generatedToOriginalId, isGeneratedId, isOriginalId, getContentType -} = __webpack_require__(3); +} = __webpack_require__(3652); -const { WasmRemap } = __webpack_require__(14); +async function getOriginalURLs(generatedSource) { + const map = await fetchSourceMap(generatedSource); + return map && map.sources; +} const COMPUTED_SPANS = new WeakSet(); +/** + * Given an original location, find the ranges on the generated file that + * are mapped from the original range containing the location. + */ +async function getGeneratedRanges(location, originalSource) { + if (!isOriginalId(location.sourceId)) { + return []; + } + + const generatedSourceId = originalToGeneratedId(location.sourceId); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return []; + } + + if (!COMPUTED_SPANS.has(map)) { + COMPUTED_SPANS.add(map); + map.computeColumnSpans(); + } + + // We want to use 'allGeneratedPositionsFor' to get the _first_ generated + // location, but it hard-codes SourceMapConsumer.LEAST_UPPER_BOUND as the + // bias, making it search in the wrong direction for this usecase. + // To work around this, we use 'generatedPositionFor' and then look up the + // exact original location, making any bias value unnecessary, and then + // use that location for the call to 'allGeneratedPositionsFor'. + const genPos = map.generatedPositionFor({ + source: originalSource.url, + line: location.line, + column: location.column == null ? 0 : location.column, + bias: SourceMapConsumer.GREATEST_LOWER_BOUND + }); + if (genPos.line === null) { + return []; + } + + const positions = map.allGeneratedPositionsFor(map.originalPositionFor({ + line: genPos.line, + column: genPos.column + })); + + return positions.map(mapping => ({ + line: mapping.line, + columnStart: mapping.column, + columnEnd: mapping.lastColumn + })).sort((a, b) => { + const line = a.line - b.line; + return line === 0 ? a.column - b.column : line; + }); +} + +async function getGeneratedLocation(location, originalSource) { + if (!isOriginalId(location.sourceId)) { + return location; + } + + const generatedSourceId = originalToGeneratedId(location.sourceId); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return location; + } + + const { line, column } = map.generatedPositionFor({ + source: originalSource.url, + line: location.line, + column: location.column == null ? 0 : location.column, + bias: SourceMapConsumer.LEAST_UPPER_BOUND + }); + + return { + sourceId: generatedSourceId, + line, + column + }; +} + +async function getAllGeneratedLocations(location, originalSource) { + if (!isOriginalId(location.sourceId)) { + return []; + } + + const generatedSourceId = originalToGeneratedId(location.sourceId); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return []; + } + + const positions = map.allGeneratedPositionsFor({ + source: originalSource.url, + line: location.line, + column: location.column == null ? 0 : location.column + }); + + return positions.map(({ line, column }) => ({ + sourceId: generatedSourceId, + line, + column + })); +} + +async function getOriginalLocation(location) { + if (!isGeneratedId(location.sourceId)) { + return location; + } + + const map = await getSourceMap(location.sourceId); + if (!map) { + return location; + } + + const { source: sourceUrl, line, column } = map.originalPositionFor({ + line: location.line, + column: location.column == null ? 0 : location.column + }); + + if (sourceUrl == null) { + // No url means the location didn't map. + return location; + } + + return { + sourceId: generatedToOriginalId(location.sourceId, sourceUrl), + sourceUrl, + line, + column + }; +} + +async function getOriginalSourceText(originalSource) { + assert(isOriginalId(originalSource.id), "Source is not an original source"); + + const generatedSourceId = originalToGeneratedId(originalSource.id); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return null; + } + + let text = map.sourceContentFor(originalSource.url); + if (!text) { + text = (await networkRequest(originalSource.url, { loadFromCache: false })).content; + } + + return { + text, + contentType: getContentType(originalSource.url || "") + }; +} + +async function hasMappedSource(location) { + if (isOriginalId(location.sourceId)) { + return true; + } + + const loc = await getOriginalLocation(location); + return loc.sourceId !== location.sourceId; +} + function applySourceMap(generatedId, url, code, mappings) { const generator = new SourceMapGenerator({ file: url }); mappings.forEach(mapping => generator.addMapping(mapping)); @@ -2348,7 +2220,8 @@ module.exports = { }; /***/ }), -/* 18 */ + +/***/ 3711: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -2421,7 +2294,8 @@ exports.decode = function (charCode) { /***/ }), -/* 19 */ + +/***/ 3712: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -2431,7 +2305,7 @@ exports.decode = function (charCode) { * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(2); +var util = __webpack_require__(3668); /** * Determine whether mappingB is after mappingA with respect to generated @@ -2506,7 +2380,8 @@ exports.MappingList = MappingList; /***/ }), -/* 20 */ + +/***/ 3713: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -2516,11 +2391,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(2); -var binarySearch = __webpack_require__(21); -var ArraySet = __webpack_require__(13).ArraySet; -var base64VLQ = __webpack_require__(12); -var quickSort = __webpack_require__(22).quickSort; +var util = __webpack_require__(3668); +var binarySearch = __webpack_require__(3714); +var ArraySet = __webpack_require__(3708).ArraySet; +var base64VLQ = __webpack_require__(3707); +var quickSort = __webpack_require__(3715).quickSort; function SourceMapConsumer(aSourceMap, aSourceMapURL) { var sourceMap = aSourceMap; @@ -3564,7 +3439,7 @@ IndexedSourceMapConsumer.prototype.sourceContentFor = * and an object is returned with the following properties: * * - line: The line number in the generated source, or null. The - * line number is 1-based. + * line number is 1-based. * - column: The column number in the generated source, or null. * The column number is 0-based. */ @@ -3657,7 +3532,8 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 21 */ + +/***/ 3714: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -3774,7 +3650,8 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 22 */ + +/***/ 3715: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -3894,7 +3771,8 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 23 */ + +/***/ 3716: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -3904,8 +3782,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(11).SourceMapGenerator; -var util = __webpack_require__(2); +var SourceMapGenerator = __webpack_require__(3706).SourceMapGenerator; +var util = __webpack_require__(3668); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -4313,12 +4191,16 @@ exports.SourceNode = SourceNode; /***/ }), -/* 24 */ -/***/ (function(module, exports) { + +/***/ 3717: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + /* 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/. */ + * file, You can obtain one at . */ function assert(condition, message) { if (!condition) { @@ -4329,40 +4211,21 @@ function assert(condition, message) { module.exports = assert; /***/ }), -/* 25 */ + +/***/ 3718: /***/ (function(module, exports, __webpack_require__) { -let _resolveAndFetch = (() => { - var _ref = _asyncToGenerator(function* (generatedSource) { - // Fetch the sourcemap over the network and create it. - const { sourceMapURL, baseURL } = _resolveSourceMapURL(generatedSource); +"use strict"; - const fetched = yield networkRequest(sourceMapURL, { loadFromCache: false }); - - // Create the source map and fix it up. - let map = new SourceMapConsumer(fetched.content, baseURL); - if (generatedSource.isWasm) { - map = new WasmRemap(map); - } - - return map; - }); - - return function _resolveAndFetch(_x) { - return _ref.apply(this, arguments); - }; -})(); - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /* 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/. */ + * file, You can obtain one at . */ -const { networkRequest } = __webpack_require__(1); -const { getSourceMap, setSourceMap } = __webpack_require__(9); -const { WasmRemap } = __webpack_require__(14); -const { SourceMapConsumer } = __webpack_require__(10); +const { networkRequest } = __webpack_require__(3651); +const { getSourceMap, setSourceMap } = __webpack_require__(3704); +const { WasmRemap } = __webpack_require__(3719); +const { SourceMapConsumer } = __webpack_require__(3705); function _resolveSourceMapURL(source) { const { url = "", sourceMapURL = "" } = source; @@ -4385,6 +4248,21 @@ function _resolveSourceMapURL(source) { return { sourceMapURL: resolvedString, baseURL }; } +async function _resolveAndFetch(generatedSource) { + // Fetch the sourcemap over the network and create it. + const { sourceMapURL, baseURL } = _resolveSourceMapURL(generatedSource); + + const fetched = await networkRequest(sourceMapURL, { loadFromCache: false }); + + // Create the source map and fix it up. + let map = new SourceMapConsumer(fetched.content, baseURL); + if (generatedSource.isWasm) { + map = new WasmRemap(map); + } + + return map; +} + function fetchSourceMap(generatedSource) { const existingRequest = getSourceMap(generatedSource.id); @@ -4400,7 +4278,7 @@ function fetchSourceMap(generatedSource) { } if (!generatedSource.sourceMapURL) { - return Promise.resolve(null); + return null; } // Fire off the request, set it in the cache, and return it. @@ -4413,6 +4291,121 @@ function fetchSourceMap(generatedSource) { module.exports = { fetchSourceMap }; +/***/ }), + +/***/ 3719: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* 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 . */ + +/** + * SourceMapConsumer for WebAssembly source maps. It transposes columns with + * lines, which allows mapping data to be used with SpiderMonkey Debugger API. + */ +class WasmRemap { + /** + * @param map SourceMapConsumer + */ + constructor(map) { + this._map = map; + this.version = map.version; + this.file = map.file; + this._computeColumnSpans = false; + } + + get sources() { + return this._map.sources; + } + + get sourceRoot() { + return this._map.sourceRoot; + } + + get names() { + return this._map.names; + } + + get sourcesContent() { + return this._map.sourcesContent; + } + + get mappings() { + throw new Error("not supported"); + } + + computeColumnSpans() { + this._computeColumnSpans = true; + } + + originalPositionFor(generatedPosition) { + const result = this._map.originalPositionFor({ + line: 1, + column: generatedPosition.line, + bias: generatedPosition.bias + }); + return result; + } + + _remapGeneratedPosition(position) { + const generatedPosition = { + line: position.column, + column: 0 + }; + if (this._computeColumnSpans) { + generatedPosition.lastColumn = Infinity; + } + return generatedPosition; + } + + generatedPositionFor(originalPosition) { + const position = this._map.generatedPositionFor(originalPosition); + return this._remapGeneratedPosition(position); + } + + allGeneratedPositionsFor(originalPosition) { + const positions = this._map.allGeneratedPositionsFor(originalPosition); + return positions.map(position => { + return this._remapGeneratedPosition(position); + }); + } + + hasContentsOfAllSources() { + return this._map.hasContentsOfAllSources(); + } + + sourceContentFor(source, returnNullOnMissing) { + return this._map.sourceContentFor(source, returnNullOnMissing); + } + + eachMapping(callback, context, order) { + this._map.eachMapping(entry => { + const { + source, + generatedColumn, + originalLine, + originalColumn, + name + } = entry; + callback({ + source, + generatedLine: generatedColumn, + generatedColumn: 0, + originalLine, + originalColumn, + name + }); + }, context, order); + } +} + +exports.WasmRemap = WasmRemap; + /***/ }) -/******/ ]); -}); + +/******/ }); +}); \ No newline at end of file From 3b53239890a54e6c338c191531b4d9b2bb5649fa Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Mon, 7 May 2018 15:33:03 -0700 Subject: [PATCH 13/22] Bug 1459609 - Add missing null-check to ParserBase::setSourceMapInfo(). (r=Waldo) --HG-- extra : rebase_source : 03defc47db1436913c249aecbde6e609d9274397 --- js/src/frontend/Parser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a8f3805f654b..46152bfd3aa9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -979,6 +979,10 @@ TraceParser(JSTracer* trc, AutoGCRooter* parser) bool ParserBase::setSourceMapInfo() { + // Not all clients initialize ss. Can't update info to an object that isn't there. + if (!ss) + return true; + if (anyChars.hasDisplayURL()) { if (!ss->setDisplayURL(context, anyChars.displayURL())) return false; From 3cfbbae4f0119e34c0f5a3a205a3d332144fa464 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Mon, 7 May 2018 17:07:52 -0600 Subject: [PATCH 14/22] Bug 1457999: Update Valgrind intentional leak whitelist to include undecorated SaveToEnv; r=bustage --HG-- extra : rebase_source : f8282bdfb2c831cd086f0e5c61b80afaeb46e393 --- build/valgrind/cross-architecture.sup | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/valgrind/cross-architecture.sup b/build/valgrind/cross-architecture.sup index b8ebc4c6dc12..a66c90c15161 100644 --- a/build/valgrind/cross-architecture.sup +++ b/build/valgrind/cross-architecture.sup @@ -11,6 +11,13 @@ fun:_ZN7mozilla9SaveToEnvEPKc ... } +{ + PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534.) + Memcheck:Leak + ... + fun:SaveToEnv + ... +} { PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793549.) Memcheck:Leak From 5dfa7d1f803f836571b16586d3781d611dedc334 Mon Sep 17 00:00:00 2001 From: Eugen Sawin Date: Mon, 7 May 2018 21:31:30 +0200 Subject: [PATCH 15/22] Bug 1459759 - [1.0] Send settings to content modules on registration. r=jchen --- mobile/android/modules/geckoview/GeckoViewModule.jsm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mobile/android/modules/geckoview/GeckoViewModule.jsm b/mobile/android/modules/geckoview/GeckoViewModule.jsm index 82f1dca65e48..8fb4fb5adcf6 100644 --- a/mobile/android/modules/geckoview/GeckoViewModule.jsm +++ b/mobile/android/modules/geckoview/GeckoViewModule.jsm @@ -79,6 +79,8 @@ class GeckoViewModule { } self.messageManager.removeMessageListener("GeckoView:ContentRegistered", listener); + self.messageManager.sendAsyncMessage("GeckoView:UpdateSettings", + self.settings); self._eventProxy.enableQueuing(false); self._eventProxy.dispatchQueuedEvents(); }); From 8d99d56270597b0f8425469c61068624aca43c64 Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Fri, 4 May 2018 09:34:45 -0700 Subject: [PATCH 16/22] Bug 1456112 - Add a pref to implement the last Symantec Distrust step r=keeler This adds another preference (DistrustSymantecRootsRegardlessOfDate == 2) that stops permitting certificates issued after 1 June 2016, and updates the test to check it. --HG-- extra : transplant_source : %F1%DE%16m%F2%DD%A8Ei%EF%B4%CAo%BF%8D%A6%A6%5E%D4%89 --- security/certverifier/CertVerifier.h | 1 + .../certverifier/NSSCertDBTrustDomain.cpp | 9 +++++-- security/manager/ssl/nsNSSComponent.cpp | 1 + .../tests/unit/test_symantec_apple_google.js | 25 +++++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h index 575c7a052724..114c06137d45 100644 --- a/security/certverifier/CertVerifier.h +++ b/security/certverifier/CertVerifier.h @@ -66,6 +66,7 @@ enum class SHA1ModeResult { enum class DistrustedCAPolicy : uint32_t { Permit = 0, DistrustSymantecRoots = 1, + DistrustSymantecRootsRegardlessOfDate = 2, }; enum class NetscapeStepUpPolicy : uint32_t; diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index c154709ad46e..f5f283147be1 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -891,7 +891,7 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, // handshake. To determine this, we check mHostname: If it isn't set, this is // not TLS, so don't run the algorithm. if (mHostname && CertDNIsInList(root.get(), RootSymantecDNs) && - mDistrustedCAPolicy == DistrustedCAPolicy::DistrustSymantecRoots) { + mDistrustedCAPolicy != DistrustedCAPolicy::Permit) { rootCert = nullptr; // Clear the state for Segment... nsCOMPtr intCerts; @@ -907,8 +907,13 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, // (new Date("2016-06-01T00:00:00Z")).getTime() * 1000 static const PRTime JUNE_1_2016 = 1464739200000000; + PRTime permitAfterDate = 0; // 0 indicates there is no permitAfterDate + if (mDistrustedCAPolicy == DistrustedCAPolicy::DistrustSymantecRoots) { + permitAfterDate = JUNE_1_2016; + } + bool isDistrusted = false; - nsrv = CheckForSymantecDistrust(intCerts, eeCert, JUNE_1_2016, + nsrv = CheckForSymantecDistrust(intCerts, eeCert, permitAfterDate, RootAppleAndGoogleSPKIs, isDistrusted); if (NS_FAILED(nsrv)) { return Result::FATAL_ERROR_LIBRARY_FAILURE; diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index 5a1d27b7fb25..768d3e36946e 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -1694,6 +1694,7 @@ void nsNSSComponent::setValidationOptions(bool isInitialSetting) switch(distrustedCAPolicy) { case DistrustedCAPolicy::Permit: case DistrustedCAPolicy::DistrustSymantecRoots: + case DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate: break; default: distrustedCAPolicy = defaultCAPolicyMode; diff --git a/security/manager/ssl/tests/unit/test_symantec_apple_google.js b/security/manager/ssl/tests/unit/test_symantec_apple_google.js index 2ffdb5804b6a..2fe90553a826 100644 --- a/security/manager/ssl/tests/unit/test_symantec_apple_google.js +++ b/security/manager/ssl/tests/unit/test_symantec_apple_google.js @@ -39,6 +39,23 @@ add_connection_test("symantec-not-whitelisted-before-cutoff.example.com", MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, null, null); +// Enable the Firefox 63 total distrust; before or after cutoff should now all +// behave the same. +add_test(function() { + clearSessionCache(); + Services.prefs.setIntPref("security.pki.distrust_ca_policy", + /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 2); + run_next_test(); +}); + +add_connection_test("symantec-not-whitelisted-before-cutoff.example.com", + MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, + null, null); + +add_connection_test("symantec-not-whitelisted-after-cutoff.example.com", + MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, + null, null); + // Disable the distrust, should be back to the console warning add_test(function() { clearSessionCache(); @@ -77,6 +94,7 @@ add_task(async function() { // (as an external fetch is bad in the tests), disable OCSP first. Services.prefs.setIntPref("security.OCSP.enabled", 0); + // Try with the policy for 60 Services.prefs.setIntPref("security.pki.distrust_ca_policy", /* DistrustedCAPolicy::DistrustSymantecRoots */ 1); @@ -85,4 +103,11 @@ add_task(async function() { await checkCertErrorGenericAtTime(certDB, whitelistedCert, PRErrorCodeSuccess, certificateUsageSSLServer, VALIDATION_TIME); + + // Try with the policy for 63 + Services.prefs.setIntPref("security.pki.distrust_ca_policy", + /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 2); + + await checkCertErrorGenericAtTime(certDB, whitelistedCert, PRErrorCodeSuccess, + certificateUsageSSLServer, VALIDATION_TIME); }); From f1f556eac05f35a2b1df9e4c4ba4026ddab9afa6 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 7 May 2018 15:11:12 -0400 Subject: [PATCH 17/22] Bug 1459774 - Make cpstartup Talos test load the target over http:// rather than chrome://. r=jmaher MozReview-Commit-ID: 6XDV2a6bGEG --HG-- extra : source : 000a9b2308a0e9ef1b29edf22e6658a72813c1b4 extra : amend_source : 99380ed825639fd82e20f24d9fe8b3b50f41f933 --- testing/talos/talos/test.py | 1 + testing/talos/talos/tests/cpstartup/bootstrap.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/talos/talos/test.py b/testing/talos/talos/test.py index 264fcbd5f490..87734cee963a 100644 --- a/testing/talos/talos/test.py +++ b/testing/talos/talos/test.py @@ -304,6 +304,7 @@ class cpstartup(PageloaderTest): tploadnocache = True unit = 'ms' preferences = { + 'addon.test.cpstartup.webserver': '${webserver}', # By default, Talos is configured to open links from # content in new windows. We're overriding them so that # they open in new tabs instead. diff --git a/testing/talos/talos/tests/cpstartup/bootstrap.js b/testing/talos/talos/tests/cpstartup/bootstrap.js index fdf1de2905a3..f735598550a8 100644 --- a/testing/talos/talos/tests/cpstartup/bootstrap.js +++ b/testing/talos/talos/tests/cpstartup/bootstrap.js @@ -6,7 +6,9 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); const PREALLOCATED_PREF = "dom.ipc.processPrelaunch.enabled"; -const TARGET_URI = "chrome://cpstartup/content/target.html"; +const TARGET_PATH = "tests/cpstartup/content/target.html"; +const WEBSERVER = Services.prefs.getCharPref("addon.test.cpstartup.webserver"); +const TARGET_URI = `${WEBSERVER}/${TARGET_PATH}`; /** * The purpose of this test it to measure the performance of a content process startup. From 80f292e771b7b63f9f3ccaacffeeec7d2d236ca9 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Tue, 6 Feb 2018 22:12:33 -0800 Subject: [PATCH 18/22] Bug 1436271 - Replace calls to String.getBytes(String) with String.getBytes(Charset). r=nalexander Also replace calls to String(byte[], String) with String(byte[], Charset). This removes some cannot-happen exception handling. --- .../mozilla/gecko/dlc/TestDownloadAction.java | 5 ++-- .../catalog/TestDownloadContentCatalog.java | 3 ++- .../org/mozilla/gecko/push/TestPushState.java | 3 ++- .../gecko/db/BrowserDatabaseHelper.java | 8 ++---- .../org/mozilla/gecko/db/LoginsProvider.java | 4 +-- .../dlc/catalog/DownloadContentCatalog.java | 14 +++-------- .../gecko/icons/storage/DiskStorage.java | 12 ++++----- .../org/mozilla/gecko/push/PushState.java | 5 ++-- .../fxa/FxAccount20CreateDelegate.java | 22 +++++++--------- .../fxa/FxAccount20LoginDelegate.java | 13 ++++------ .../background/fxa/FxAccountClient20.java | 9 ++++--- .../gecko/background/fxa/FxAccountUtils.java | 23 +++++++++-------- .../fxa/QuickPasswordStretcher.java | 3 ++- .../gecko/browserid/JSONWebTokenUtils.java | 19 +++++++------- .../fxa/authenticator/AndroidFxAccount.java | 7 ++---- .../gecko/fxa/sync/FxAccountSyncAdapter.java | 3 ++- .../mozilla/gecko/sync/CommandProcessor.java | 8 +++--- .../org/mozilla/gecko/sync/CryptoRecord.java | 12 ++++----- .../gecko/sync/ExtendedJSONObject.java | 3 ++- .../java/org/mozilla/gecko/sync/Utils.java | 25 ++++++++----------- .../org/mozilla/gecko/sync/crypto/HKDF.java | 7 ++---- .../mozilla/gecko/sync/crypto/KeyBundle.java | 10 ++++---- .../Crypto5MiddlewareRepositorySession.java | 3 +-- .../sync/net/HMACAuthHeaderProvider.java | 6 ++--- .../sync/net/HawkAuthHeaderProvider.java | 16 ++++++------ .../sync/repositories/domain/Record.java | 8 ++---- .../sync/stage/SyncClientsEngineStage.java | 3 --- .../sync/telemetry/TelemetryCollector.java | 14 +++++------ .../telemetry/TelemetryEventCollector.java | 5 ++-- .../org/mozilla/gecko/util/PRNGFixes.java | 7 +----- .../net/test/TestCredentialsEndToEnd.java | 3 ++- .../android/sync/test/TestCollectionKeys.java | 3 ++- .../android/sync/test/TestCryptoRecord.java | 15 +++++------ .../login/TestFxAccountLoginStateMachine.java | 5 ++-- .../sync/crypto/test/TestCryptoInfo.java | 11 ++++---- .../gecko/sync/crypto/test/TestKeyBundle.java | 5 ++-- .../net/test/TestHMACAuthHeaderProvider.java | 2 +- .../net/test/TestHawkAuthHeaderProvider.java | 7 +++--- .../gecko/sync/net/test/TestLiveHawkAuth.java | 3 ++- .../telemetry/TelemetryCollectorTest.java | 11 ++++---- .../sync/test/TestExtendedJSONObject.java | 5 ++-- .../gecko/tests/testBrowserProvider.java | 5 ++-- .../mozilla/gecko/tests/testNativeCrypto.java | 5 ++-- 43 files changed, 168 insertions(+), 192 deletions(-) diff --git a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java index 4d4c37403cb9..a86202de969b 100644 --- a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java +++ b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java @@ -14,6 +14,7 @@ import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.dlc.catalog.DownloadContent; import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder; import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -223,7 +224,7 @@ public class TestDownloadAction { verify(connection).getInputStream(); verify(connection).setRequestProperty("Range", "bytes=1337-"); - Assert.assertEquals("HelloWorld", new String(outputStream.toByteArray(), "UTF-8")); + Assert.assertEquals("HelloWorld", new String(outputStream.toByteArray(), StringUtils.UTF_8)); verify(action).openFile(eq(temporaryFile), eq(true)); verify(catalog).markAsDownloaded(content); @@ -635,7 +636,7 @@ public class TestDownloadAction { HttpURLConnection connection = mock(HttpURLConnection.class); doReturn(statusCode).when(connection).getResponseCode(); - doReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))).when(connection).getInputStream(); + doReturn(new ByteArrayInputStream(content.getBytes(StringUtils.UTF_8))).when(connection).getInputStream(); return connection; } diff --git a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java index f7d7089699a9..d16fdd61e996 100644 --- a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java +++ b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java @@ -13,6 +13,7 @@ import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.mozilla.gecko.AppConstants; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.FileNotFoundException; @@ -37,7 +38,7 @@ public class TestDownloadContentCatalog { @Test public void testUntouchedCatalogHasNotChangedAndWillNotBePersisted() throws Exception { AtomicFile file = mock(AtomicFile.class); - doReturn("{content:[]}".getBytes("UTF-8")).when(file).readFully(); + doReturn("{content:[]}".getBytes(StringUtils.UTF_8)).when(file).readFully(); DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file)); catalog.loadFromDisk(); diff --git a/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java b/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java index 76e6e64128b8..779da35e3223 100644 --- a/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java +++ b/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java @@ -7,6 +7,7 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RuntimeEnvironment; import java.io.File; @@ -57,7 +58,7 @@ public class TestPushState { FileOutputStream fos = null; try { fos = new FileOutputStream(file); - fos.write("}".getBytes("UTF-8")); + fos.write("}".getBytes(StringUtils.UTF_8)); } finally { if (fos != null) { fos.close(); diff --git a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java index 4b86c418ced1..a23a7b738e83 100644 --- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java +++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java @@ -43,6 +43,7 @@ import org.mozilla.gecko.sync.SynchronizerConfiguration; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.repositories.android.RepoUtils; import org.mozilla.gecko.util.FileUtils; +import org.mozilla.gecko.util.StringUtils; import static org.mozilla.gecko.db.DBUtils.qualifyColumn; @@ -1782,18 +1783,13 @@ public class BrowserDatabaseHelper extends SQLiteOpenHelper { @RobocopTarget public static String getReaderCacheFileNameForURL(String url) { try { - // On KitKat and above we can use java.nio.charset.StandardCharsets.UTF_8 in place of "UTF8" - // which avoids having to handle UnsupportedCodingException - byte[] utf8 = url.getBytes("UTF8"); + byte[] utf8 = url.getBytes(StringUtils.UTF_8); final MessageDigest digester = MessageDigest.getInstance("MD5"); byte[] hash = digester.digest(utf8); final String hashString = new Base32().encodeAsString(hash); return hashString.substring(0, hashString.indexOf('=')) + ".json"; - } catch (UnsupportedEncodingException e) { - // This should never happen - throw new IllegalStateException("UTF8 encoding not available - can't process readercache filename"); } catch (NoSuchAlgorithmException e) { // This should also never happen throw new IllegalStateException("MD5 digester unavailable - can't process readercache filename"); diff --git a/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java b/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java index 740056a34e7a..5fd015460b33 100644 --- a/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java +++ b/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java @@ -498,7 +498,7 @@ public class LoginsProvider extends SharedBrowserDatabaseProvider { private String encrypt(@NonNull String initialValue) { try { final Cipher cipher = getCipher(Cipher.ENCRYPT_MODE); - return Base64.encodeToString(cipher.doFinal(initialValue.getBytes("UTF-8")), Base64.URL_SAFE); + return Base64.encodeToString(cipher.doFinal(initialValue.getBytes(StringUtils.UTF_8)), Base64.URL_SAFE); } catch (Exception e) { debug("encryption failed : " + e); throw new IllegalStateException("Logins encryption failed", e); @@ -509,7 +509,7 @@ public class LoginsProvider extends SharedBrowserDatabaseProvider { try { final Cipher cipher = getCipher(Cipher.DECRYPT_MODE); return new String(cipher.doFinal(Base64.decode( - initialValue.getBytes("UTF-8"), Base64.URL_SAFE)), StringUtils.UTF_8); + initialValue.getBytes(StringUtils.UTF_8), Base64.URL_SAFE)), StringUtils.UTF_8); } catch (Exception e) { debug("Decryption failed : " + e); throw new IllegalStateException("Logins decryption failed", e); diff --git a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java index b7afa4c09eac..e00da38d0603 100644 --- a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java +++ b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java @@ -14,12 +14,12 @@ import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.gecko.util.StringUtils; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; @@ -218,7 +218,7 @@ public class DownloadContentCatalog { JSONObject catalog; synchronized (file) { - catalog = new JSONObject(new String(file.readFully(), "UTF-8")); + catalog = new JSONObject(new String(file.readFully(), StringUtils.UTF_8)); } JSONArray array = catalog.getJSONArray(JSON_KEY_CONTENT); @@ -233,10 +233,6 @@ public class DownloadContentCatalog { Log.w(LOGTAG, "Unable to parse catalog JSON. Re-creating empty catalog.", e); loadedContent = new ArrayMap<>(); hasCatalogChanged = true; // Indicate that we want to persist the new catalog - } catch (UnsupportedEncodingException e) { - AssertionError error = new AssertionError("Should not happen: This device does not speak UTF-8"); - error.initCause(e); - throw error; } catch (IOException e) { Log.d(LOGTAG, "Can't read catalog due to IOException", e); } @@ -275,15 +271,11 @@ public class DownloadContentCatalog { JSONObject catalog = new JSONObject(); catalog.put(JSON_KEY_CONTENT, array); - outputStream.write(catalog.toString().getBytes("UTF-8")); + outputStream.write(catalog.toString().getBytes(StringUtils.UTF_8)); file.finishWrite(outputStream); hasCatalogChanged = false; - } catch (UnsupportedEncodingException e) { - AssertionError error = new AssertionError("Should not happen: This device does not speak UTF-8"); - error.initCause(e); - throw error; } catch (IOException | JSONException e) { Log.e(LOGTAG, "IOException during writing catalog", e); diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java b/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java index 3c0e2a55423b..d0438ac5002c 100644 --- a/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java +++ b/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java @@ -19,12 +19,12 @@ import org.mozilla.gecko.icons.IconRequest; import org.mozilla.gecko.icons.IconResponse; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.util.IOUtils; +import org.mozilla.gecko.util.StringUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.security.MessageDigest; /** @@ -257,10 +257,10 @@ public class DiskStorage { return null; } - byte[] data = prefix.getBytes("UTF-8"); + byte[] data = prefix.getBytes(StringUtils.UTF_8); NativeCrypto.sha256update(ctx, data, data.length); - data = url.getBytes("UTF-8"); + data = url.getBytes(StringUtils.UTF_8); NativeCrypto.sha256update(ctx, data, data.length); return Utils.byte2Hex(NativeCrypto.sha256finalize(ctx)); } catch (NoClassDefFoundError | ExceptionInInitializerError error) { @@ -269,15 +269,13 @@ public class DiskStorage { // we will have a lot of other problems if we can't load libmozglue.so try { MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(prefix.getBytes("UTF-8")); - md.update(url.getBytes("UTF-8")); + md.update(prefix.getBytes(StringUtils.UTF_8)); + md.update(url.getBytes(StringUtils.UTF_8)); return Utils.byte2Hex(md.digest()); } catch (Exception e) { // Just give up. And let everyone know. throw new RuntimeException(e); } - } catch (UnsupportedEncodingException e) { - throw new AssertionError("Should not happen: Device does not understand UTF-8"); } } diff --git a/mobile/android/base/java/org/mozilla/gecko/push/PushState.java b/mobile/android/base/java/org/mozilla/gecko/push/PushState.java index 686bf5a0d1e3..2f84cd9690e5 100644 --- a/mobile/android/base/java/org/mozilla/gecko/push/PushState.java +++ b/mobile/android/base/java/org/mozilla/gecko/push/PushState.java @@ -13,6 +13,7 @@ import android.util.Log; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.gecko.util.StringUtils; import java.io.File; import java.io.FileNotFoundException; @@ -46,7 +47,7 @@ public class PushState { file = new AtomicFile(new File(context.getApplicationInfo().dataDir, fileName)); synchronized (file) { try { - final String s = new String(file.readFully(), "UTF-8"); + final String s = new String(file.readFully(), StringUtils.UTF_8); final JSONObject temp = new JSONObject(s); if (temp.optLong("version", 0L) != VERSION) { throw new JSONException("Unknown version!"); @@ -91,7 +92,7 @@ public class PushState { FileOutputStream fileOutputStream = null; try { fileOutputStream = file.startWrite(); - fileOutputStream.write(toJSONObject().toString().getBytes("UTF-8")); + fileOutputStream.write(toJSONObject().toString().getBytes(StringUtils.UTF_8)); file.finishWrite(fileOutputStream); return true; } catch (JSONException | IOException e) { diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java index 98809137fb2d..9e696db6792d 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java @@ -6,6 +6,7 @@ package org.mozilla.gecko.background.fxa; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; @@ -25,7 +26,6 @@ public class FxAccount20CreateDelegate { * @param preVerified * true if account should be marked already verified; only effective * for non-production auth servers. - * @throws UnsupportedEncodingException * @throws GeneralSecurityException */ public FxAccount20CreateDelegate(byte[] emailUTF8, byte[] quickStretchedPW, boolean preVerified) throws UnsupportedEncodingException, GeneralSecurityException { @@ -34,19 +34,15 @@ public class FxAccount20CreateDelegate { this.preVerified = preVerified; } - public ExtendedJSONObject getCreateBody() throws FxAccountClientException { + public ExtendedJSONObject getCreateBody() { final ExtendedJSONObject body = new ExtendedJSONObject(); - try { - body.put("email", new String(emailUTF8, "UTF-8")); - body.put("authPW", Utils.byte2Hex(authPW)); - if (preVerified) { - // Production endpoints do not allow preVerified; this assumes we only - // set it when it's okay to send it. - body.put("preVerified", preVerified); - } - return body; - } catch (UnsupportedEncodingException e) { - throw new FxAccountClientException(e); + body.put("email", new String(emailUTF8, StringUtils.UTF_8)); + body.put("authPW", Utils.byte2Hex(authPW)); + if (preVerified) { + // Production endpoints do not allow preVerified; this assumes we only + // set it when it's okay to send it. + body.put("preVerified", preVerified); } + return body; } } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java index 0266a6eab9ac..f2544c9a9057 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java @@ -6,6 +6,7 @@ package org.mozilla.gecko.background.fxa; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; @@ -23,14 +24,10 @@ public class FxAccount20LoginDelegate { this.authPW = FxAccountUtils.generateAuthPW(quickStretchedPW); } - public ExtendedJSONObject getCreateBody() throws FxAccountClientException { + public ExtendedJSONObject getCreateBody() { final ExtendedJSONObject body = new ExtendedJSONObject(); - try { - body.put("email", new String(emailUTF8, "UTF-8")); - body.put("authPW", Utils.byte2Hex(authPW)); - return body; - } catch (UnsupportedEncodingException e) { - throw new FxAccountClientException(e); - } + body.put("email", new String(emailUTF8, StringUtils.UTF_8)); + body.put("authPW", Utils.byte2Hex(authPW)); + return body; } } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java index e35fca9e045a..fa2d927b47cc 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java @@ -24,6 +24,7 @@ import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider; import org.mozilla.gecko.sync.net.Resource; import org.mozilla.gecko.sync.net.SyncResponse; import org.mozilla.gecko.sync.net.SyncStorageResponse; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -647,7 +648,7 @@ public class FxAccountClient20 implements FxAccountClient { if (getKeys) { keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN)); } - LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, "UTF-8"), uid, verified, sessionToken, keyFetchToken); + LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, StringUtils.UTF_8), uid, verified, sessionToken, keyFetchToken); delegate.handleSuccess(loginResponse); } @@ -697,7 +698,7 @@ public class FxAccountClient20 implements FxAccountClient { if (getKeys) { keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN)); } - LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, "UTF-8"), uid, verified, sessionToken, keyFetchToken); + LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, StringUtils.UTF_8), uid, verified, sessionToken, keyFetchToken); delegate.handleSuccess(loginResponse); } @@ -736,7 +737,7 @@ public class FxAccountClient20 implements FxAccountClient { final RequestDelegate delegate) { byte[] quickStretchedPW; try { - FxAccountUtils.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, "UTF-8") + "'" ); + FxAccountUtils.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, StringUtils.UTF_8) + "'" ); quickStretchedPW = stretcher.getQuickStretchedPW(emailUTF8); } catch (Exception e) { delegate.handleError(e); @@ -768,7 +769,7 @@ public class FxAccountClient20 implements FxAccountClient { try { // Nota bene: this is not recursive, since we call the fixed password // signature here, which invokes a non-retrying version. - byte[] alternateEmailUTF8 = alternateEmail.getBytes("UTF-8"); + byte[] alternateEmailUTF8 = alternateEmail.getBytes(StringUtils.UTF_8); byte[] alternateQuickStretchedPW = stretcher.getQuickStretchedPW(alternateEmailUTF8); login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, queryParameters, delegate); } catch (Exception innerException) { diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java index 6b8919fc4527..c4e7b1ae5bca 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java @@ -20,6 +20,7 @@ import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.crypto.HKDF; import org.mozilla.gecko.sync.crypto.KeyBundle; import org.mozilla.gecko.sync.crypto.PBKDF2; +import org.mozilla.gecko.util.StringUtils; import android.content.Context; @@ -49,21 +50,21 @@ public class FxAccountUtils { } } - public static String bytes(String string) throws UnsupportedEncodingException { - return Utils.byte2Hex(string.getBytes("UTF-8")); + public static String bytes(String string) { + return Utils.byte2Hex(string.getBytes(StringUtils.UTF_8)); } - public static byte[] KW(String name) throws UnsupportedEncodingException { + public static byte[] KW(String name) { return Utils.concatAll( - KW_VERSION_STRING.getBytes("UTF-8"), - name.getBytes("UTF-8")); + KW_VERSION_STRING.getBytes(StringUtils.UTF_8), + name.getBytes(StringUtils.UTF_8)); } - public static byte[] KWE(String name, byte[] emailUTF8) throws UnsupportedEncodingException { + public static byte[] KWE(String name, byte[] emailUTF8) { return Utils.concatAll( - KW_VERSION_STRING.getBytes("UTF-8"), - name.getBytes("UTF-8"), - ":".getBytes("UTF-8"), + KW_VERSION_STRING.getBytes(StringUtils.UTF_8), + name.getBytes(StringUtils.UTF_8), + ":".getBytes(StringUtils.UTF_8), emailUTF8); } @@ -71,8 +72,8 @@ public class FxAccountUtils { * Calculate the SRP verifier x value. */ public static BigInteger srpVerifierLowercaseX(byte[] emailUTF8, byte[] srpPWBytes, byte[] srpSaltBytes) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - byte[] inner = Utils.sha256(Utils.concatAll(emailUTF8, ":".getBytes("UTF-8"), srpPWBytes)); + throws NoSuchAlgorithmException { + byte[] inner = Utils.sha256(Utils.concatAll(emailUTF8, ":".getBytes(StringUtils.UTF_8), srpPWBytes)); byte[] outer = Utils.sha256(Utils.concatAll(srpSaltBytes, inner)); return new BigInteger(1, outer); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java index bf4b1bc97558..a45f6dc2a23f 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; public class QuickPasswordStretcher implements PasswordStretcher { protected final String password; @@ -26,7 +27,7 @@ public class QuickPasswordStretcher implements PasswordStretcher { } String key = Utils.byte2Hex(emailUTF8); if (!cache.containsKey(key)) { - byte[] value = FxAccountUtils.generateQuickStretchedPW(emailUTF8, password.getBytes("UTF-8")); + byte[] value = FxAccountUtils.generateQuickStretchedPW(emailUTF8, password.getBytes(StringUtils.UTF_8)); cache.put(key, Utils.byte2Hex(value)); return value; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java index 4d4589b7256d..4a4b4341014f 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java @@ -4,15 +4,16 @@ package org.mozilla.gecko.browserid; +import static org.mozilla.apache.commons.codec.binary.StringUtils.newStringUtf8; + import org.json.simple.JSONObject; import org.mozilla.apache.commons.codec.binary.Base64; -import org.mozilla.apache.commons.codec.binary.StringUtils; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.TreeMap; @@ -32,21 +33,21 @@ public class JSONWebTokenUtils { public static final String DEFAULT_CERTIFICATE_ISSUER = "127.0.0.1"; public static final String DEFAULT_ASSERTION_ISSUER = "127.0.0.1"; - public static String encode(String payload, SigningPrivateKey privateKey) throws UnsupportedEncodingException, GeneralSecurityException { + public static String encode(String payload, SigningPrivateKey privateKey) throws GeneralSecurityException { final ExtendedJSONObject header = new ExtendedJSONObject(); header.put("alg", privateKey.getAlgorithm()); - String encodedHeader = Base64.encodeBase64URLSafeString(header.toJSONString().getBytes("UTF-8")); - String encodedPayload = Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")); + String encodedHeader = Base64.encodeBase64URLSafeString(header.toJSONString().getBytes(StringUtils.UTF_8)); + String encodedPayload = Base64.encodeBase64URLSafeString(payload.getBytes(StringUtils.UTF_8)); ArrayList segments = new ArrayList(); segments.add(encodedHeader); segments.add(encodedPayload); - byte[] message = Utils.toDelimitedString(".", segments).getBytes("UTF-8"); + byte[] message = Utils.toDelimitedString(".", segments).getBytes(StringUtils.UTF_8); byte[] signature = privateKey.signMessage(message); segments.add(Base64.encodeBase64URLSafeString(signature)); return Utils.toDelimitedString(".", segments); } - public static String decode(String token, VerifyingPublicKey publicKey) throws GeneralSecurityException, UnsupportedEncodingException { + public static String decode(String token, VerifyingPublicKey publicKey) throws GeneralSecurityException { if (token == null) { throw new IllegalArgumentException("token must not be null"); } @@ -54,13 +55,13 @@ public class JSONWebTokenUtils { if (segments == null || segments.length != 3) { throw new GeneralSecurityException("malformed token"); } - byte[] message = (segments[0] + "." + segments[1]).getBytes("UTF-8"); + byte[] message = (segments[0] + "." + segments[1]).getBytes(StringUtils.UTF_8); byte[] signature = Base64.decodeBase64(segments[2]); boolean verifies = publicKey.verifyMessage(message, signature); if (!verifies) { throw new GeneralSecurityException("bad signature"); } - String payload = StringUtils.newStringUtf8(Base64.decodeBase64(segments[1])); + String payload = newStringUtf8(Base64.decodeBase64(segments[1])); return payload; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java index eaf619068fdc..830a1a9bf233 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java @@ -45,6 +45,7 @@ import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.ThreadPool; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.setup.Constants; +import org.mozilla.gecko.util.StringUtils; import org.mozilla.gecko.util.ThreadUtils; import java.io.IOException; @@ -495,11 +496,7 @@ public class AndroidFxAccount { public ExtendedJSONObject toJSONObject() { ExtendedJSONObject o = unbundle(); o.put("email", account.name); - try { - o.put("emailUTF8", Utils.byte2Hex(account.name.getBytes("UTF-8"))); - } catch (UnsupportedEncodingException e) { - // Ignore. - } + o.put("emailUTF8", Utils.byte2Hex(account.name.getBytes(StringUtils.UTF_8))); o.put("fxaDeviceId", getDeviceId()); o.put("fxaDeviceRegistrationVersion", getDeviceRegistrationVersion()); o.put("fxaDeviceRegistrationTimestamp", getDeviceRegistrationTimestamp()); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java index 3677a8d133ed..9b53c0671c85 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java @@ -57,6 +57,7 @@ import org.mozilla.gecko.tokenserver.TokenServerClient; import org.mozilla.gecko.tokenserver.TokenServerClientDelegate; import org.mozilla.gecko.tokenserver.TokenServerException; import org.mozilla.gecko.tokenserver.TokenServerToken; +import org.mozilla.gecko.util.StringUtils; import java.net.URI; import java.net.URISyntaxException; @@ -408,7 +409,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { // so we explicitly do not send payload verification hashes to the // Sync storage endpoint. final boolean includePayloadVerificationHash = false; - final AuthHeaderProvider authHeaderProvider = new HawkAuthHeaderProvider(token.id, token.key.getBytes("UTF-8"), includePayloadVerificationHash, storageServerSkew); + final AuthHeaderProvider authHeaderProvider = new HawkAuthHeaderProvider(token.id, token.key.getBytes(StringUtils.UTF_8), includePayloadVerificationHash, storageServerSkew); final Context context = getContext(); final SyncConfiguration syncConfig = new SyncConfiguration(token.uid, authHeaderProvider, sharedPrefs, syncKeyBundle); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java index 8570095e045f..15890b953aac 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java @@ -21,8 +21,8 @@ import org.mozilla.gecko.sync.repositories.NullCursorException; import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; import org.mozilla.gecko.sync.telemetry.TelemetryEventCollector; +import org.mozilla.gecko.util.StringUtils; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; @@ -267,10 +267,10 @@ public class CommandProcessor { extra.put("flowID", command.flowID); } try { - extra.put("deviceID", Utils.byte2Hex(Utils.sha256(clientID.concat(hashedFxAUID).getBytes("UTF-8")))); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + extra.put("deviceID", Utils.byte2Hex(Utils.sha256(clientID.concat(hashedFxAUID).getBytes(StringUtils.UTF_8)))); + } catch (NoSuchAlgorithmException e) { // Should not happen. - Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); + Log.e(LOG_TAG, "SHA-256 is not supported", e); } TelemetryEventCollector.recordEvent(context, "sendcommand", command.commandType, null, extra); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java index ca7e08a952ff..86bee17f1d06 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java @@ -5,7 +5,6 @@ package org.mozilla.gecko.sync; import java.io.IOException; -import java.io.UnsupportedEncodingException; import org.json.simple.JSONObject; import org.mozilla.apache.commons.codec.binary.Base64; @@ -56,11 +55,10 @@ public class CryptoRecord extends Record { * Input: JSONObject containing a valid payload (cipherText, IV, HMAC), * KeyBundle with keys for decryption. Output: byte[] clearText * @throws CryptoException - * @throws UnsupportedEncodingException */ - private static byte[] decryptPayload(ExtendedJSONObject payload, KeyBundle keybundle) throws CryptoException, UnsupportedEncodingException { - byte[] ciphertext = Base64.decodeBase64(((String) payload.get(KEY_CIPHERTEXT)).getBytes("UTF-8")); - byte[] iv = Base64.decodeBase64(((String) payload.get(KEY_IV)).getBytes("UTF-8")); + private static byte[] decryptPayload(ExtendedJSONObject payload, KeyBundle keybundle) throws CryptoException { + byte[] ciphertext = Base64.decodeBase64(((String) payload.get(KEY_CIPHERTEXT)).getBytes(StringUtils.UTF_8)); + byte[] iv = Base64.decodeBase64(((String) payload.get(KEY_IV)).getBytes(StringUtils.UTF_8)); byte[] hmac = Utils.hex2Byte((String) payload.get(KEY_HMAC)); return CryptoInfo.decrypt(ciphertext, iv, hmac, keybundle).getMessage(); @@ -131,7 +129,7 @@ public class CryptoRecord extends Record { */ public static CryptoRecord fromJSONRecord(String jsonRecord) throws NonObjectJSONException, IOException, RecordParseException { - byte[] bytes = jsonRecord.getBytes("UTF-8"); + byte[] bytes = jsonRecord.getBytes(StringUtils.UTF_8); ExtendedJSONObject object = ExtendedJSONObject.parseUTF8AsJSONObject(bytes); return CryptoRecord.fromJSONRecord(object); @@ -201,7 +199,7 @@ public class CryptoRecord extends Record { return this; } - public CryptoRecord encrypt() throws CryptoException, UnsupportedEncodingException { + public CryptoRecord encrypt() throws CryptoException { if (this.keyBundle == null) { throw new NoKeyBundleException(); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java index 69ffbbd61fdc..8a572f4336d2 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java @@ -10,6 +10,7 @@ import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.sync.UnexpectedJSONException.BadRequiredFieldJSONException; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; import java.io.Reader; @@ -138,7 +139,7 @@ public class ExtendedJSONObject implements Cloneable { */ public static ExtendedJSONObject parseUTF8AsJSONObject(byte[] in) throws NonObjectJSONException, IOException { - return new ExtendedJSONObject(new String(in, "UTF-8")); + return new ExtendedJSONObject(new String(in, StringUtils.UTF_8)); } public ExtendedJSONObject() { diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java index 4544aa919e62..fbf67648bdc8 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java @@ -7,7 +7,6 @@ package org.mozilla.gecko.sync; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLDecoder; @@ -127,11 +126,9 @@ public class Utils { * An input string. Will be decoded as UTF-8. * @return * A byte array of decoded values. - * @throws UnsupportedEncodingException - * Should not occur. */ - public static byte[] decodeBase64(String base64) throws UnsupportedEncodingException { - return Base64.decodeBase64(base64.getBytes("UTF-8")); + public static byte[] decodeBase64(String base64) { + return Base64.decodeBase64(base64.getBytes(StringUtils.UTF_8)); } public static byte[] decodeFriendlyBase32(String base32) { @@ -202,8 +199,8 @@ public class Utils { } protected static byte[] sha1(final String utf8) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - final byte[] bytes = utf8.getBytes("UTF-8"); + throws NoSuchAlgorithmException { + final byte[] bytes = utf8.getBytes(StringUtils.UTF_8); try { return NativeCrypto.sha1(bytes); } catch (final LinkageError e) { @@ -213,12 +210,12 @@ public class Utils { Logger.warn(LOG_TAG, "Got throwable stretching password using native sha1 implementation; " + "ignoring and using Java implementation.", e); final MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); - return sha1.digest(utf8.getBytes("UTF-8")); + return sha1.digest(utf8.getBytes(StringUtils.UTF_8)); } } protected static String sha1Base32(final String utf8) - throws NoSuchAlgorithmException, UnsupportedEncodingException { + throws NoSuchAlgorithmException { return new Base32().encodeAsString(sha1(utf8)).toLowerCase(Locale.US); } @@ -229,10 +226,9 @@ public class Utils { * An account string. * @return * An acceptable string. - * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException */ - public static String usernameFromAccount(final String account) throws NoSuchAlgorithmException, UnsupportedEncodingException { + public static String usernameFromAccount(final String account) throws NoSuchAlgorithmException { if (account == null || account.equals("")) { throw new IllegalArgumentException("No account name provided."); } @@ -252,10 +248,9 @@ public class Utils { * @param version the version of preferences to reference. * @return the path. * @throws NoSuchAlgorithmException - * @throws UnsupportedEncodingException */ public static String getPrefsPath(final String product, final String accountKey, final String serverURL, final String profile, final long version) - throws NoSuchAlgorithmException, UnsupportedEncodingException { + throws NoSuchAlgorithmException { final String encodedAccount = sha1Base32(serverURL + ":" + usernameFromAccount(accountKey)); if (version <= 0) { @@ -515,13 +510,13 @@ public class Utils { * This is the format produced by desktop Firefox when exchanging credentials * containing non-ASCII characters. */ - public static String decodeUTF8(final String in) throws UnsupportedEncodingException { + public static String decodeUTF8(final String in) { final int length = in.length(); final byte[] asciiBytes = new byte[length]; for (int i = 0; i < length; ++i) { asciiBytes[i] = (byte) in.codePointAt(i); } - return new String(asciiBytes, "UTF-8"); + return new String(asciiBytes, StringUtils.UTF_8); } /** diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java index f5136f10966d..7e273fc2861e 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java @@ -12,6 +12,7 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; /* * A standards-compliant implementation of RFC 5869 @@ -25,11 +26,7 @@ public class HKDF { * Used for conversion in cases in which you *know* the encoding exists. */ public static final byte[] bytes(String in) { - try { - return in.getBytes("UTF-8"); - } catch (java.io.UnsupportedEncodingException e) { - return null; - } + return in.getBytes(StringUtils.UTF_8); } public static final int BLOCKSIZE = 256 / 8; diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java index 2063b1e32aaa..b61d546d2dda 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java @@ -4,7 +4,6 @@ package org.mozilla.gecko.sync.crypto; -import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -14,6 +13,7 @@ import javax.crypto.Mac; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; public class KeyBundle { private static final String KEY_ALGORITHM_SPEC = "AES"; @@ -44,7 +44,7 @@ public class KeyBundle { // Hash appropriately. try { username = Utils.usernameFromAccount(username); - } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("Invalid username."); } @@ -77,9 +77,9 @@ public class KeyBundle { * * @return A KeyBundle with the specified keys. */ - public static KeyBundle fromBase64EncodedKeys(String base64EncryptionKey, String base64HmacKey) throws UnsupportedEncodingException { - return new KeyBundle(Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8")), - Base64.decodeBase64(base64HmacKey.getBytes("UTF-8"))); + public static KeyBundle fromBase64EncodedKeys(String base64EncryptionKey, String base64HmacKey) { + return new KeyBundle(Base64.decodeBase64(base64EncryptionKey.getBytes(StringUtils.UTF_8)), + Base64.decodeBase64(base64HmacKey.getBytes(StringUtils.UTF_8))); } /** diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java index 8377e7d12042..ead31d581646 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java @@ -4,7 +4,6 @@ package org.mozilla.gecko.sync.middleware; -import java.io.UnsupportedEncodingException; import java.util.concurrent.ExecutorService; import org.mozilla.gecko.sync.CryptoRecord; @@ -161,7 +160,7 @@ public class Crypto5MiddlewareRepositorySession extends MiddlewareRepositorySess rec.keyBundle = this.keyBundle; try { rec.encrypt(); - } catch (UnsupportedEncodingException | CryptoException e) { + } catch (CryptoException e) { storeDelegate.onRecordStoreFailed(e, record.guid); return; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java index 5314d345b63c..6a601c02212a 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java @@ -16,6 +16,7 @@ import javax.crypto.spec.SecretKeySpec; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase; @@ -197,11 +198,10 @@ public class HMACAuthHeaderProvider implements AuthHeaderProvider { * @return signature as base-64 encoded string. * @throws InvalidKeyException * @throws NoSuchAlgorithmException - * @throws UnsupportedEncodingException */ protected static String getSignature(String requestString, String key) - throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { - String macString = Base64.encodeBase64String(sha1(requestString.getBytes("UTF-8"), key.getBytes("UTF-8"))); + throws InvalidKeyException, NoSuchAlgorithmException { + String macString = Base64.encodeBase64String(sha1(requestString.getBytes(StringUtils.UTF_8), key.getBytes(StringUtils.UTF_8))); return macString; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java index 2bdd5604a871..97ec3e84c64a 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java @@ -20,6 +20,7 @@ import javax.crypto.spec.SecretKeySpec; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.HttpEntity; @@ -151,7 +152,7 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { String app = null; String dlg = null; String requestString = getRequestString(request, "header", timestamp, nonce, payloadHash, extra, app, dlg); - String macString = getSignature(requestString.getBytes("UTF-8"), this.key); + String macString = getSignature(requestString.getBytes(StringUtils.UTF_8), this.key); StringBuilder sb = new StringBuilder(); sb.append("Hawk id=\""); @@ -191,12 +192,11 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { * to compute hash for. * @return verification hash, or null if the request does not enclose an entity. * @throws IllegalArgumentException if the request does not enclose a valid non-null entity. - * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException * @throws IOException */ protected static String getPayloadHashString(HttpRequestBase request) - throws UnsupportedEncodingException, NoSuchAlgorithmException, IOException, IllegalArgumentException { + throws NoSuchAlgorithmException, IOException, IllegalArgumentException { final boolean shouldComputePayloadHash = request instanceof HttpEntityEnclosingRequest; if (!shouldComputePayloadHash) { Logger.debug(LOG_TAG, "Not computing payload verification hash for non-enclosing request."); @@ -278,14 +278,14 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { * @return hash. * @throws IllegalArgumentException if entity is not repeatable. */ - protected static byte[] getPayloadHash(HttpEntity entity) throws UnsupportedEncodingException, IOException, NoSuchAlgorithmException { + protected static byte[] getPayloadHash(HttpEntity entity) throws IOException, NoSuchAlgorithmException { if (!entity.isRepeatable()) { throw new IllegalArgumentException("entity must be repeatable"); } final MessageDigest digest = MessageDigest.getInstance("SHA-256"); - digest.update(("hawk." + HAWK_HEADER_VERSION + ".payload\n").getBytes("UTF-8")); - digest.update(getBaseContentType(entity.getContentType()).getBytes("UTF-8")); - digest.update("\n".getBytes("UTF-8")); + digest.update(("hawk." + HAWK_HEADER_VERSION + ".payload\n").getBytes(StringUtils.UTF_8)); + digest.update(getBaseContentType(entity.getContentType()).getBytes(StringUtils.UTF_8)); + digest.update("\n".getBytes(StringUtils.UTF_8)); InputStream stream = entity.getContent(); try { int numRead; @@ -295,7 +295,7 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { digest.update(buffer, 0, numRead); } } - digest.update("\n".getBytes("UTF-8")); // Trailing newline is specified by Hawk. + digest.update("\n".getBytes(StringUtils.UTF_8)); // Trailing newline is specified by Hawk. return digest.digest(); } finally { stream.close(); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java index 5ca3a4ffa1b4..e09aaead5fb0 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java @@ -11,6 +11,7 @@ import java.io.UnsupportedEncodingException; import org.json.simple.JSONObject; import org.mozilla.gecko.sync.CryptoRecord; import org.mozilla.gecko.sync.ExtendedJSONObject; +import org.mozilla.gecko.util.StringUtils; /** * Record is the abstract base class for all entries that Sync processes: @@ -259,12 +260,7 @@ public abstract class Record { } public static byte[] stringToJSONBytes(String in) { - try { - return in.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - // Can't happen. - return null; - } + return in.getBytes(StringUtils.UTF_8); } /** diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java index cb82c8f60504..d18c075bd6e6 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java @@ -11,7 +11,6 @@ import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -672,8 +671,6 @@ public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage { return null; } return cryptoRecord.encrypt(); - } catch (UnsupportedEncodingException e) { - doAbort(e, encryptionFailure + " Unsupported encoding."); } catch (CryptoException e) { doAbort(e, encryptionFailure); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java index 15b0d08eaba4..8ce884386809 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java @@ -18,8 +18,8 @@ import org.mozilla.gecko.sync.net.SyncStorageResponse; import org.mozilla.gecko.sync.repositories.FetchFailedException; import org.mozilla.gecko.sync.repositories.StoreFailedException; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; +import org.mozilla.gecko.util.StringUtils; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; @@ -77,11 +77,11 @@ public class TelemetryCollector { this.hashedUID = uid; try { this.hashedDeviceID = Utils.byte2Hex(Utils.sha256( - deviceID.concat(uid).getBytes("UTF-8") + deviceID.concat(uid).getBytes(StringUtils.UTF_8) )); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // Should not happen. - Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); + Log.e(LOG_TAG, "SHA-256 is not supported", e); } } @@ -128,11 +128,11 @@ public class TelemetryCollector { try { device.putString( TelemetryContract.KEY_DEVICE_ID, - Utils.byte2Hex(Utils.sha256(clientAndUid.getBytes("UTF-8"))) + Utils.byte2Hex(Utils.sha256(clientAndUid.getBytes(StringUtils.UTF_8))) ); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // Should not happen. - Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); + Log.e(LOG_TAG, "SHA-256 is not supported", e); } devices.add(device); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java index 03b76f9f7c8a..fe3bb0e9f54d 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java @@ -21,6 +21,7 @@ import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.delegates.ClientsDataDelegate; import org.mozilla.gecko.sync.net.BaseResource; +import org.mozilla.gecko.util.StringUtils; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; @@ -126,10 +127,10 @@ public class TelemetryEventCollector { final ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs, context); try { final String hashedDeviceID = Utils.byte2Hex(Utils.sha256( - clientsDataDelegate.getAccountGUID().concat(hashedFxAUID).getBytes("UTF-8") + clientsDataDelegate.getAccountGUID().concat(hashedFxAUID).getBytes(StringUtils.UTF_8) )); event.putString(TelemetryContract.KEY_LOCAL_DEVICE_ID, hashedDeviceID); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // Should not happen. Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); return false; diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java b/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java index ebb50f765927..25d5c6ff1893 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java @@ -22,7 +22,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; @@ -330,10 +329,6 @@ public final class PRNGFixes { if (serial != null) { result.append(serial); } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } + return result.toString().getBytes(StringUtils.UTF_8); } } diff --git a/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java b/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java index 53615670b27c..c9a096411327 100644 --- a/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java +++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java @@ -9,6 +9,7 @@ import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -53,7 +54,7 @@ public class TestCredentialsEndToEnd { final String decoded = Utils.decodeUTF8(password); final byte[] expectedBytes = Utils.decodeBase64(BTOA_PASSWORD); - final String expected = new String(expectedBytes, "UTF-8"); + final String expected = new String(expectedBytes, StringUtils.UTF_8); assertEquals(DESKTOP_ASSERTED_SIZE, password.length()); assertEquals(expected, decoded); diff --git a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java index 3ee2f20a6afb..a4c23b1b8819 100644 --- a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java +++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java @@ -13,6 +13,7 @@ import org.mozilla.gecko.sync.NoCollectionKeysSetException; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.crypto.CryptoException; import org.mozilla.gecko.sync.crypto.KeyBundle; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -80,7 +81,7 @@ public class TestCollectionKeys { rec.encrypt(); CollectionKeys ck = new CollectionKeys(); ck.setKeyPairsFromWBO(rec, syncKeyBundle); - byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes("UTF-8"); + byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes(StringUtils.UTF_8); byte[] expected = Base64.decodeBase64(input); assertSame(expected, ck.defaultKeyBundle().getEncryptionKey()); } diff --git a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java index 648a75819929..d741a6fbf609 100644 --- a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java +++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java @@ -17,6 +17,7 @@ import org.mozilla.gecko.sync.crypto.KeyBundle; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; import org.mozilla.gecko.sync.repositories.domain.HistoryRecord; import org.mozilla.gecko.sync.repositories.domain.Record; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -109,8 +110,8 @@ public class TestCryptoRecord { payload.put("hmac", base16Hmac); body.put("payload", payload.toJSONString()); CryptoRecord record = CryptoRecord.fromJSONRecord(body); - byte[] decodedKey = Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8")); - byte[] decodedHMAC = Base64.decodeBase64(base64HmacKey.getBytes("UTF-8")); + byte[] decodedKey = Base64.decodeBase64(base64EncryptionKey.getBytes(StringUtils.UTF_8)); + byte[] decodedHMAC = Base64.decodeBase64(base64HmacKey.getBytes(StringUtils.UTF_8)); record.keyBundle = new KeyBundle(decodedKey, decodedHMAC); record.decrypt(); @@ -125,14 +126,14 @@ public class TestCryptoRecord { String user = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd"; // Check our friendly base32 decoding. - assertTrue(Arrays.equals(Utils.decodeFriendlyBase32(key), Base64.decodeBase64("8xbKrJfQYwbFkguKmlSm/g==".getBytes("UTF-8")))); + assertTrue(Arrays.equals(Utils.decodeFriendlyBase32(key), Base64.decodeBase64("8xbKrJfQYwbFkguKmlSm/g==".getBytes(StringUtils.UTF_8)))); KeyBundle bundle = new KeyBundle(user, key); String expectedEncryptKeyBase64 = "/8RzbFT396htpZu5rwgIg2WKfyARgm7dLzsF5pwrVz8="; String expectedHMACKeyBase64 = "NChGjrqoXYyw8vIYP2334cvmMtsjAMUZNqFwV2LGNkM="; byte[] computedEncryptKey = bundle.getEncryptionKey(); byte[] computedHMACKey = bundle.getHMACKey(); - assertTrue(Arrays.equals(computedEncryptKey, Base64.decodeBase64(expectedEncryptKeyBase64.getBytes("UTF-8")))); - assertTrue(Arrays.equals(computedHMACKey, Base64.decodeBase64(expectedHMACKeyBase64.getBytes("UTF-8")))); + assertTrue(Arrays.equals(computedEncryptKey, Base64.decodeBase64(expectedEncryptKeyBase64.getBytes(StringUtils.UTF_8)))); + assertTrue(Arrays.equals(computedHMACKey, Base64.decodeBase64(expectedHMACKeyBase64.getBytes(StringUtils.UTF_8)))); } @Test @@ -264,8 +265,8 @@ public class TestCryptoRecord { JSONArray keys = new ExtendedJSONObject(decrypted.payload.toJSONString()).getArray("default"); KeyBundle keyBundle = KeyBundle.fromBase64EncodedKeys((String)keys.get(0), (String)keys.get(1)); - assertArrayEquals(Base64.decodeBase64(expectedBase64EncryptionKey.getBytes("UTF-8")), keyBundle.getEncryptionKey()); - assertArrayEquals(Base64.decodeBase64(expectedBase64HmacKey.getBytes("UTF-8")), keyBundle.getHMACKey()); + assertArrayEquals(Base64.decodeBase64(expectedBase64EncryptionKey.getBytes(StringUtils.UTF_8)), keyBundle.getEncryptionKey()); + assertArrayEquals(Base64.decodeBase64(expectedBase64HmacKey.getBytes(StringUtils.UTF_8)), keyBundle.getHMACKey()); } @Test diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java b/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java index 9539403105c3..0463af2eff70 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java @@ -16,6 +16,7 @@ import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.LoginStateMachineD import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition; import org.mozilla.gecko.fxa.login.State.StateLabel; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.security.NoSuchAlgorithmException; @@ -39,10 +40,10 @@ public class TestFxAccountLoginStateMachine { @Before public void setUp() throws Exception { if (TEST_EMAIL_UTF8 == null) { - TEST_EMAIL_UTF8 = TEST_EMAIL.getBytes("UTF-8"); + TEST_EMAIL_UTF8 = TEST_EMAIL.getBytes(StringUtils.UTF_8); } if (TEST_PASSWORD_UTF8 == null) { - TEST_PASSWORD_UTF8 = TEST_PASSWORD.getBytes("UTF-8"); + TEST_PASSWORD_UTF8 = TEST_PASSWORD.getBytes(StringUtils.UTF_8); } if (TEST_QUICK_STRETCHED_PW == null) { TEST_QUICK_STRETCHED_PW = FxAccountUtils.generateQuickStretchedPW(TEST_EMAIL_UTF8, TEST_PASSWORD_UTF8); diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java index 6e76109db4bf..1d9b2d0814d8 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java @@ -10,6 +10,7 @@ import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.crypto.CryptoException; import org.mozilla.gecko.sync.crypto.CryptoInfo; import org.mozilla.gecko.sync.crypto.KeyBundle; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.UnsupportedEncodingException; @@ -24,17 +25,17 @@ import static org.junit.Assert.assertTrue; public class TestCryptoInfo { @Test - public void testEncryptedHMACIsSet() throws CryptoException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException { + public void testEncryptedHMACIsSet() throws CryptoException, InvalidKeyException, NoSuchAlgorithmException { KeyBundle kb = KeyBundle.withRandomKeys(); - CryptoInfo encrypted = CryptoInfo.encrypt("plaintext".getBytes("UTF-8"), kb); + CryptoInfo encrypted = CryptoInfo.encrypt("plaintext".getBytes(StringUtils.UTF_8), kb); assertSame(kb, encrypted.getKeys()); assertTrue(encrypted.generatedHMACIsHMAC()); } @Test - public void testRandomEncryptedDecrypted() throws CryptoException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException { + public void testRandomEncryptedDecrypted() throws CryptoException, InvalidKeyException, NoSuchAlgorithmException { KeyBundle kb = KeyBundle.withRandomKeys(); - byte[] plaintext = "plaintext".getBytes("UTF-8"); + byte[] plaintext = "plaintext".getBytes(StringUtils.UTF_8); CryptoInfo info = CryptoInfo.encrypt(plaintext, kb); byte[] iv = info.getIV(); info.decrypt(); @@ -141,4 +142,4 @@ public class TestCryptoInfo { assertArrayEquals(Base64.decodeBase64(base64CipherText), encrypted.getMessage()); assertArrayEquals(Utils.hex2Byte(base16Hmac), encrypted.getHMAC()); } -} \ No newline at end of file +} diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java index 6bb45ed8bd63..0c3f3ba12528 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java @@ -8,6 +8,7 @@ import org.junit.runner.RunWith; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.sync.crypto.CryptoException; import org.mozilla.gecko.sync.crypto.KeyBundle; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.UnsupportedEncodingException; @@ -30,8 +31,8 @@ public class TestKeyBundle { "dKj0O+b0fwI="; KeyBundle keys = new KeyBundle(username, friendlyBase32SyncKey); - assertArrayEquals(keys.getEncryptionKey(), Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8"))); - assertArrayEquals(keys.getHMACKey(), Base64.decodeBase64(base64HmacKey.getBytes("UTF-8"))); + assertArrayEquals(keys.getEncryptionKey(), Base64.decodeBase64(base64EncryptionKey.getBytes(StringUtils.UTF_8))); + assertArrayEquals(keys.getHMACKey(), Base64.decodeBase64(base64HmacKey.getBytes(StringUtils.UTF_8))); } /* diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java index eb343078ef8c..69d5a98e3397 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java @@ -32,7 +32,7 @@ public class TestHMACAuthHeaderProvider { } public static String getSignature(String requestString, String key) - throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { + throws InvalidKeyException, NoSuchAlgorithmException { return HMACAuthHeaderProvider.getSignature(requestString, key); } } diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java index 367fb80f52af..82e8320399cc 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java @@ -15,6 +15,7 @@ import ch.boye.httpclientandroidlib.protocol.BasicHttpContext; import org.junit.Test; import org.junit.runner.RunWith; import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -46,7 +47,7 @@ public class TestHawkAuthHeaderProvider { // Public for testing. public static String getSignature(String requestString, String key) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { - return HawkAuthHeaderProvider.getSignature(requestString.getBytes("UTF-8"), key.getBytes("UTF-8")); + return HawkAuthHeaderProvider.getSignature(requestString.getBytes(StringUtils.UTF_8), key.getBytes(StringUtils.UTF_8)); } // Public for testing. @@ -106,7 +107,7 @@ public class TestHawkAuthHeaderProvider { @Test public void testSpecPayloadExample() throws Exception { - LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8")); + LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes(StringUtils.UTF_8)); URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2"); HttpPost req = new HttpPost(uri); String body = "Thank you for flying Hawk"; @@ -119,7 +120,7 @@ public class TestHawkAuthHeaderProvider { @Test public void testSpecAuthorizationHeader() throws Exception { - LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8")); + LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes(StringUtils.UTF_8)); URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2"); HttpGet req = new HttpGet(uri); Header header = provider.getAuthHeader(req, null, null, 1353832234L, "j4h3g2", "some-app-ext-data", false); diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java index 8f136e3d09e2..f8d01fdb2b27 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java @@ -19,6 +19,7 @@ import org.mozilla.gecko.sync.net.BaseResourceDelegate; import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider; import org.mozilla.gecko.sync.net.Resource; import org.mozilla.gecko.sync.net.SyncResponse; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -39,7 +40,7 @@ public class TestLiveHawkAuth { public void testHawkUsage() throws Exception { // Id and credentials are hard-coded in example/usage.js. final String id = "dh37fgj492je"; - final byte[] key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8"); + final byte[] key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes(StringUtils.UTF_8); final BaseResource resource = new BaseResource("http://localhost:8000/", false); // Basic GET. diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java index a5e71834f3f6..df7e7471447e 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java @@ -18,6 +18,7 @@ import org.mozilla.gecko.sync.net.SyncStorageResponse; import org.mozilla.gecko.sync.repositories.FetchFailedException; import org.mozilla.gecko.sync.repositories.StoreFailedException; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.util.ArrayList; @@ -51,7 +52,7 @@ public class TelemetryCollectorTest { assertEquals(uid, bundle.get("uid")); // Expect device ID to be hashed with the UID. assertEquals( - Utils.byte2Hex(Utils.sha256(deviceID.concat(uid).getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256(deviceID.concat(uid).getBytes(StringUtils.UTF_8))), bundle.get("deviceID") ); } @@ -79,7 +80,7 @@ public class TelemetryCollectorTest { ArrayList devices = data.getParcelableArrayList("devices"); assertEquals(1, devices.size()); assertEquals( - Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes(StringUtils.UTF_8))), devices.get(0).getString("id") ); assertEquals("iOS", devices.get(0).getString("os")); @@ -98,14 +99,14 @@ public class TelemetryCollectorTest { assertEquals("iOS", devices.get(0).getString("os")); assertEquals("1.33.7", devices.get(0).getString("version")); assertEquals( - Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes(StringUtils.UTF_8))), devices.get(0).getString("id") ); assertEquals("Android", devices.get(1).getString("os")); assertEquals("55.0a1", devices.get(1).getString("version")); assertEquals( - Utils.byte2Hex(Utils.sha256("client2-guid".concat("hashed-uid").getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256("client2-guid".concat("hashed-uid").getBytes(StringUtils.UTF_8))), devices.get(1).getString("id") ); } @@ -346,4 +347,4 @@ public class TelemetryCollectorTest { assertEquals("othererror", error.getString("name")); assertEquals("store:IllegalStateException", error.getString("error")); } -} \ No newline at end of file +} diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java index 55bed700f3bf..fa7216a884d5 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java @@ -11,6 +11,7 @@ import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonArrayJSONException; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.UnexpectedJSONException.BadRequiredFieldJSONException; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -102,7 +103,7 @@ public class TestExtendedJSONObject { public void testParseUTF8AsJSONObject() throws Exception { String TEST = "{\"key\":\"value\"}"; - ExtendedJSONObject o = ExtendedJSONObject.parseUTF8AsJSONObject(TEST.getBytes("UTF-8")); + ExtendedJSONObject o = ExtendedJSONObject.parseUTF8AsJSONObject(TEST.getBytes(StringUtils.UTF_8)); assertNotNull(o); assertEquals("value", o.getString("key")); } @@ -117,7 +118,7 @@ public class TestExtendedJSONObject { } try { - ExtendedJSONObject.parseUTF8AsJSONObject("{".getBytes("UTF-8")); + ExtendedJSONObject.parseUTF8AsJSONObject("{".getBytes(StringUtils.UTF_8)); fail(); } catch (NonObjectJSONException e) { // Do nothing. diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java index 993e80931b2c..d25204458d21 100644 --- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java +++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java @@ -20,6 +20,7 @@ import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.URLMetadata; import org.mozilla.gecko.db.URLImageDataTable; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; @@ -195,7 +196,7 @@ public class testBrowserProvider extends ContentProviderTest { faviconEntry.put(BrowserContract.Favicons.PAGE_URL, pageUrl); faviconEntry.put(BrowserContract.Favicons.URL, pageUrl + "/favicon.ico"); - faviconEntry.put(BrowserContract.Favicons.DATA, data.getBytes("UTF8")); + faviconEntry.put(BrowserContract.Favicons.DATA, data.getBytes(StringUtils.UTF_8)); return faviconEntry; } @@ -204,7 +205,7 @@ public class testBrowserProvider extends ContentProviderTest { ContentValues thumbnailEntry = new ContentValues(); thumbnailEntry.put(BrowserContract.Thumbnails.URL, pageUrl); - thumbnailEntry.put(BrowserContract.Thumbnails.DATA, data.getBytes("UTF8")); + thumbnailEntry.put(BrowserContract.Thumbnails.DATA, data.getBytes(StringUtils.UTF_8)); return thumbnailEntry; } diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java index 2ae2bb532d08..eef8abcc3089 100644 --- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java +++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java @@ -19,6 +19,7 @@ import java.security.NoSuchAlgorithmException; import org.mozilla.gecko.background.nativecode.NativeCrypto; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.tests.helpers.GeckoHelper; +import org.mozilla.gecko.util.StringUtils; import android.os.SystemClock; @@ -238,9 +239,9 @@ public class testNativeCrypto extends UITest { } } - private void _testSHA256WithMultipleUpdatesFromStream() throws UnsupportedEncodingException { + private void _testSHA256WithMultipleUpdatesFromStream() { final String input = "HelloWorldThisIsASuperLongStringThatIsReadAsAStreamOfBytes"; - final ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes("UTF-8")); + final ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes(StringUtils.UTF_8)); final String expected = "8b5cb76b80f7eb6fb83ee138bfd31e2922e71dd245daa21a8d9876e8dee9eef5"; byte[] buffer = new byte[10]; From 60a26310904f7da6e17aeb7743ecc2cb3386d964 Mon Sep 17 00:00:00 2001 From: Richard Marti Date: Mon, 7 May 2018 21:28:46 +0200 Subject: [PATCH 19/22] Bug 1459563 - Set also on Linux a width of the page number field in print preview dialog. r=mconley --- toolkit/themes/linux/global/printPreview.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/toolkit/themes/linux/global/printPreview.css b/toolkit/themes/linux/global/printPreview.css index 5d20e35b97ed..6170c1aee79d 100644 --- a/toolkit/themes/linux/global/printPreview.css +++ b/toolkit/themes/linux/global/printPreview.css @@ -17,3 +17,8 @@ .toolbar-landscape-page { list-style-image: url("moz-icon://stock/gtk-orientation-landscape?size=button"); } + +#pageNumber { + /* 3 chars + 4px padding left + 2px padding right + 2*6px border */ + width: calc(18px + 3ch); +} From 659145e037ff944d413b8e5fdd5c6b5955895cdd Mon Sep 17 00:00:00 2001 From: Issei Horie Date: Sun, 29 Apr 2018 14:29:10 +0900 Subject: [PATCH 20/22] Bug 1438561 - Restrict histogram bucket ranges to INT_MAX. r=chutten --- .../components/telemetry/parse_histograms.py | 6 +++++ .../python/test_histogramtools_strict.py | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/toolkit/components/telemetry/parse_histograms.py b/toolkit/components/telemetry/parse_histograms.py index 567dfeb0c96f..fe3b56c58325 100755 --- a/toolkit/components/telemetry/parse_histograms.py +++ b/toolkit/components/telemetry/parse_histograms.py @@ -12,6 +12,7 @@ import sys import atexit import shared_telemetry_utils as utils +from ctypes import c_int from shared_telemetry_utils import ParserError from collections import OrderedDict atexit.register(ParserError.exit_func) @@ -487,6 +488,11 @@ associated with the histogram. Returns None if no guarding is necessary.""" ParserError('Value for key "{0}" in histogram "{1}" should be {2}.' .format(key, name, nice_type_name(key_type))).handle_later() + # Make sure the max range is lower than or equal to INT_MAX + if "high" in definition and not c_int(definition["high"]).value > 0: + ParserError('Value for high in histogram "{0}" should be lower or equal to INT_MAX.' + .format(nice_type_name(c_int))).handle_later() + for key, key_type in type_checked_list_fields.iteritems(): if key not in definition: continue diff --git a/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py b/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py index c0b99767892a..d9a3fe63b0c9 100644 --- a/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py +++ b/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py @@ -122,6 +122,29 @@ class TestParser(unittest.TestCase): parse_histograms.whitelists = None + def test_high_value(self): + SAMPLE_HISTOGRAM = { + "TEST_HISTOGRAM_WHITELIST_N_BUCKETS": { + "record_in_processes": ["main", "content"], + "alert_emails": ["team@mozilla.xyz"], + "bug_numbers": [1383793], + "expires_in_version": "never", + "kind": "exponential", + "low": 1024, + "high": 2 ** 64, + "n_buckets": 100, + "description": "Test histogram", + } + } + histograms = load_histogram(SAMPLE_HISTOGRAM) + parse_histograms.load_whitelist() + + parse_histograms.Histogram('TEST_HISTOGRAM_WHITELIST_N_BUCKETS', + histograms['TEST_HISTOGRAM_WHITELIST_N_BUCKETS'], + strict_type_checks=True) + + self.assertRaises(SystemExit, ParserError.exit_func) + def test_high_n_buckets(self): SAMPLE_HISTOGRAM = { "TEST_HISTOGRAM_WHITELIST_N_BUCKETS": { From d992429c032a017d0ebc00aa33fd07805c837263 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Mon, 7 May 2018 10:37:00 -0400 Subject: [PATCH 21/22] Bug 1459673 - Remove ANDROID_ prefix from Android event type constants in jsat. r=yzen --- accessible/jsat/Constants.jsm | 26 +++++----- accessible/jsat/Presentation.jsm | 28 +++++------ accessible/tests/mochitest/jsat/jsatcommon.js | 18 +++---- .../mochitest/jsat/test_live_regions.html | 48 +++++++++---------- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/accessible/jsat/Constants.jsm b/accessible/jsat/Constants.jsm index bf97b60a51a3..8a1591a9b81b 100644 --- a/accessible/jsat/Constants.jsm +++ b/accessible/jsat/Constants.jsm @@ -1,19 +1,19 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); const AndroidEvents = { - ANDROID_VIEW_CLICKED: 0x01, - ANDROID_VIEW_LONG_CLICKED: 0x02, - ANDROID_VIEW_SELECTED: 0x04, - ANDROID_VIEW_FOCUSED: 0x08, - ANDROID_VIEW_TEXT_CHANGED: 0x10, - ANDROID_WINDOW_STATE_CHANGED: 0x20, - ANDROID_VIEW_HOVER_ENTER: 0x80, - ANDROID_VIEW_HOVER_EXIT: 0x100, - ANDROID_VIEW_SCROLLED: 0x1000, - ANDROID_VIEW_TEXT_SELECTION_CHANGED: 0x2000, - ANDROID_ANNOUNCEMENT: 0x4000, - ANDROID_VIEW_ACCESSIBILITY_FOCUSED: 0x8000, - ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000, + VIEW_CLICKED: 0x01, + VIEW_LONG_CLICKED: 0x02, + VIEW_SELECTED: 0x04, + VIEW_FOCUSED: 0x08, + VIEW_TEXT_CHANGED: 0x10, + WINDOW_STATE_CHANGED: 0x20, + VIEW_HOVER_ENTER: 0x80, + VIEW_HOVER_EXIT: 0x100, + VIEW_SCROLLED: 0x1000, + VIEW_TEXT_SELECTION_CHANGED: 0x2000, + ANNOUNCEMENT: 0x4000, + VIEW_ACCESSIBILITY_FOCUSED: 0x8000, + VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000, }; function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) { diff --git a/accessible/jsat/Presentation.jsm b/accessible/jsat/Presentation.jsm index 2bf90f221d1e..a0cc6d1dba12 100644 --- a/accessible/jsat/Presentation.jsm +++ b/accessible/jsat/Presentation.jsm @@ -44,13 +44,13 @@ class AndroidPresentor { let isExploreByTouch = (aReason == Ci.nsIAccessiblePivot.REASON_POINT && Utils.AndroidSdkVersion >= 14); let focusEventType = (Utils.AndroidSdkVersion >= 16) ? - AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED : - AndroidEvents.ANDROID_VIEW_FOCUSED; + AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED : + AndroidEvents.VIEW_FOCUSED; if (isExploreByTouch) { // This isn't really used by TalkBack so this is a half-hearted attempt // for now. - androidEvents.push({eventType: AndroidEvents.ANDROID_VIEW_HOVER_EXIT, text: []}); + androidEvents.push({eventType: AndroidEvents.VIEW_HOVER_EXIT, text: []}); } if (aReason === Ci.nsIAccessiblePivot.REASON_TEXT) { @@ -58,7 +58,7 @@ class AndroidPresentor { let adjustedText = context.textAndAdjustedOffsets; androidEvents.push({ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, text: [adjustedText.text], fromIndex: adjustedText.startOffset, toIndex: adjustedText.endOffset @@ -67,7 +67,7 @@ class AndroidPresentor { } else { let state = Utils.getState(context.accessible); androidEvents.push({eventType: (isExploreByTouch) ? - AndroidEvents.ANDROID_VIEW_HOVER_ENTER : focusEventType, + AndroidEvents.VIEW_HOVER_ENTER : focusEventType, text: Utils.localize(UtteranceGenerator.genForContext( context)), bounds: context.bounds, @@ -105,7 +105,7 @@ class AndroidPresentor { } return [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED, + eventType: AndroidEvents.VIEW_CLICKED, text, checked: state.contains(States.CHECKED) }]; @@ -116,7 +116,7 @@ class AndroidPresentor { */ textChanged(aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) { let androidEvent = { - eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED, + eventType: AndroidEvents.VIEW_TEXT_CHANGED, text: [aText], fromIndex: aStart, removedCount: 0, @@ -144,7 +144,7 @@ class AndroidPresentor { if (Utils.AndroidSdkVersion >= 14 && !aIsFromUserInput) { androidEvents.push({ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED, + eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED, text: [aText], fromIndex: aStart, toIndex: aEnd, @@ -156,7 +156,7 @@ class AndroidPresentor { let [from, to] = aOldStart < aStart ? [aOldStart, aStart] : [aStart, aOldStart]; androidEvents.push({ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, text: [aText], fromIndex: from, toIndex: to @@ -229,7 +229,7 @@ class AndroidPresentor { } let events = [{ - eventType: AndroidEvents.ANDROID_VIEW_SCROLLED, + eventType: AndroidEvents.VIEW_SCROLLED, text: [], scrollX: aWindow.scrollX, scrollY: aWindow.scrollY, @@ -241,7 +241,7 @@ class AndroidPresentor { let currentAcc = currentContext.accessibleForBounds; if (Utils.isAliveAndVisible(currentAcc)) { events.push({ - eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED, + eventType: AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED, bounds: Utils.getBounds(currentAcc) }); } @@ -264,8 +264,8 @@ class AndroidPresentor { let localizedAnnouncement = Utils.localize(aAnnouncement).join(" "); return [{ eventType: (Utils.AndroidSdkVersion >= 16) ? - AndroidEvents.ANDROID_ANNOUNCEMENT : - AndroidEvents.ANDROID_VIEW_TEXT_CHANGED, + AndroidEvents.ANNOUNCEMENT : + AndroidEvents.VIEW_TEXT_CHANGED, text: [localizedAnnouncement], addedCount: localizedAnnouncement.length, removedCount: 0, @@ -280,7 +280,7 @@ class AndroidPresentor { */ noMove(aMoveMethod) { return [{ - eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED, + eventType: AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED, exitView: aMoveMethod, text: [""] }]; diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js index 9da2acfd155b..11fb74c14ea5 100644 --- a/accessible/tests/mochitest/jsat/jsatcommon.js +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -551,7 +551,7 @@ ExpectedPresent.prototype.ignore = function(aMessage) { let firstEvent = (aMessage.json || [])[0]; - return firstEvent && firstEvent.eventType === AndroidEvents.ANDROID_VIEW_SCROLLED; + return firstEvent && firstEvent.eventType === AndroidEvents.VIEW_SCROLLED; }; function ExpectedCursorChange(aSpeech, aOptions) { @@ -564,7 +564,7 @@ ExpectedCursorChange.prototype = Object.create(ExpectedPresent.prototype); function ExpectedCursorTextChange(aSpeech, aStartOffset, aEndOffset, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, fromIndex: aStartOffset, toIndex: aEndOffset }], aOptions); @@ -578,7 +578,7 @@ ExpectedCursorTextChange.prototype = function ExpectedClickAction(aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED + eventType: AndroidEvents.VIEW_CLICKED }], aOptions); } @@ -586,7 +586,7 @@ ExpectedClickAction.prototype = Object.create(ExpectedPresent.prototype); function ExpectedCheckAction(aChecked, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED, + eventType: AndroidEvents.VIEW_CLICKED, checked: aChecked }], aOptions); } @@ -595,7 +595,7 @@ ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype); function ExpectedSwitchAction(aSwitched, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED, + eventType: AndroidEvents.VIEW_CLICKED, checked: aSwitched }], aOptions); } @@ -619,7 +619,7 @@ ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype); // XXX: Implement Android event? function ExpectedTextChanged(aValue, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED + eventType: AndroidEvents.VIEW_TEXT_CHANGED }], aOptions); } @@ -634,7 +634,7 @@ ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype); function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED, + eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED, }], aOptions); } @@ -643,7 +643,7 @@ ExpectedTextSelectionChanged.prototype = function ExpectedTextCaretChanged(aFrom, aTo, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, fromIndex: aFrom, toIndex: aTo }], aOptions); @@ -653,7 +653,7 @@ ExpectedTextCaretChanged.prototype = Object.create(ExpectedPresent.prototype); function ExpectedAnnouncement(aAnnouncement, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_ANNOUNCEMENT, + eventType: AndroidEvents.ANNOUNCEMENT, text: [ aAnnouncement], addedCount: aAnnouncement.length }], aOptions); diff --git a/accessible/tests/mochitest/jsat/test_live_regions.html b/accessible/tests/mochitest/jsat/test_live_regions.html index 0d23786e27a0..0cffb4fb758e 100644 --- a/accessible/tests/mochitest/jsat/test_live_regions.html +++ b/accessible/tests/mochitest/jsat/test_live_regions.html @@ -57,7 +57,7 @@ var tests = [{ expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -71,7 +71,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -86,7 +86,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -100,7 +100,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -115,7 +115,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -129,7 +129,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -144,7 +144,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -158,7 +158,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -173,7 +173,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -187,7 +187,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -201,7 +201,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -215,7 +215,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -229,7 +229,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Text Added"], "addedCount": "Text Added".length, "removedCount": 0, @@ -243,7 +243,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Text Added"], "addedCount": "Text Added".length, "removedCount": 0, @@ -257,7 +257,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden Text Removed"], "addedCount": "hidden Text Removed".length, "removedCount": 0, @@ -271,7 +271,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -285,7 +285,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -299,7 +299,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden Descendant Text Removed"], "addedCount": "hidden Descendant Text Removed".length, "removedCount": 0, @@ -313,7 +313,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -327,7 +327,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -341,7 +341,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden Descendant Text Removed"], "addedCount": "hidden Descendant Text Removed".length, "removedCount": 0, @@ -355,7 +355,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I am replaced main"], "addedCount": "I am replaced main".length, "removedCount": 0, @@ -370,7 +370,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I am a replaced text"], "addedCount": "I am a replaced text".length, "removedCount": 0, @@ -384,7 +384,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I am a replaced text"], "addedCount": "I am a replaced text".length, "removedCount": 0, From fbaa7511c1968a7060afa13a5649f189b423fc7f Mon Sep 17 00:00:00 2001 From: sotaro Date: Tue, 8 May 2018 11:37:39 +0900 Subject: [PATCH 22/22] Bug 1459525 - Remove wr_shutdown_log_for_gpu_process() r=jrmuizel --- gfx/webrender_bindings/src/bindings.rs | 5 ----- gfx/webrender_bindings/webrender_ffi_generated.h | 4 ---- 2 files changed, 9 deletions(-) diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index ccac97afc0a2..7855b3d7662a 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2353,11 +2353,6 @@ extern "C" { -> bool; } -#[no_mangle] -pub extern "C" fn wr_shutdown_log_for_gpu_process() { - // log does not support shutdown -} - #[no_mangle] pub extern "C" fn wr_root_scroll_node_id() -> usize { // The PipelineId doesn't matter here, since we just want the numeric part of the id diff --git a/gfx/webrender_bindings/webrender_ffi_generated.h b/gfx/webrender_bindings/webrender_ffi_generated.h index 54c4f96472c5..33f3fe77d571 100644 --- a/gfx/webrender_bindings/webrender_ffi_generated.h +++ b/gfx/webrender_bindings/webrender_ffi_generated.h @@ -1587,10 +1587,6 @@ void wr_set_item_tag(WrState *aState, uint16_t aHitInfo) WR_FUNC; -WR_INLINE -void wr_shutdown_log_for_gpu_process() -WR_FUNC; - WR_INLINE void wr_state_delete(WrState *aState) WR_DESTRUCTOR_SAFE_FUNC;