ma1 pushed to branch tor-browser-115.24.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
-
0a4acb71
by smayya at 2025-05-22T17:18:56+02:00
-
02ee510f
by hackademix at 2025-05-22T17:34:56+02:00
-
6186c1fe
by Oskar Mansfeld at 2025-05-26T17:25:28+02:00
-
dc06e11d
by Daniel Holbert at 2025-05-26T17:25:48+02:00
-
4f3e5d70
by Daniel Holbert at 2025-05-26T17:25:49+02:00
-
d5a152e4
by Daniel Holbert at 2025-05-26T17:25:50+02:00
-
73753ce8
by Jonathan Kew at 2025-05-26T17:25:50+02:00
-
d3e4fff1
by Gijs Kruitbosch at 2025-05-26T17:25:51+02:00
16 changed files:
- browser/app/profile/001-base-profile.js
- dom/svg/DOMSVGLength.cpp
- dom/svg/DOMSVGLength.h
- dom/svg/DOMSVGPoint.cpp
- dom/svg/DOMSVGPoint.h
- dom/svg/DOMSVGPointList.cpp
- dom/svg/DOMSVGPointList.h
- dom/svg/DOMSVGStringList.cpp
- dom/svg/DOMSVGStringList.h
- gfx/thebes/gfxFont.cpp
- modules/libpref/init/StaticPrefList.yaml
- netwerk/base/nsIOService.cpp
- netwerk/base/nsSocketTransport2.cpp
- netwerk/protocol/http/HttpConnectionUDP.cpp
- netwerk/test/unit/trr_common.js
- toolkit/components/aboutmemory/content/aboutMemory.js
Changes:
| ... | ... | @@ -482,6 +482,11 @@ pref("network.http.http2.default-hpack-buffer", 65536, locked); |
| 482 | 482 | pref("network.http.http2.websockets", true, locked);
|
| 483 | 483 | pref("network.http.http2.enable-hpack-dump", false, locked);
|
| 484 | 484 | |
| 485 | +// Block 0.0.0.0
|
|
| 486 | +// https://bugzilla.mozilla.org/show_bug.cgi?id=1889130
|
|
| 487 | +// tor-browser#43811
|
|
| 488 | +pref("network.socket.ip_addr_any.disabled", true);
|
|
| 489 | + |
|
| 485 | 490 | // tor-browser#23044: Make sure we don't have any GIO supported protocols
|
| 486 | 491 | // (defense in depth measure)
|
| 487 | 492 | pref("network.gio.supported-protocols", "");
|
| ... | ... | @@ -51,6 +51,7 @@ DOMSVGLength::DOMSVGLength(DOMSVGLengthList* aList, uint8_t aAttrEnum, |
| 51 | 51 | mListIndex(aListIndex),
|
| 52 | 52 | mAttrEnum(aAttrEnum),
|
| 53 | 53 | mIsAnimValItem(aIsAnimValItem),
|
| 54 | + mIsInTearoffTable(false),
|
|
| 54 | 55 | mUnit(SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {
|
| 55 | 56 | MOZ_ASSERT(aList, "bad arg");
|
| 56 | 57 | MOZ_ASSERT(mAttrEnum == aAttrEnum, "bitfield too small");
|
| ... | ... | @@ -63,6 +64,7 @@ DOMSVGLength::DOMSVGLength() |
| 63 | 64 | mListIndex(0),
|
| 64 | 65 | mAttrEnum(0),
|
| 65 | 66 | mIsAnimValItem(false),
|
| 67 | + mIsInTearoffTable(false),
|
|
| 66 | 68 | mUnit(SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {}
|
| 67 | 69 | |
| 68 | 70 | DOMSVGLength::DOMSVGLength(SVGAnimatedLength* aVal, SVGElement* aSVGElement,
|
| ... | ... | @@ -71,6 +73,7 @@ DOMSVGLength::DOMSVGLength(SVGAnimatedLength* aVal, SVGElement* aSVGElement, |
| 71 | 73 | mListIndex(0),
|
| 72 | 74 | mAttrEnum(aVal->mAttrEnum),
|
| 73 | 75 | mIsAnimValItem(aAnimVal),
|
| 76 | + mIsInTearoffTable(false),
|
|
| 74 | 77 | mUnit(SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {
|
| 75 | 78 | MOZ_ASSERT(aVal, "bad arg");
|
| 76 | 79 | MOZ_ASSERT(mAttrEnum == aVal->mAttrEnum, "bitfield too small");
|
| ... | ... | @@ -88,22 +91,33 @@ void DOMSVGLength::CleanupWeakRefs() { |
| 88 | 91 | |
| 89 | 92 | // Similarly, we must update the tearoff table to remove its (non-owning)
|
| 90 | 93 | // pointer to mVal.
|
| 91 | - if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
|
|
| 92 | - auto& table = mIsAnimValItem ? sAnimSVGLengthTearOffTable
|
|
| 93 | - : sBaseSVGLengthTearOffTable;
|
|
| 94 | - table.RemoveTearoff(svg->GetAnimatedLength(mAttrEnum));
|
|
| 94 | + if (mIsInTearoffTable) {
|
|
| 95 | + nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner);
|
|
| 96 | + MOZ_ASSERT(svg,
|
|
| 97 | + "We need our svgElement reference in order to remove "
|
|
| 98 | + "ourselves from tearoff table...");
|
|
| 99 | + if (MOZ_LIKELY(svg)) {
|
|
| 100 | + auto& table = mIsAnimValItem ? sAnimSVGLengthTearOffTable
|
|
| 101 | + : sBaseSVGLengthTearOffTable;
|
|
| 102 | + table.RemoveTearoff(svg->GetAnimatedLength(mAttrEnum));
|
|
| 103 | + mIsInTearoffTable = false;
|
|
| 104 | + }
|
|
| 95 | 105 | }
|
| 96 | 106 | }
|
| 97 | 107 | |
| 98 | 108 | already_AddRefed<DOMSVGLength> DOMSVGLength::GetTearOff(SVGAnimatedLength* aVal,
|
| 99 | 109 | SVGElement* aSVGElement,
|
| 100 | 110 | bool aAnimVal) {
|
| 111 | + MOZ_ASSERT(aVal && aSVGElement, "Expecting non-null aVal and aSVGElement");
|
|
| 112 | + MOZ_ASSERT(aVal == aSVGElement->GetAnimatedLength(aVal->mAttrEnum),
|
|
| 113 | + "Mismatched aVal/SVGElement?");
|
|
| 101 | 114 | auto& table =
|
| 102 | 115 | aAnimVal ? sAnimSVGLengthTearOffTable : sBaseSVGLengthTearOffTable;
|
| 103 | 116 | RefPtr<DOMSVGLength> domLength = table.GetTearoff(aVal);
|
| 104 | 117 | if (!domLength) {
|
| 105 | 118 | domLength = new DOMSVGLength(aVal, aSVGElement, aAnimVal);
|
| 106 | 119 | table.AddTearoff(aVal, domLength);
|
| 120 | + domLength->mIsInTearoffTable = true;
|
|
| 107 | 121 | }
|
| 108 | 122 | |
| 109 | 123 | return domLength.forget();
|
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | #include "mozilla/Attributes.h"
|
| 16 | 16 | #include "nsWrapperCache.h"
|
| 17 | 17 | |
| 18 | -#define MOZ_SVG_LIST_INDEX_BIT_COUNT 22 // supports > 4 million list items
|
|
| 18 | +#define MOZ_SVG_LIST_INDEX_BIT_COUNT 21 // supports > 2 million list items
|
|
| 19 | 19 | |
| 20 | 20 | namespace mozilla {
|
| 21 | 21 | |
| ... | ... | @@ -198,6 +198,13 @@ class DOMSVGLength final : public nsWrapperCache { |
| 198 | 198 | uint32_t mAttrEnum : 4; // supports up to 16 attributes
|
| 199 | 199 | uint32_t mIsAnimValItem : 1;
|
| 200 | 200 | |
| 201 | + // Tracks whether we're in the tearoff table. Initialized to false in the
|
|
| 202 | + // ctor, but then immediately set to true after we're added to the table
|
|
| 203 | + // (unless we're an instance created via 'Copy()'; those never get added to
|
|
| 204 | + // the table). Updated to false when we're removed from the table (at which
|
|
| 205 | + // point we're being destructed or soon-to-be destructed).
|
|
| 206 | + uint32_t mIsInTearoffTable : 1;
|
|
| 207 | + |
|
| 201 | 208 | // The following members are only used when we're not in a list:
|
| 202 | 209 | uint32_t mUnit : 5; // can handle 31 units (the 10 SVG 1.1 units + rem, vw,
|
| 203 | 210 | // vh, wm, calc + future additions)
|
| ... | ... | @@ -168,6 +168,7 @@ already_AddRefed<DOMSVGPoint> DOMSVGPoint::GetTranslateTearOff( |
| 168 | 168 | if (!domPoint) {
|
| 169 | 169 | domPoint = new DOMSVGPoint(aVal, aSVGSVGElement);
|
| 170 | 170 | sSVGTranslateTearOffTable.AddTearoff(aVal, domPoint);
|
| 171 | + domPoint->mIsInTearoffTable = true;
|
|
| 171 | 172 | }
|
| 172 | 173 | |
| 173 | 174 | return domPoint.forget();
|
| ... | ... | @@ -204,12 +205,18 @@ void DOMSVGPoint::CleanupWeakRefs() { |
| 204 | 205 | pointList->mItems[mListIndex] = nullptr;
|
| 205 | 206 | }
|
| 206 | 207 | |
| 208 | + if (mIsInTearoffTable) {
|
|
| 209 | + // Similarly, we must update the tearoff table to remove its (non-owning)
|
|
| 210 | + // pointer to mVal.
|
|
| 211 | + MOZ_ASSERT(mVal && mIsTranslatePoint,
|
|
| 212 | + "Tearoff table should only be used for translate-point objects "
|
|
| 213 | + "with non-null mVal (see GetTranslateTearOff and its callers)");
|
|
| 214 | + sSVGTranslateTearOffTable.RemoveTearoff(mVal);
|
|
| 215 | + mIsInTearoffTable = false;
|
|
| 216 | + }
|
|
| 217 | + |
|
| 207 | 218 | if (mVal) {
|
| 208 | - if (mIsTranslatePoint) {
|
|
| 209 | - // Similarly, we must update the tearoff table to remove its (non-owning)
|
|
| 210 | - // pointer to mVal.
|
|
| 211 | - sSVGTranslateTearOffTable.RemoveTearoff(mVal);
|
|
| 212 | - } else {
|
|
| 219 | + if (!mIsTranslatePoint) {
|
|
| 213 | 220 | // In this case we own mVal
|
| 214 | 221 | delete mVal;
|
| 215 | 222 | }
|
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | #include "mozilla/dom/SVGSVGElement.h"
|
| 18 | 18 | #include "mozilla/gfx/2D.h"
|
| 19 | 19 | |
| 20 | -#define MOZ_SVG_LIST_INDEX_BIT_COUNT 30
|
|
| 20 | +#define MOZ_SVG_LIST_INDEX_BIT_COUNT 29
|
|
| 21 | 21 | |
| 22 | 22 | namespace mozilla::dom {
|
| 23 | 23 | struct DOMMatrix2DInit;
|
| ... | ... | @@ -51,7 +51,8 @@ class DOMSVGPoint final : public nsWrapperCache { |
| 51 | 51 | mOwner(aList),
|
| 52 | 52 | mListIndex(aListIndex),
|
| 53 | 53 | mIsAnimValItem(aIsAnimValItem),
|
| 54 | - mIsTranslatePoint(false) {
|
|
| 54 | + mIsTranslatePoint(false),
|
|
| 55 | + mIsInTearoffTable(false) {
|
|
| 55 | 56 | // These shifts are in sync with the members.
|
| 56 | 57 | MOZ_ASSERT(aList && aListIndex <= MaxListIndex(), "bad arg");
|
| 57 | 58 | |
| ... | ... | @@ -60,7 +61,10 @@ class DOMSVGPoint final : public nsWrapperCache { |
| 60 | 61 | |
| 61 | 62 | // Constructor for unowned points and SVGSVGElement.createSVGPoint
|
| 62 | 63 | explicit DOMSVGPoint(const Point& aPt)
|
| 63 | - : mListIndex(0), mIsAnimValItem(false), mIsTranslatePoint(false) {
|
|
| 64 | + : mListIndex(0),
|
|
| 65 | + mIsAnimValItem(false),
|
|
| 66 | + mIsTranslatePoint(false),
|
|
| 67 | + mIsInTearoffTable(false) {
|
|
| 64 | 68 | // In this case we own mVal
|
| 65 | 69 | mVal = new SVGPoint(aPt.x, aPt.y);
|
| 66 | 70 | }
|
| ... | ... | @@ -72,7 +76,8 @@ class DOMSVGPoint final : public nsWrapperCache { |
| 72 | 76 | mOwner(ToSupports(aSVGSVGElement)),
|
| 73 | 77 | mListIndex(0),
|
| 74 | 78 | mIsAnimValItem(false),
|
| 75 | - mIsTranslatePoint(true) {}
|
|
| 79 | + mIsTranslatePoint(true),
|
|
| 80 | + mIsInTearoffTable(false) {}
|
|
| 76 | 81 | |
| 77 | 82 | virtual ~DOMSVGPoint() { CleanupWeakRefs(); }
|
| 78 | 83 | |
| ... | ... | @@ -178,6 +183,12 @@ class DOMSVGPoint final : public nsWrapperCache { |
| 178 | 183 | uint32_t mListIndex : MOZ_SVG_LIST_INDEX_BIT_COUNT;
|
| 179 | 184 | uint32_t mIsAnimValItem : 1; // True if We're the animated value of a list
|
| 180 | 185 | uint32_t mIsTranslatePoint : 1; // true iff our owner is a SVGSVGElement
|
| 186 | + |
|
| 187 | + // Tracks whether we're in the tearoff table. Initialized to false in the
|
|
| 188 | + // ctor, but then immediately set to true if/when we're added to the table
|
|
| 189 | + // (not all instances are). Updated to false when we're removed from the
|
|
| 190 | + // table (at which point we're being destructed or soon-to-be destructed).
|
|
| 191 | + uint32_t mIsInTearoffTable : 1;
|
|
| 181 | 192 | };
|
| 182 | 193 | |
| 183 | 194 | } // namespace mozilla::dom
|
| ... | ... | @@ -88,9 +88,12 @@ void DOMSVGPointList::RemoveFromTearoffTable() { |
| 88 | 88 | //
|
| 89 | 89 | // There are now no longer any references to us held by script or list items.
|
| 90 | 90 | // Note we must use GetAnimValKey/GetBaseValKey here, NOT InternalList()!
|
| 91 | - void* key = mIsAnimValList ? InternalAList().GetAnimValKey()
|
|
| 92 | - : InternalAList().GetBaseValKey();
|
|
| 93 | - SVGPointListTearoffTable().RemoveTearoff(key);
|
|
| 91 | + if (mIsInTearoffTable) {
|
|
| 92 | + void* key = mIsAnimValList ? InternalAList().GetAnimValKey()
|
|
| 93 | + : InternalAList().GetBaseValKey();
|
|
| 94 | + SVGPointListTearoffTable().RemoveTearoff(key);
|
|
| 95 | + mIsInTearoffTable = false;
|
|
| 96 | + }
|
|
| 94 | 97 | }
|
| 95 | 98 | |
| 96 | 99 | DOMSVGPointList::~DOMSVGPointList() { RemoveFromTearoffTable(); }
|
| ... | ... | @@ -250,6 +250,12 @@ class DOMSVGPointList final : public nsISupports, public nsWrapperCache { |
| 250 | 250 | RefPtr<dom::SVGElement> mElement;
|
| 251 | 251 | |
| 252 | 252 | bool mIsAnimValList;
|
| 253 | + |
|
| 254 | + // Tracks whether we're in the tearoff table. Initialized to true, since all
|
|
| 255 | + // new instances are added to the table right after construction. Updated to
|
|
| 256 | + // false when we're removed from the table (at which point we're being
|
|
| 257 | + // destructed or soon-to-be destructed).
|
|
| 258 | + bool mIsInTearoffTable = true;
|
|
| 253 | 259 | };
|
| 254 | 260 | |
| 255 | 261 | NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGPointList, MOZILLA_DOMSVGPOINTLIST_IID)
|
| ... | ... | @@ -91,7 +91,10 @@ already_AddRefed<DOMSVGStringList> DOMSVGStringList::GetDOMWrapper( |
| 91 | 91 | |
| 92 | 92 | void DOMSVGStringList::RemoveFromTearoffTable() {
|
| 93 | 93 | // Script no longer has any references to us.
|
| 94 | - SVGStringListTearoffTable().RemoveTearoff(&InternalList());
|
|
| 94 | + if (mIsInTearoffTable) {
|
|
| 95 | + SVGStringListTearoffTable().RemoveTearoff(&InternalList());
|
|
| 96 | + mIsInTearoffTable = false;
|
|
| 97 | + }
|
|
| 95 | 98 | }
|
| 96 | 99 | |
| 97 | 100 | DOMSVGStringList::~DOMSVGStringList() { RemoveFromTearoffTable(); }
|
| ... | ... | @@ -108,6 +108,12 @@ class DOMSVGStringList final : public nsISupports, public nsWrapperCache { |
| 108 | 108 | uint8_t mAttrEnum;
|
| 109 | 109 | |
| 110 | 110 | bool mIsConditionalProcessingAttribute;
|
| 111 | + |
|
| 112 | + // Tracks whether we're in the tearoff table. Initialized to true, since all
|
|
| 113 | + // new instances are added to the table right after construction. Updated to
|
|
| 114 | + // false when we're removed from the table (at which point we're being
|
|
| 115 | + // destructed or soon-to-be destructed).
|
|
| 116 | + bool mIsInTearoffTable = true;
|
|
| 111 | 117 | };
|
| 112 | 118 | |
| 113 | 119 | } // namespace dom
|
| ... | ... | @@ -1293,8 +1293,12 @@ static const hb_tag_t defaultFeatures[] = { |
| 1293 | 1293 | void gfxFont::CheckForFeaturesInvolvingSpace() const {
|
| 1294 | 1294 | gfxFontEntry::SpaceFeatures flags = gfxFontEntry::SpaceFeatures::None;
|
| 1295 | 1295 | |
| 1296 | + // mFontEntry->mHasSpaceFeatures is a std::atomic<>, so we set it with
|
|
| 1297 | + // `exchange` to avoid a potential data race. It's ok if two threads both
|
|
| 1298 | + // try to set it; they'll end up with the same value, so it doesn't matter
|
|
| 1299 | + // that one will overwrite the other.
|
|
| 1296 | 1300 | auto setFlags =
|
| 1297 | - MakeScopeExit([&]() { mFontEntry->mHasSpaceFeatures = flags; });
|
|
| 1301 | + MakeScopeExit([&]() { mFontEntry->mHasSpaceFeatures.exchange(flags); });
|
|
| 1298 | 1302 | |
| 1299 | 1303 | bool log = LOG_FONTINIT_ENABLED();
|
| 1300 | 1304 | TimeStamp start;
|
| ... | ... | @@ -11735,6 +11735,13 @@ |
| 11735 | 11735 | value: true
|
| 11736 | 11736 | mirror: always
|
| 11737 | 11737 | |
| 11738 | +# Disable requests to 0.0.0.0
|
|
| 11739 | +# See Bug 1889130
|
|
| 11740 | +- name: network.socket.ip_addr_any.disabled
|
|
| 11741 | + type: RelaxedAtomicBool
|
|
| 11742 | + value: @IS_EARLY_BETA_OR_EARLIER@
|
|
| 11743 | + mirror: always
|
|
| 11744 | + |
|
| 11738 | 11745 | # Set true to allow resolving proxy for localhost
|
| 11739 | 11746 | - name: network.proxy.allow_hijacking_localhost
|
| 11740 | 11747 | type: RelaxedAtomicBool
|
| ... | ... | @@ -230,6 +230,7 @@ static const char* gCallbackPrefsForSocketProcess[] = { |
| 230 | 230 | "network.proxy.allow_hijacking_localhost",
|
| 231 | 231 | "network.connectivity-service.",
|
| 232 | 232 | "network.captive-portal-service.testMode",
|
| 233 | + "network.socket.ip_addr_any.disabled",
|
|
| 233 | 234 | nullptr,
|
| 234 | 235 | };
|
| 235 | 236 |
| ... | ... | @@ -1245,6 +1245,15 @@ nsresult nsSocketTransport::InitiateSocket() { |
| 1245 | 1245 | if (gIOService->IsNetTearingDown()) {
|
| 1246 | 1246 | return NS_ERROR_ABORT;
|
| 1247 | 1247 | }
|
| 1248 | + |
|
| 1249 | + // Since https://github.com/whatwg/fetch/pull/1763,
|
|
| 1250 | + // we need to disable access to 0.0.0.0 for non-test purposes
|
|
| 1251 | + if (StaticPrefs::network_socket_ip_addr_any_disabled() &&
|
|
| 1252 | + mNetAddr.IsIPAddrAny() && !mProxyTransparentResolvesHost) {
|
|
| 1253 | + SOCKET_LOG(("connection refused NS_ERROR_CONNECTION_REFUSED\n"));
|
|
| 1254 | + return NS_ERROR_CONNECTION_REFUSED;
|
|
| 1255 | + }
|
|
| 1256 | + |
|
| 1248 | 1257 | if (gIOService->IsOffline()) {
|
| 1249 | 1258 | if (StaticPrefs::network_disable_localhost_when_offline() || !isLocal) {
|
| 1250 | 1259 | return NS_ERROR_OFFLINE;
|
| ... | ... | @@ -86,6 +86,15 @@ nsresult HttpConnectionUDP::Init(nsHttpConnectionInfo* info, |
| 86 | 86 | return rv;
|
| 87 | 87 | }
|
| 88 | 88 | |
| 89 | + // We are disabling 0.0.0.0 for non-test purposes.
|
|
| 90 | + // See https://github.com/whatwg/fetch/pull/1763 for context.
|
|
| 91 | + if (peerAddr.IsIPAddrAny()) {
|
|
| 92 | + if (StaticPrefs::network_socket_ip_addr_any_disabled()) {
|
|
| 93 | + LOG(("Connection refused because of 0.0.0.0 IP address\n"));
|
|
| 94 | + return NS_ERROR_CONNECTION_REFUSED;
|
|
| 95 | + }
|
|
| 96 | + }
|
|
| 97 | + |
|
| 89 | 98 | mSocket = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
|
| 90 | 99 | if (NS_FAILED(rv)) {
|
| 91 | 100 | return rv;
|
| ... | ... | @@ -1025,6 +1025,7 @@ async function test_ipv4_trr_fallback() { |
| 1025 | 1025 | async function test_no_retry_without_doh() {
|
| 1026 | 1026 | info("Bug 1648147 - if the TRR returns 0.0.0.0 we should not retry with DNS");
|
| 1027 | 1027 | Services.prefs.setBoolPref("network.trr.fallback-on-zero-response", false);
|
| 1028 | + Services.prefs.setBoolPref("network.socket.ip_addr_any.disabled", false);
|
|
| 1028 | 1029 | |
| 1029 | 1030 | async function test(url, ip) {
|
| 1030 | 1031 | setModeAndURI(2, `doh?responseIP=${ip}`);
|
| ... | ... | @@ -1071,6 +1072,8 @@ async function test_no_retry_without_doh() { |
| 1071 | 1072 | await test(`http://unknown.ipv4.stuff:666/path`, "0.0.0.0");
|
| 1072 | 1073 | await test(`http://unknown.ipv6.stuff:666/path`, "::");
|
| 1073 | 1074 | }
|
| 1075 | + |
|
| 1076 | + Services.prefs.clearUserPref("network.socket.ip_addr_any.disabled");
|
|
| 1074 | 1077 | }
|
| 1075 | 1078 | |
| 1076 | 1079 | async function test_connection_reuse_and_cycling() {
|
| ... | ... | @@ -506,19 +506,11 @@ window.onload = function () { |
| 506 | 506 | appendElementWithText(gFooter, "div", "legend", legendText1);
|
| 507 | 507 | appendElementWithText(gFooter, "div", "legend hiddenOnMobile", legendText2);
|
| 508 | 508 | |
| 509 | - // See if we're loading from a file. (Because about:memory is a non-standard
|
|
| 510 | - // URL, location.search is undefined, so we have to use location.href
|
|
| 511 | - // instead.)
|
|
| 512 | - let search = location.href.split("?")[1];
|
|
| 513 | - if (search) {
|
|
| 514 | - let searchSplit = search.split("&");
|
|
| 515 | - for (let s of searchSplit) {
|
|
| 516 | - if (s.toLowerCase().startsWith("file=")) {
|
|
| 517 | - let filename = s.substring("file=".length);
|
|
| 518 | - updateAboutMemoryFromFile(decodeURIComponent(filename));
|
|
| 519 | - return;
|
|
| 520 | - }
|
|
| 521 | - }
|
|
| 509 | + // See if we're loading from a file.
|
|
| 510 | + let { searchParams } = URL.fromURI(document.documentURIObject);
|
|
| 511 | + let fileParam = searchParams.get("file");
|
|
| 512 | + if (fileParam) {
|
|
| 513 | + updateAboutMemoryFromFile(fileParam);
|
|
| 522 | 514 | }
|
| 523 | 515 | };
|
| 524 | 516 |