Diff
Modified: trunk/LayoutTests/ChangeLog (252613 => 252614)
--- trunk/LayoutTests/ChangeLog 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/LayoutTests/ChangeLog 2019-11-19 01:30:51 UTC (rev 252614)
@@ -1,3 +1,13 @@
+2019-11-18 Devin Rousso <[email protected]>
+
+ Web Inspector: Local Resource Overrides: allow substitution based on a url pattern
+ https://bugs.webkit.org/show_bug.cgi?id=202375
+
+ Reviewed by Brian Burg.
+
+ * http/tests/inspector/network/local-resource-override-basic.html:
+ * http/tests/inspector/network/local-resource-override-basic-expected.txt:
+
2019-11-18 Megan Gardner <[email protected]>
Update dismiss-picker-using-keyboard.html test to work on iPad correctly
Modified: trunk/LayoutTests/http/tests/inspector/network/local-resource-override-basic-expected.txt (252613 => 252614)
--- trunk/LayoutTests/http/tests/inspector/network/local-resource-override-basic-expected.txt 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/LayoutTests/http/tests/inspector/network/local-resource-override-basic-expected.txt 2019-11-19 01:30:51 UTC (rev 252614)
@@ -88,6 +88,45 @@
X-Expected: PASS
Content: PASS
+-- Running test case: LocalResourceOverride.URL.CaseSensitive
+Creating Local Resource Override for: http://127.0.0.1:8000/inspector/network/resources/override.txt?case=sensitive
+Triggering load...
+Resource Loaded:
+URL: http://127.0.0.1:8000/inspector/network/resources/override.txt?CaSe=SeNsItIvE
+MIME Type: text/plain
+Status: 200 OK
+Response Source: Symbol(inspector-override)
+Response Headers:
+ Content-Type: text/plain
+ X-Expected: PASS
+Content: PASS
+
+-- Running test case: LocalResourceOverride.URL.IsRegex
+Creating Local Resource Override for: \/override\.txt\?t=\d+
+Triggering load...
+Resource Loaded:
+URL: http://127.0.0.1:8000/inspector/network/resources/override.txt?t=123456789
+MIME Type: text/plain
+Status: 200 OK
+Response Source: Symbol(inspector-override)
+Response Headers:
+ Content-Type: text/plain
+ X-Expected: PASS
+Content: PASS
+
+-- Running test case: LocalResourceOverride.URL.IsCaseSensitiveRegex
+Creating Local Resource Override for: \/OvErRiDe\.TxT\?t=\d+
+Triggering load...
+Resource Loaded:
+URL: http://127.0.0.1:8000/inspector/network/resources/override.txt?t=123456789
+MIME Type: text/plain
+Status: 200 OK
+Response Source: Symbol(inspector-override)
+Response Headers:
+ Content-Type: text/plain
+ X-Expected: PASS
+Content: PASS
+
-- Running test case: LocalResourceOverride.404
Creating Local Resource Override for: http://127.0.0.1:8000/inspector/network/resources/override.txt
Triggering load...
Modified: trunk/LayoutTests/http/tests/inspector/network/local-resource-override-basic.html (252613 => 252614)
--- trunk/LayoutTests/http/tests/inspector/network/local-resource-override-basic.html 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/LayoutTests/http/tests/inspector/network/local-resource-override-basic.html 2019-11-19 01:30:51 UTC (rev 252614)
@@ -165,6 +165,55 @@
});
addTestCase({
+ name: "LocalResourceOverride.URL.CaseSensitive",
+ description: "Test override for a load with a fragment.",
+ _expression_: `triggerOverrideLoad("?CaSe=SeNsItIvE")`,
+ overrides: [{
+ url: "http://127.0.0.1:8000/inspector/network/resources/override.txt?case=sensitive",
+ mimeType: "text/plain",
+ content: "PASS",
+ base64Encoded: false,
+ statusCode: 200,
+ statusText: "OK",
+ headers: {"X-Expected": "PASS"},
+ isCaseSensitive: false,
+ }]
+ });
+
+ addTestCase({
+ name: "LocalResourceOverride.URL.IsRegex",
+ description: "Test override for a load with a fragment.",
+ _expression_: `triggerOverrideLoad("?t=123456789")`,
+ overrides: [{
+ url: "\\/override\\.txt\\?t=\\d+",
+ mimeType: "text/plain",
+ content: "PASS",
+ base64Encoded: false,
+ statusCode: 200,
+ statusText: "OK",
+ headers: {"X-Expected": "PASS"},
+ isRegex: true,
+ }]
+ });
+
+ addTestCase({
+ name: "LocalResourceOverride.URL.IsCaseSensitiveRegex",
+ description: "Test override for a load with a fragment.",
+ _expression_: `triggerOverrideLoad("?t=123456789")`,
+ overrides: [{
+ url: "\\/OvErRiDe\\.TxT\\?t=\\d+",
+ mimeType: "text/plain",
+ content: "PASS",
+ base64Encoded: false,
+ statusCode: 200,
+ statusText: "OK",
+ headers: {"X-Expected": "PASS"},
+ isCaseSensitive: false,
+ isRegex: true,
+ }]
+ });
+
+ addTestCase({
name: "LocalResourceOverride.404",
description: "Test for a 404 override.",
_expression_: `triggerOverrideLoad()`,
Modified: trunk/Source/_javascript_Core/ChangeLog (252613 => 252614)
--- trunk/Source/_javascript_Core/ChangeLog 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-11-19 01:30:51 UTC (rev 252614)
@@ -1,3 +1,23 @@
+2019-11-18 Devin Rousso <[email protected]>
+
+ Web Inspector: Local Resource Overrides: allow substitution based on a url pattern
+ https://bugs.webkit.org/show_bug.cgi?id=202375
+
+ Reviewed by Brian Burg.
+
+ Often, websites will load content with a timestamp-based URL query parameter for
+ cache-busting or logging purposes. If a developer is trying to override these resources (or
+ is trying to have an existing override also match these resources), they'd need to edit the
+ local override's URL to match in addition to editing the resource that loads it (e.g. change
+ the <script> in an HTML file), which can sometimes be tricky of the content is dynamically
+ loaded (e.g. an XHR with a non-hardcoded URL).
+
+ Allowing for local overrides to be set using a regular _expression_ pattern would help resolve
+ this limitation.
+
+ * inspector/protocol/Network.json:
+ Add `isRegex` parameter to `Network.addInterception` and `Network.removeInterception`.
+
2019-11-18 Keith Rollin <[email protected]>
Move jsc from Resources to Helpers
Modified: trunk/Source/_javascript_Core/inspector/protocol/Network.json (252613 => 252614)
--- trunk/Source/_javascript_Core/inspector/protocol/Network.json 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/_javascript_Core/inspector/protocol/Network.json 2019-11-19 01:30:51 UTC (rev 252614)
@@ -239,6 +239,8 @@
"description": "Add an interception.",
"parameters": [
{ "name": "url", "type": "string" },
+ { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If false, ignores letter casing of `url` parameter." },
+ { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats `url` parameter as a regular _expression_." },
{ "name": "stage", "$ref": "NetworkStage", "optional": true, "description": "If not present this applies to all network stages." }
]
},
@@ -247,6 +249,8 @@
"description": "Remove an interception.",
"parameters": [
{ "name": "url", "type": "string" },
+ { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If false, ignores letter casing of `url` parameter." },
+ { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats `url` parameter as a regular _expression_." },
{ "name": "stage", "$ref": "NetworkStage", "optional": true, "description": "If not present this applies to all network stages." }
]
},
Modified: trunk/Source/WebCore/ChangeLog (252613 => 252614)
--- trunk/Source/WebCore/ChangeLog 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebCore/ChangeLog 2019-11-19 01:30:51 UTC (rev 252614)
@@ -1,3 +1,33 @@
+2019-11-18 Devin Rousso <[email protected]>
+
+ Web Inspector: Local Resource Overrides: allow substitution based on a url pattern
+ https://bugs.webkit.org/show_bug.cgi?id=202375
+
+ Reviewed by Brian Burg.
+
+ Test: http/tests/inspector/network/local-resource-override-isRegex.html
+
+ Often, websites will load content with a timestamp-based URL query parameter for
+ cache-busting or logging purposes. If a developer is trying to override these resources (or
+ is trying to have an existing override also match these resources), they'd need to edit the
+ local override's URL to match in addition to editing the resource that loads it (e.g. change
+ the <script> in an HTML file), which can sometimes be tricky of the content is dynamically
+ loaded (e.g. an XHR with a non-hardcoded URL).
+
+ Allowing for local overrides to be set using a regular _expression_ pattern would help resolve
+ this limitation.
+
+ * inspector/agents/InspectorNetworkAgent.h:
+ (WebCore::InspectorNetworkAgent::Intercept): Added.
+ (WebCore::InspectorNetworkAgent::Intercept::operator== const): Added.
+ * inspector/agents/InspectorNetworkAgent.cpp:
+ (WebCore::InspectorNetworkAgent::disable):
+ (WebCore::InspectorNetworkAgent::shouldIntercept): Added.
+ (WebCore::InspectorNetworkAgent::addInterception):
+ (WebCore::InspectorNetworkAgent::removeInterception):
+ (WebCore::InspectorNetworkAgent::willInterceptRequest):
+ (WebCore::InspectorNetworkAgent::shouldInterceptResponse):
+
2019-11-18 Andres Gonzalez <[email protected]>
Run AccessibilityController::rootElement on secondary thread to simulate HIServices during LayoutTests.
Modified: trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp (252613 => 252614)
--- trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp 2019-11-19 01:30:51 UTC (rev 252614)
@@ -80,6 +80,8 @@
#include <_javascript_Core/JSCInlines.h>
#include <_javascript_Core/ScriptCallStack.h>
#include <_javascript_Core/ScriptCallStackFactory.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
#include <wtf/JSONValues.h>
#include <wtf/Lock.h>
#include <wtf/RefPtr.h>
@@ -87,6 +89,7 @@
#include <wtf/persistence/PersistentEncoder.h>
#include <wtf/text/Base64.h>
#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
typedef Inspector::NetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback;
@@ -830,7 +833,7 @@
{
m_enabled = false;
m_interceptionEnabled = false;
- m_interceptResponseURLs.clear();
+ m_intercepts.clear();
m_instrumentingAgents.setInspectorNetworkAgent(nullptr);
m_resourcesData->clear();
m_extraRequestHeaders.clear();
@@ -840,6 +843,23 @@
setResourceCachingDisabled(false);
}
+bool InspectorNetworkAgent::shouldIntercept(URL url)
+{
+ url.removeFragmentIdentifier();
+
+ String urlString = url.string();
+ if (urlString.isEmpty())
+ return false;
+
+ for (auto& intercept : m_intercepts) {
+ auto regex = ContentSearchUtilities::createSearchRegex(intercept.url, intercept.caseSensitive, intercept.isRegex);
+ if (regex.match(urlString) != -1)
+ return true;
+ }
+
+ return false;
+}
+
void InspectorNetworkAgent::continuePendingResponses()
{
for (auto& pendingInterceptResponse : m_pendingInterceptResponses.values())
@@ -1009,7 +1029,7 @@
continuePendingResponses();
}
-void InspectorNetworkAgent::addInterception(ErrorString& errorString, const String& url, const String* networkStageString)
+void InspectorNetworkAgent::addInterception(ErrorString& errorString, const String& url, const bool* optionalCaseSensitive, const bool* optionalIsRegex, const String* networkStageString)
{
if (networkStageString) {
auto networkStage = Inspector::Protocol::InspectorHelpers::parseEnumValueFromString<Inspector::Protocol::Network::NetworkStage>(*networkStageString);
@@ -1019,13 +1039,20 @@
}
}
+ Intercept intercept;
+ intercept.url = ""
+ if (optionalCaseSensitive)
+ intercept.caseSensitive = *optionalCaseSensitive;
+ if (optionalIsRegex)
+ intercept.isRegex = *optionalIsRegex;
+
// FIXME: Support intercepting requests.
- if (!m_interceptResponseURLs.add(url).isNewEntry)
- errorString = "Intercept for given url already exists"_s;
+ if (!m_intercepts.appendIfNotContains(intercept))
+ errorString = "Intercept for given url and given isRegex already exists"_s;
}
-void InspectorNetworkAgent::removeInterception(ErrorString& errorString, const String& url, const String* networkStageString)
+void InspectorNetworkAgent::removeInterception(ErrorString& errorString, const String& url, const bool* optionalCaseSensitive, const bool* optionalIsRegex, const String* networkStageString)
{
if (networkStageString) {
auto networkStage = Inspector::Protocol::InspectorHelpers::parseEnumValueFromString<Inspector::Protocol::Network::NetworkStage>(*networkStageString);
@@ -1035,10 +1062,17 @@
}
}
+ Intercept intercept;
+ intercept.url = ""
+ if (optionalCaseSensitive)
+ intercept.caseSensitive = *optionalCaseSensitive;
+ if (optionalIsRegex)
+ intercept.isRegex = *optionalIsRegex;
+
// FIXME: Support intercepting requests.
- if (!m_interceptResponseURLs.remove(url))
- errorString = "Missing intercept for given url"_s;
+ if (!m_intercepts.removeAll(intercept))
+ errorString = "Missing intercept for given url and given isRegex"_s;
}
bool InspectorNetworkAgent::willInterceptRequest(const ResourceRequest& request)
@@ -1046,14 +1080,7 @@
if (!m_interceptionEnabled)
return false;
- URL requestURL = request.url();
- requestURL.removeFragmentIdentifier();
-
- String url = ""
- if (url.isEmpty())
- return false;
-
- return m_interceptResponseURLs.contains(url);
+ return shouldIntercept(request.url());
}
bool InspectorNetworkAgent::shouldInterceptResponse(const ResourceResponse& response)
@@ -1061,14 +1088,7 @@
if (!m_interceptionEnabled)
return false;
- URL responseURL = response.url();
- responseURL.removeFragmentIdentifier();
-
- String url = ""
- if (url.isEmpty())
- return false;
-
- return m_interceptResponseURLs.contains(url);
+ return shouldIntercept(response.url());
}
void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response, unsigned long identifier, CompletionHandler<void(const ResourceResponse&, RefPtr<SharedBuffer>)>&& handler)
Modified: trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h (252613 => 252614)
--- trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h 2019-11-19 01:30:51 UTC (rev 252614)
@@ -37,9 +37,8 @@
#include <_javascript_Core/InspectorBackendDispatchers.h>
#include <_javascript_Core/InspectorFrontendDispatchers.h>
#include <_javascript_Core/RegularExpression.h>
-#include <wtf/HashSet.h>
+#include <wtf/Forward.h>
#include <wtf/JSONValues.h>
-#include <wtf/text/WTFString.h>
namespace Inspector {
class InjectedScriptManager;
@@ -89,8 +88,8 @@
void getSerializedCertificate(ErrorString&, const String& requestId, String* serializedCertificate) final;
void resolveWebSocket(ErrorString&, const String& requestId, const String* objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>&) final;
void setInterceptionEnabled(ErrorString&, bool enabled) final;
- void addInterception(ErrorString&, const String& url, const String* networkStageString) final;
- void removeInterception(ErrorString&, const String& url, const String* networkStageString) final;
+ void addInterception(ErrorString&, const String& url, const bool* caseSensitive, const bool* isRegex, const String* networkStageString) final;
+ void removeInterception(ErrorString&, const String& url, const bool* caseSensitive, const bool* isRegex, const String* networkStageString) final;
void interceptContinue(ErrorString&, const String& requestId) final;
void interceptWithResponse(ErrorString&, const String& requestId, const String& content, bool base64Encoded, const String* mimeType, const int* status, const String* statusText, const JSON::Object* headers) final;
@@ -141,6 +140,7 @@
void willSendRequest(unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, InspectorPageAgent::ResourceType);
+ bool shouldIntercept(URL);
void continuePendingResponses();
WebSocket* webSocketForRequestId(const String& requestId);
@@ -200,7 +200,19 @@
HashMap<String, String> m_extraRequestHeaders;
HashSet<unsigned long> m_hiddenRequestIdentifiers;
- HashSet<String> m_interceptResponseURLs;
+ struct Intercept {
+ String url;
+ bool caseSensitive { true };
+ bool isRegex { false };
+
+ inline bool operator==(const Intercept& other) const
+ {
+ return url == other.url
+ && caseSensitive == other.caseSensitive
+ && isRegex == other.isRegex;
+ }
+ };
+ Vector<Intercept> m_intercepts;
HashMap<String, std::unique_ptr<PendingInterceptResponse>> m_pendingInterceptResponses;
// FIXME: InspectorNetworkAgent should not be aware of style recalculation.
Modified: trunk/Source/WebInspectorUI/ChangeLog (252613 => 252614)
--- trunk/Source/WebInspectorUI/ChangeLog 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/ChangeLog 2019-11-19 01:30:51 UTC (rev 252614)
@@ -1,3 +1,54 @@
+2019-11-18 Devin Rousso <[email protected]>
+
+ Web Inspector: Local Resource Overrides: allow substitution based on a url pattern
+ https://bugs.webkit.org/show_bug.cgi?id=202375
+
+ Reviewed by Brian Burg.
+
+ Often, websites will load content with a timestamp-based URL query parameter for
+ cache-busting or logging purposes. If a developer is trying to override these resources (or
+ is trying to have an existing override also match these resources), they'd need to edit the
+ local override's URL to match in addition to editing the resource that loads it (e.g. change
+ the <script> in an HTML file), which can sometimes be tricky of the content is dynamically
+ loaded (e.g. an XHR with a non-hardcoded URL).
+
+ Allowing for local overrides to be set using a regular _expression_ pattern would help resolve
+ this limitation.
+
+ * UserInterface/Models/LocalResourceOverride.js:
+ (WI.LocalResourceOverride):
+ (WI.LocalResourceOverride.create):
+ (WI.LocalResourceOverride.fromJSON):
+ (WI.LocalResourceOverride.prototype.toJSON):
+ (WI.LocalResourceOverride.prototype.get isCaseSensitive): Added.
+ (WI.LocalResourceOverride.prototype.get isRegex): Added.
+ (WI.LocalResourceOverride.prototype.matches): Added.
+ (WI.LocalResourceOverride.prototype.saveIdentityToCookie):
+
+ * UserInterface/Controllers/NetworkManager.js:
+ (WI.NetworkManager):
+ (WI.NetworkManager.prototype.initializeTarget):
+ (WI.NetworkManager.prototype.get localResourceOverrides):
+ (WI.NetworkManager.prototype.addLocalResourceOverride):
+ (WI.NetworkManager.prototype.removeLocalResourceOverride):
+ (WI.NetworkManager.prototype.localResourceOverrideForURL):
+ (WI.NetworkManager.prototype.responseIntercepted):
+
+ * UserInterface/Views/LocalResourceOverridePopover.js:
+ (WI.LocalResourceOverridePopover):
+ (WI.LocalResourceOverridePopover.prototype.get serializedData):
+ (WI.LocalResourceOverridePopover.prototype.show):
+ (WI.LocalResourceOverridePopover.prototype._createEditor):
+
+ * UserInterface/Views/LocalResourceOverrideTreeElement.js:
+ (WI.LocalResourceOverrideTreeElement.prototype.get mainTitleText): Added.
+ (WI.LocalResourceOverrideTreeElement.prototype.onattach):
+ (WI.LocalResourceOverrideTreeElement.prototype.ondetach):
+ (WI.LocalResourceOverrideTreeElement.prototype.populateContextMenu):
+ (WI.LocalResourceOverrideTreeElement.prototype.willDismissPopover):
+ * UserInterface/Views/SourcesNavigationSidebarPanel.js:
+ (WI.SourcesNavigationSidebarPanel.prototype._willDismissLocalOverridePopover):
+
2019-11-15 Devin Rousso <[email protected]>
Web Inspector: Elements: Styles: support multiline CSS property values
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (252613 => 252614)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-11-19 01:30:51 UTC (rev 252614)
@@ -46,6 +46,7 @@
localizedStrings["%dpx\u00B2"] = "%dpx\u00B2";
localizedStrings["%s (%s)"] = "%s (%s)";
localizedStrings["%s (%s, %s)"] = "%s (%s, %s)";
+localizedStrings["%s (Case Insensitive)"] = "%s (Case Insensitive)";
localizedStrings["%s (default)"] = "%s (default)";
localizedStrings["%s (hidden)"] = "%s (hidden)";
localizedStrings["%s Callback"] = "%s Callback";
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js (252613 => 252614)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js 2019-11-19 01:30:51 UTC (rev 252614)
@@ -43,7 +43,7 @@
this._sourceMapURLMap = new Map;
this._downloadingSourceMaps = new Set;
- this._localResourceOverrideMap = new Map;
+ this._localResourceOverrides = new Set;
this._harImportLocalResourceMap = new Set;
this._pendingLocalResourceOverrideSaves = null;
@@ -158,9 +158,15 @@
if (this._interceptionEnabled)
target.NetworkAgent.setInterceptionEnabled(this._interceptionEnabled);
- for (let [url, localResourceOverride] of this._localResourceOverrideMap) {
- if (!localResourceOverride.disabled)
- target.NetworkAgent.addInterception(localResourceOverride.url, InspectorBackend.Enum.Network.NetworkStage.Response);
+ for (let localResourceOverride of this._localResourceOverrides) {
+ if (!localResourceOverride.disabled) {
+ target.NetworkAgent.addInterception.invoke({
+ url: localResourceOverride.url,
+ caseSensitive: localResourceOverride.isCaseSensitive,
+ isRegex: localResourceOverride.isRegex,
+ networkStage: InspectorBackend.Enum.Network.NetworkStage.Response,
+ });
+ }
}
}
}
@@ -187,7 +193,7 @@
get localResourceOverrides()
{
- return Array.from(this._localResourceOverrideMap.values());
+ return Array.from(this._localResourceOverrides);
}
get interceptionEnabled()
@@ -350,17 +356,24 @@
{
console.assert(localResourceOverride instanceof WI.LocalResourceOverride);
- console.assert(!this._localResourceOverrideMap.get(localResourceOverride.url), "Already had an existing local resource override.");
- this._localResourceOverrideMap.set(localResourceOverride.url, localResourceOverride);
+ console.assert(!this._localResourceOverrides.has(localResourceOverride), "Already had an existing local resource override.");
+ this._localResourceOverrides.add(localResourceOverride);
if (!this._restoringLocalResourceOverrides)
WI.objectStores.localResourceOverrides.putObject(localResourceOverride);
if (!localResourceOverride.disabled) {
+ let commandArguments = {
+ url: localResourceOverride.url,
+ caseSensitive: localResourceOverride.isCaseSensitive,
+ isRegex: localResourceOverride.isRegex,
+ networkStage: InspectorBackend.Enum.Network.NetworkStage.Response,
+ };
+
// COMPATIBILITY (iOS 13.0): Network.addInterception did not exist.
for (let target of WI.targets) {
if (target.hasCommand("Network.addInterception"))
- target.NetworkAgent.addInterception(localResourceOverride.url, InspectorBackend.Enum.Network.NetworkStage.Response);
+ target.NetworkAgent.addInterception.invoke(commandArguments);
}
}
@@ -371,7 +384,7 @@
{
console.assert(localResourceOverride instanceof WI.LocalResourceOverride);
- if (!this._localResourceOverrideMap.delete(localResourceOverride.url)) {
+ if (!this._localResourceOverrides.delete(localResourceOverride)) {
console.assert(false, "Attempted to remove a local resource override that was not known.");
return;
}
@@ -383,10 +396,17 @@
WI.objectStores.localResourceOverrides.deleteObject(localResourceOverride);
if (!localResourceOverride.disabled) {
+ let commandArguments = {
+ url: localResourceOverride.url,
+ caseSensitive: localResourceOverride.isCaseSensitive,
+ isRegex: localResourceOverride.isRegex,
+ networkStage: InspectorBackend.Enum.Network.NetworkStage.Response,
+ };
+
// COMPATIBILITY (iOS 13.0): Network.removeInterception did not exist.
for (let target of WI.targets) {
if (target.hasCommand("Network.removeInterception"))
- target.NetworkAgent.removeInterception(localResourceOverride.url, InspectorBackend.Enum.Network.NetworkStage.Response);
+ target.NetworkAgent.removeInterception.invoke(commandArguments);
}
}
@@ -395,7 +415,11 @@
localResourceOverrideForURL(url)
{
- return this._localResourceOverrideMap.get(url);
+ for (let localResourceOverride of this._localResourceOverrides) {
+ if (localResourceOverride.matches(url))
+ return localResourceOverride;
+ }
+ return null;
}
canBeOverridden(resource)
@@ -923,7 +947,7 @@
responseIntercepted(target, requestId, response)
{
let url = ""
- let localResourceOverride = this._localResourceOverrideMap.get(url);
+ let localResourceOverride = this.localResourceOverrideForURL(url);
if (!localResourceOverride || localResourceOverride.disabled) {
target.NetworkAgent.interceptContinue(requestId);
return;
@@ -1387,13 +1411,20 @@
let localResourceOverride = event.target;
WI.objectStores.localResourceOverrides.putObject(localResourceOverride);
+ let commandArguments = {
+ url: localResourceOverride.url,
+ caseSensitive: localResourceOverride.isCaseSensitive,
+ isRegex: localResourceOverride.isRegex,
+ networkStage: InspectorBackend.Enum.Network.NetworkStage.Response,
+ };
+
// COMPATIBILITY (iOS 13.0): Network.addInterception / Network.removeInterception did not exist.
for (let target of WI.targets) {
if (target.hasDomain("Network")) {
if (localResourceOverride.disabled)
- target.NetworkAgent.removeInterception(localResourceOverride.url, InspectorBackend.Enum.Network.NetworkStage.Response);
+ target.NetworkAgent.removeInterception.invoke(commandArguments);
else
- target.NetworkAgent.addInterception(localResourceOverride.url, InspectorBackend.Enum.Network.NetworkStage.Response);
+ target.NetworkAgent.addInterception.invoke(commandArguments);
}
}
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/LocalResourceOverride.js (252613 => 252614)
--- trunk/Source/WebInspectorUI/UserInterface/Models/LocalResourceOverride.js 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/LocalResourceOverride.js 2019-11-19 01:30:51 UTC (rev 252614)
@@ -25,26 +25,30 @@
WI.LocalResourceOverride = class LocalResourceOverride extends WI.Object
{
- constructor(localResource, {disabled} = {})
+ constructor(localResource, {isCaseSensitive, isRegex, disabled} = {})
{
console.assert(localResource instanceof WI.LocalResource);
console.assert(localResource.isLocalResourceOverride);
console.assert(localResource.url);
- console.assert(!disabled || typeof disabled === "boolean");
+ console.assert(isCaseSensitive === undefined || typeof isCaseSensitive === "boolean");
+ console.assert(isRegex === undefined || typeof isRegex === "boolean");
+ console.assert(disabled === undefined || typeof disabled === "boolean");
super();
this._localResource = localResource;
- this._disabled = disabled || false;
+ this._isCaseSensitive = isCaseSensitive !== undefined ? isCaseSensitive : true;
+ this._isRegex = isRegex !== undefined ? isRegex : false;
+ this._disabled = disabled !== undefined ? disabled : false;
}
// Static
- static create({url, mimeType, content, base64Encoded, statusCode, statusText, headers, disabled})
+ static create({url, mimeType, content, base64Encoded, statusCode, statusText, headers, isCaseSensitive, isRegex, disabled})
{
let localResource = new WI.LocalResource({
request: {
- url: WI.urlWithoutFragment(url),
+ url: isRegex ? url : WI.urlWithoutFragment(url),
},
response: {
headers,
@@ -57,7 +61,7 @@
isLocalResourceOverride: true,
});
- return new WI.LocalResourceOverride(localResource, {disabled});
+ return new WI.LocalResourceOverride(localResource, {isCaseSensitive, isRegex, disabled});
}
// Import / Export
@@ -64,8 +68,8 @@
static fromJSON(json)
{
- let {localResource, disabled} = json;
- return new WI.LocalResourceOverride(WI.LocalResource.fromJSON(localResource), {disabled});
+ let {localResource, isCaseSensitive, isRegex, disabled} = json;
+ return new WI.LocalResourceOverride(WI.LocalResource.fromJSON(localResource), {isCaseSensitive, isRegex, disabled});
}
toJSON(key)
@@ -72,6 +76,8 @@
{
let json = {
localResource: this._localResource.toJSON(key),
+ isCaseSensitive: this._isCaseSensitive,
+ isRegex: this._isRegex,
disabled: this._disabled,
};
@@ -85,6 +91,8 @@
get url() { return this._localResource.url; }
get localResource() { return this._localResource; }
+ get isCaseSensitive() { return this._isCaseSensitive; }
+ get isRegex() { return this._isRegex; }
get disabled()
{
@@ -101,11 +109,26 @@
this.dispatchEventToListeners(WI.LocalResourceOverride.Event.DisabledChanged);
}
+ matches(url)
+ {
+ if (this._isRegex) {
+ let regex = new RegExp(this.url, !this._isCaseSensitive ? "i" : "");
+ return regex.test(url);
+ }
+
+ if (!this._isCaseSensitive)
+ return String(url).toLowerCase() === this.url.toLowerCase();
+
+ return url ="" this.url;
+ }
+
// Protected
saveIdentityToCookie(cookie)
{
cookie["local-resource-override-url"] = this._localResource.url;
+ cookie["local-resource-override-is-case-sensitive"] = this._isCaseSensitive;
+ cookie["local-resource-override-is-regex"] = this._isRegex;
cookie["local-resource-override-disabled"] = this._disabled;
}
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverridePopover.css (252613 => 252614)
--- trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverridePopover.css 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverridePopover.css 2019-11-19 01:30:51 UTC (rev 252614)
@@ -69,6 +69,14 @@
width: 324px;
}
+.popover .local-resource-override-popover-content label:matches(.is-case-sensitive, .is-regex) {
+ display: inline-block;
+}
+
+.popover .local-resource-override-popover-content label.is-case-sensitive {
+ -webkit-margin-end: 8px;
+}
+
.popover .local-resource-override-popover-content .editor.mime {
width: 240px;
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverridePopover.js (252613 => 252614)
--- trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverridePopover.js 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverridePopover.js 2019-11-19 01:30:51 UTC (rev 252614)
@@ -30,6 +30,8 @@
super(delegate);
this._urlCodeMirror = null;
+ this._isCaseSensitiveCheckbox = null;
+ this._isRegexCheckbox = null;
this._mimeTypeCodeMirror = null;
this._statusCodeCodeMirror = null;
this._statusTextCodeMirror = null;
@@ -51,9 +53,12 @@
if (!url)
return null;
- const schemes = ["http:", "https:", "file:"];
- if (!schemes.some((scheme) => url.startsWith(scheme)))
- return null;
+ let isRegex = this._isRegexCheckbox && this._isRegexCheckbox.checked;
+ if (!isRegex) {
+ const schemes = ["http:", "https:", "file:"];
+ if (!schemes.some((scheme) => url.toLowerCase().startsWith(scheme)))
+ return null;
+ }
// NOTE: We can allow an empty mimeType / statusCode / statusText to pass
// network values through, but lets require them for overrides so that
@@ -91,6 +96,12 @@
headers,
};
+ if (this._isCaseSensitiveCheckbox)
+ data.isCaseSensitive = this._isCaseSensitiveCheckbox.checked;
+
+ if (this._isRegexCheckbox)
+ data.isRegex = this._isRegexCheckbox.checked;
+
// No change.
let oldSerialized = JSON.stringify(this._serializedDataWhenShown);
let newSerialized = JSON.stringify(data);
@@ -100,11 +111,13 @@
return data;
}
- show(localResource, targetElement, preferredEdges)
+ show(localResourceOverride, targetElement, preferredEdges)
{
this._targetElement = targetElement;
this._preferredEdges = preferredEdges;
+ let localResource = localResourceOverride ? localResourceOverride.localResource : null;
+
let url = "" ? localResource.url : "";
let mimeType = localResource ? localResource.mimeType : "";
let statusCode = localResource ? String(localResource.statusCode) : "";
@@ -125,7 +138,7 @@
let table = popoverContentElement.appendChild(document.createElement("table"));
- let createRow = (label, id, text) => {
+ let createRow = (label, id, text, placeholder) => {
let row = table.appendChild(document.createElement("tr"));
let headerElement = row.appendChild(document.createElement("th"));
let dataElement = row.appendChild(document.createElement("td"));
@@ -136,7 +149,7 @@
let editorElement = dataElement.appendChild(document.createElement("div"));
editorElement.classList.add("editor", id);
- let codeMirror = this._createEditor(editorElement, text);
+ let codeMirror = this._createEditor(editorElement, text, placeholder);
let inputField = codeMirror.getInputField();
inputField.id = `local-resource-override-popover-${id}-input-field`;
labelElement.setAttribute("for", inputField.id);
@@ -144,19 +157,56 @@
return {codeMirror, dataElement};
};
- let urlRow = createRow(WI.UIString("URL"), "url", url);
+ let urlRow = createRow(WI.UIString("URL"), "url", url, url || "http://example.com/index.html");
this._urlCodeMirror = urlRow.codeMirror;
- this._urlCodeMirror.setOption("mode", "text/x-local-override-url");
- let mimeTypeRow = createRow(WI.UIString("MIME Type"), "mime", mimeType);
+ let updateURLCodeMirrorMode = () => {
+ let isRegex = this._isRegexCheckbox && this._isRegexCheckbox.checked;
+
+ this._urlCodeMirror.setOption("mode", isRegex ? "text/x-regex" : "text/x-local-override-url");
+
+ if (!isRegex) {
+ let url = ""
+ const schemes = ["http:", "https:", "file:"];
+ if (!schemes.some((scheme) => url.toLowerCase().startsWith(scheme)))
+ this._urlCodeMirror.setValue("http://" + url);
+ }
+ };
+
+ if (InspectorBackend.hasCommand("Network.addInterception", "caseSensitive")) {
+ let isCaseSensitiveLabel = urlRow.dataElement.appendChild(document.createElement("label"));
+ isCaseSensitiveLabel.className = "is-case-sensitive";
+
+ this._isCaseSensitiveCheckbox = isCaseSensitiveLabel.appendChild(document.createElement("input"));
+ this._isCaseSensitiveCheckbox.type = "checkbox";
+ this._isCaseSensitiveCheckbox.checked = localResourceOverride ? localResourceOverride.isCaseSensitive : true;
+
+ isCaseSensitiveLabel.append(WI.UIString("Case Sensitive"));
+ }
+
+ if (InspectorBackend.hasCommand("Network.addInterception", "isRegex")) {
+ let isRegexLabel = urlRow.dataElement.appendChild(document.createElement("label"));
+ isRegexLabel.className = "is-regex";
+
+ this._isRegexCheckbox = isRegexLabel.appendChild(document.createElement("input"));
+ this._isRegexCheckbox.type = "checkbox";
+ this._isRegexCheckbox.checked = localResourceOverride ? localResourceOverride.isRegex : false;
+ this._isRegexCheckbox.addEventListener("change", (event) => {
+ updateURLCodeMirrorMode();
+ });
+
+ isRegexLabel.append(WI.UIString("Regular _expression_"));
+ }
+
+ let mimeTypeRow = createRow(WI.UIString("MIME Type"), "mime", mimeType, mimeType || "text/html");
this._mimeTypeCodeMirror = mimeTypeRow.codeMirror;
- let statusCodeRow = createRow(WI.UIString("Status"), "status", statusCode);
+ let statusCodeRow = createRow(WI.UIString("Status"), "status", statusCode, statusCode || "200");
this._statusCodeCodeMirror = statusCodeRow.codeMirror;
let statusTextEditorElement = statusCodeRow.dataElement.appendChild(document.createElement("div"));
statusTextEditorElement.className = "editor status-text";
- this._statusTextCodeMirror = this._createEditor(statusTextEditorElement, statusText);
+ this._statusTextCodeMirror = this._createEditor(statusTextEditorElement, statusText, statusText || "OK");
let editCallback = () => {};
let deleteCallback = (node) => {
@@ -278,6 +328,9 @@
// Update mimeType when URL gets a file extension.
this._urlCodeMirror.on("change", (cm) => {
+ if (this._isRegexCheckbox && this._isRegexCheckbox.checked)
+ return;
+
let extension = WI.fileExtensionForURL(cm.getValue());
if (!extension)
return;
@@ -296,6 +349,8 @@
contentTypeDataGridNode.data = "" "Content-Type", value: mimeType};
});
+ updateURLCodeMirrorMode();
+
this._serializedDataWhenShown = this.serializedData;
this.content = popoverContentElement;
@@ -315,7 +370,7 @@
// Private
- _createEditor(element, value)
+ _createEditor(element, value, placeholder)
{
let codeMirror = WI.CodeMirrorEditor.create(element, {
extraKeys: {"Tab": false, "Shift-Tab": false},
@@ -322,7 +377,7 @@
lineWrapping: false,
mode: "text/plain",
matchBrackets: true,
- placeholder: "http://example.com/index.html",
+ placeholder,
scrollbarStyle: null,
value,
});
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverrideTreeElement.js (252613 => 252614)
--- trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverrideTreeElement.js 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LocalResourceOverrideTreeElement.js 2019-11-19 01:30:51 UTC (rev 252614)
@@ -40,6 +40,21 @@
// Protected
+ get mainTitleText()
+ {
+ let text;
+ if (this.representedObject.isRegex) {
+ text = "/" + this.resource.url + "/";
+ if (!this.representedObject.isCaseSensitive)
+ text += "i";
+ } else {
+ text = super.mainTitleText;
+ if (!this.representedObject.isCaseSensitive)
+ text = WI.UIString("%s (Case Insensitive)").format(text);
+ }
+ return text;
+ }
+
onattach()
{
super.onattach();
@@ -86,7 +101,7 @@
{
contextMenu.appendItem(WI.UIString("Edit Local Override\u2026"), (event) => {
let popover = new WI.LocalResourceOverridePopover(this);
- popover.show(this._localResourceOverride.localResource, this.status, [WI.RectEdge.MAX_X, WI.RectEdge.MIN_X]);
+ popover.show(this._localResourceOverride, this.status, [WI.RectEdge.MAX_X, WI.RectEdge.MIN_X]);
});
let toggleEnabledString = this._localResourceOverride.disabled ? WI.UIString("Enable Local Override") : WI.UIString("Disable Local Override");
@@ -114,7 +129,7 @@
if (!serializedData)
return;
- let {url, mimeType, statusCode, statusText, headers} = serializedData;
+ let {url, isCaseSensitive, isRegex, mimeType, statusCode, statusText, headers} = serializedData;
// Do not conflict with an existing override unless we are modifying ourselves.
let existingOverride = WI.networkManager.localResourceOverrideForURL(url);
@@ -128,6 +143,8 @@
let revision = this._localResourceOverride.localResource.currentRevision;
let newLocalResourceOverride = WI.LocalResourceOverride.create({
url,
+ isCaseSensitive,
+ isRegex,
mimeType,
statusCode,
statusText,
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js (252613 => 252614)
--- trunk/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js 2019-11-19 01:12:57 UTC (rev 252613)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js 2019-11-19 01:30:51 UTC (rev 252614)
@@ -667,7 +667,7 @@
return;
}
- let {url, mimeType, statusCode, statusText, headers} = serializedData;
+ let {url, isCaseSensitive, isRegex, mimeType, statusCode, statusText, headers} = serializedData;
// Do not conflict with an existing override.
let existingOverride = WI.networkManager.localResourceOverrideForURL(url);
@@ -678,6 +678,8 @@
let localResourceOverride = WI.LocalResourceOverride.create({
url,
+ isCaseSensitive,
+ isRegex,
mimeType,
statusCode,
statusText,