Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Need a mechanism to override navigator.userAgent
https://bugs.webkit.org/show_bug.cgi?id=193762
<rdar://problem/47504939>

Reviewed by Brent Fulgham.

Source/WebCore:

Added the ability to specify user agent string just for navigator.userAgent via DocumentLoader.

* loader/DocumentLoader.h:
(WebCore::DocumentLoader::setCustomJavaScriptUserAgent):
(WebCore::DocumentLoader::customJavaScriptUserAgent const):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::userAgentForJavaScript const):
* loader/FrameLoader.h:
* page/Navigator.cpp:
(WebCore::Navigator::userAgent const):

Source/WebKit:

This patch adds a new _WKWebsitePolicies SPI to specify the user agent string returned by
navigator.userAgent without affecting the user agent string used to send network requests.

Tests: WebKit.WebsitePoliciesCustomJavaScriptUserAgent
       WebKit.WebsitePoliciesCustomUserAgents

* Shared/WebsitePoliciesData.cpp:
(WebKit::WebsitePoliciesData::encode const):
(WebKit::WebsitePoliciesData::decode):
(WebKit::WebsitePoliciesData::applyToDocumentLoader):
* Shared/WebsitePoliciesData.h:
* UIProcess/API/APIWebsitePolicies.cpp:
(API::WebsitePolicies::data):
* UIProcess/API/APIWebsitePolicies.h:
* UIProcess/API/Cocoa/_WKWebsitePolicies.h:
* UIProcess/API/Cocoa/_WKWebsitePolicies.mm:
(-[_WKWebsitePolicies setCustomJavaScriptUserAgent:]):
(-[_WKWebsitePolicies customJavaScriptUserAgent]):

Tools:

Added test cases for _WKWebsitePolicies.customJavaScriptUserAgent.

* TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm:
(-[CustomJavaScriptUserAgentDelegate _webView:decidePolicyForNavigationAction:userInfo:decisionHandler:]):
(-[CustomJavaScriptUserAgentDelegate webView:didFinishNavigation:]):


Canonical link: https://commits.webkit.org/208372@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240541 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
rniwa committed Jan 26, 2019
1 parent 6fa9d47 commit 2a78f19
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 5 deletions.
19 changes: 19 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,22 @@
2019-01-25 Ryosuke Niwa <rniwa@webkit.org>

Need a mechanism to override navigator.userAgent
https://bugs.webkit.org/show_bug.cgi?id=193762
<rdar://problem/47504939>

Reviewed by Brent Fulgham.

Added the ability to specify user agent string just for navigator.userAgent via DocumentLoader.

* loader/DocumentLoader.h:
(WebCore::DocumentLoader::setCustomJavaScriptUserAgent):
(WebCore::DocumentLoader::customJavaScriptUserAgent const):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::userAgentForJavaScript const):
* loader/FrameLoader.h:
* page/Navigator.cpp:
(WebCore::Navigator::userAgent const):

2019-01-25 Devin Rousso <drousso@apple.com>

Web Inspector: provide a way to edit page settings on a remote target
Expand Down
6 changes: 5 additions & 1 deletion Source/WebCore/loader/DocumentLoader.h
Expand Up @@ -270,7 +270,10 @@ class DocumentLoader

void setCustomUserAgent(const String& customUserAgent) { m_customUserAgent = customUserAgent; }
const String& customUserAgent() const { return m_customUserAgent; }


void setCustomJavaScriptUserAgent(const String& customJavaScriptUserAgent) { m_customJavaScriptUserAgent = customJavaScriptUserAgent; }
const String& customJavaScriptUserAgent() const { return m_customJavaScriptUserAgent; }

void setCustomNavigatorPlatform(const String& customNavigatorPlatform) { m_customNavigatorPlatform = customNavigatorPlatform; }
const String& customNavigatorPlatform() const { return m_customNavigatorPlatform; }

Expand Down Expand Up @@ -543,6 +546,7 @@ class DocumentLoader
HashMap<String, Vector<std::pair<String, uint32_t>>> m_pendingContentExtensionDisplayNoneSelectors;
#endif
String m_customUserAgent;
String m_customJavaScriptUserAgent;
String m_customNavigatorPlatform;
bool m_userContentExtensionsEnabled { true };
bool m_deviceOrientationEventEnabled { true };
Expand Down
14 changes: 14 additions & 0 deletions Source/WebCore/loader/FrameLoader.cpp
Expand Up @@ -2705,6 +2705,20 @@ String FrameLoader::userAgent(const URL& url) const

return m_client.userAgent(url);
}

String FrameLoader::userAgentForJavaScript(const URL& url) const
{
if (auto* documentLoader = m_frame.mainFrame().loader().activeDocumentLoader()) {
auto& customJavaScriptUserAgent = documentLoader->customJavaScriptUserAgent();
if (!customJavaScriptUserAgent.isEmpty())
return customJavaScriptUserAgent;
auto& customUserAgent = documentLoader->customUserAgent();
if (!customUserAgent.isEmpty())
return customUserAgent;
}

return m_client.userAgent(url);
}

String FrameLoader::navigatorPlatform() const
{
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/loader/FrameLoader.h
Expand Up @@ -234,6 +234,7 @@ class FrameLoader {

void dispatchOnloadEvents();
String userAgent(const URL&) const;
String userAgentForJavaScript(const URL&) const;
String navigatorPlatform() const;

void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&);
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/page/Navigator.cpp
Expand Up @@ -92,7 +92,7 @@ const String& Navigator::userAgent() const
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::UserAgent);
if (m_userAgent.isNull())
m_userAgent = frame->loader().userAgent(frame->document()->url());
m_userAgent = frame->loader().userAgentForJavaScript(frame->document()->url());
return m_userAgent;
}

Expand Down
27 changes: 27 additions & 0 deletions Source/WebKit/ChangeLog
@@ -1,3 +1,30 @@
2019-01-25 Ryosuke Niwa <rniwa@webkit.org>

Need a mechanism to override navigator.userAgent
https://bugs.webkit.org/show_bug.cgi?id=193762
<rdar://problem/47504939>

Reviewed by Brent Fulgham.

This patch adds a new _WKWebsitePolicies SPI to specify the user agent string returned by
navigator.userAgent without affecting the user agent string used to send network requests.

Tests: WebKit.WebsitePoliciesCustomJavaScriptUserAgent
WebKit.WebsitePoliciesCustomUserAgents

* Shared/WebsitePoliciesData.cpp:
(WebKit::WebsitePoliciesData::encode const):
(WebKit::WebsitePoliciesData::decode):
(WebKit::WebsitePoliciesData::applyToDocumentLoader):
* Shared/WebsitePoliciesData.h:
* UIProcess/API/APIWebsitePolicies.cpp:
(API::WebsitePolicies::data):
* UIProcess/API/APIWebsitePolicies.h:
* UIProcess/API/Cocoa/_WKWebsitePolicies.h:
* UIProcess/API/Cocoa/_WKWebsitePolicies.mm:
(-[_WKWebsitePolicies setCustomJavaScriptUserAgent:]):
(-[_WKWebsitePolicies customJavaScriptUserAgent]):

2019-01-25 Devin Rousso <drousso@apple.com>

Web Inspector: provide a way to edit page settings on a remote target
Expand Down
8 changes: 8 additions & 0 deletions Source/WebKit/Shared/WebsitePoliciesData.cpp
Expand Up @@ -44,6 +44,7 @@ void WebsitePoliciesData::encode(IPC::Encoder& encoder) const
encoder << popUpPolicy;
encoder << websiteDataStoreParameters;
encoder << customUserAgent;
encoder << customJavaScriptUserAgent;
encoder << customNavigatorPlatform;
}

Expand Down Expand Up @@ -89,6 +90,11 @@ Optional<WebsitePoliciesData> WebsitePoliciesData::decode(IPC::Decoder& decoder)
if (!customUserAgent)
return WTF::nullopt;

Optional<String> customJavaScriptUserAgent;
decoder >> customJavaScriptUserAgent;
if (!customJavaScriptUserAgent)
return WTF::nullopt;

Optional<String> customNavigatorPlatform;
decoder >> customNavigatorPlatform;
if (!customNavigatorPlatform)
Expand All @@ -103,6 +109,7 @@ Optional<WebsitePoliciesData> WebsitePoliciesData::decode(IPC::Decoder& decoder)
WTFMove(*popUpPolicy),
WTFMove(*websiteDataStoreParameters),
WTFMove(*customUserAgent),
WTFMove(*customJavaScriptUserAgent),
WTFMove(*customNavigatorPlatform),
} };
}
Expand All @@ -111,6 +118,7 @@ void WebsitePoliciesData::applyToDocumentLoader(WebsitePoliciesData&& websitePol
{
documentLoader.setCustomHeaderFields(WTFMove(websitePolicies.customHeaderFields));
documentLoader.setCustomUserAgent(websitePolicies.customUserAgent);
documentLoader.setCustomJavaScriptUserAgent(websitePolicies.customJavaScriptUserAgent);
documentLoader.setCustomNavigatorPlatform(websitePolicies.customNavigatorPlatform);
documentLoader.setDeviceOrientationEventEnabled(websitePolicies.deviceOrientationEventEnabled);

Expand Down
3 changes: 2 additions & 1 deletion Source/WebKit/Shared/WebsitePoliciesData.h
Expand Up @@ -54,8 +54,9 @@ struct WebsitePoliciesData {
WebsitePopUpPolicy popUpPolicy { WebsitePopUpPolicy::Default };
Optional<WebsiteDataStoreParameters> websiteDataStoreParameters;
String customUserAgent;
String customJavaScriptUserAgent;
String customNavigatorPlatform;

void encode(IPC::Encoder&) const;
static Optional<WebsitePoliciesData> decode(IPC::Decoder&);
};
Expand Down
3 changes: 2 additions & 1 deletion Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp
Expand Up @@ -56,7 +56,8 @@ WebKit::WebsitePoliciesData WebsitePolicies::data()
Optional<WebKit::WebsiteDataStoreParameters> parameters;
if (m_websiteDataStore)
parameters = m_websiteDataStore->websiteDataStore().parameters();
return { contentBlockersEnabled(), deviceOrientationEventEnabled(), allowedAutoplayQuirks(), autoplayPolicy(), customHeaderFields(), popUpPolicy(), WTFMove(parameters), m_customUserAgent, m_customNavigatorPlatform };
return { contentBlockersEnabled(), deviceOrientationEventEnabled(), allowedAutoplayQuirks(), autoplayPolicy(),
customHeaderFields(), popUpPolicy(), WTFMove(parameters), m_customUserAgent, m_customJavaScriptUserAgent, m_customNavigatorPlatform };
}

}
Expand Down
6 changes: 5 additions & 1 deletion Source/WebKit/UIProcess/API/APIWebsitePolicies.h
Expand Up @@ -74,7 +74,10 @@ class WebsitePolicies final : public API::ObjectImpl<API::Object::Type::WebsiteP

void setCustomUserAgent(const WTF::String& customUserAgent) { m_customUserAgent = customUserAgent; }
const WTF::String& customUserAgent() const { return m_customUserAgent; }


void setCustomJavaScriptUserAgent(const WTF::String& customJavaScriptUserAgent) { m_customJavaScriptUserAgent = customJavaScriptUserAgent; }
const WTF::String& customJavaScriptUserAgent() const { return m_customJavaScriptUserAgent; }

void setCustomNavigatorPlatform(const WTF::String& customNavigatorPlatform) { m_customNavigatorPlatform = customNavigatorPlatform; }
const WTF::String& customNavigatorPlatform() const { return m_customNavigatorPlatform; }

Expand All @@ -89,6 +92,7 @@ class WebsitePolicies final : public API::ObjectImpl<API::Object::Type::WebsiteP
WebKit::WebsitePopUpPolicy m_popUpPolicy { WebKit::WebsitePopUpPolicy::Default };
RefPtr<WebsiteDataStore> m_websiteDataStore;
WTF::String m_customUserAgent;
WTF::String m_customJavaScriptUserAgent;
WTF::String m_customNavigatorPlatform;
};

Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/UIProcess/API/Cocoa/_WKWebsitePolicies.h
Expand Up @@ -59,6 +59,7 @@ WK_CLASS_AVAILABLE(macosx(10.12.3), ios(10.3))
@property (nonatomic) _WKWebsitePopUpPolicy popUpPolicy WK_API_AVAILABLE(macosx(10.14), ios(12.0));
@property (nonatomic, strong) WKWebsiteDataStore *websiteDataStore WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
@property (nonatomic, copy) NSString *customUserAgent WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic, copy) NSString *customJavaScriptUserAgent WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic, copy) NSString *customNavigatorPlatform WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic) BOOL deviceOrientationEventEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));

Expand Down
10 changes: 10 additions & 0 deletions Source/WebKit/UIProcess/API/Cocoa/_WKWebsitePolicies.mm
Expand Up @@ -209,6 +209,16 @@ - (NSString *)customUserAgent
return _websitePolicies->customUserAgent();
}

- (void)setCustomJavaScriptUserAgent:(NSString *)customUserAgent
{
_websitePolicies->setCustomJavaScriptUserAgent(customUserAgent);
}

- (NSString *)customJavaScriptUserAgent
{
return _websitePolicies->customJavaScriptUserAgent();
}

- (void)setCustomNavigatorPlatform:(NSString *)customNavigatorPlatform
{
_websitePolicies->setCustomNavigatorPlatform(customNavigatorPlatform);
Expand Down
14 changes: 14 additions & 0 deletions Tools/ChangeLog
@@ -1,3 +1,17 @@
2019-01-25 Ryosuke Niwa <rniwa@webkit.org>

Need a mechanism to override navigator.userAgent
https://bugs.webkit.org/show_bug.cgi?id=193762
<rdar://problem/47504939>

Reviewed by Brent Fulgham.

Added test cases for _WKWebsitePolicies.customJavaScriptUserAgent.

* TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm:
(-[CustomJavaScriptUserAgentDelegate _webView:decidePolicyForNavigationAction:userInfo:decisionHandler:]):
(-[CustomJavaScriptUserAgentDelegate webView:didFinishNavigation:]):

2019-01-25 Dean Jackson <dino@apple.com>

REGRESSION: Some USDz from 3rd party websites don't go directly to AR QL
Expand Down
94 changes: 94 additions & 0 deletions Tools/TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm
Expand Up @@ -1046,6 +1046,9 @@ - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigat
fetch("test://www.webkit.org/fetchResource.html");
}, 0);
}
onmessage = (event) => {
window.subframeUserAgent = event.data;
}
</script>
)TESTRESOURCE";

Expand All @@ -1058,6 +1061,7 @@ - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigat
setTimeout(() => {
fetch("test://www.apple.com/fetchResource.html");
}, 0);
top.postMessage(navigator.userAgent, '*');
}
</script>
)TESTRESOURCE";
Expand Down Expand Up @@ -1100,6 +1104,96 @@ - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigat
loadCount = 0;
}

@interface CustomJavaScriptUserAgentDelegate : NSObject <WKNavigationDelegate>
@property (nonatomic) BOOL setCustomUserAgent;
@end

@implementation CustomJavaScriptUserAgentDelegate

- (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction userInfo:(id <NSSecureCoding>)userInfo decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
{
_WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
if (navigationAction.targetFrame.mainFrame) {
[websitePolicies setCustomJavaScriptUserAgent:@"Foo Custom JavaScript UserAgent"];
if (_setCustomUserAgent)
[websitePolicies setCustomUserAgent:@"Foo Custom Request UserAgent"];
}

decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
finishedNavigation = true;
}

@end

TEST(WebKit, WebsitePoliciesCustomJavaScriptUserAgent)
{
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);

auto schemeHandler = adoptNS([[DataMappingSchemeHandler alloc] init]);
[schemeHandler addMappingFromURLString:@"test://www.webkit.org/main.html" toData:customUserAgentMainFrameTestBytes];
[schemeHandler addMappingFromURLString:@"test://www.apple.com/subframe.html" toData:customUserAgentSubFrameTestBytes];
[schemeHandler setTaskHandler:[](id <WKURLSchemeTask> task) {
auto* userAgentString = [task.request valueForHTTPHeaderField:@"User-Agent"];
EXPECT_TRUE([userAgentString hasPrefix:@"Mozilla/5.0 (Macintosh;"]);
EXPECT_TRUE([userAgentString hasSuffix:@"(KHTML, like Gecko)"]);
}];
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"test"];

auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);

auto delegate = adoptNS([[CustomJavaScriptUserAgentDelegate alloc] init]);
[webView setNavigationDelegate:delegate.get()];

loadCount = 0;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"test://www.webkit.org/main.html"]];
[webView loadRequest:request];

TestWebKitAPI::Util::run(&finishedNavigation);
finishedNavigation = false;

while (loadCount != 9U)
TestWebKitAPI::Util::spinRunLoop();

EXPECT_STREQ("Foo Custom JavaScript UserAgent", [[webView stringByEvaluatingJavaScript:@"navigator.userAgent"] UTF8String]);
EXPECT_STREQ("Foo Custom JavaScript UserAgent", [[webView stringByEvaluatingJavaScript:@"subframeUserAgent"] UTF8String]);
}

TEST(WebKit, WebsitePoliciesCustomUserAgents)
{
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);

auto schemeHandler = adoptNS([[DataMappingSchemeHandler alloc] init]);
[schemeHandler addMappingFromURLString:@"test://www.webkit.org/main.html" toData:customUserAgentMainFrameTestBytes];
[schemeHandler addMappingFromURLString:@"test://www.apple.com/subframe.html" toData:customUserAgentSubFrameTestBytes];
[schemeHandler setTaskHandler:[](id <WKURLSchemeTask> task) {
EXPECT_STREQ("Foo Custom Request UserAgent", [[task.request valueForHTTPHeaderField:@"User-Agent"] UTF8String]);
}];
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"test"];

auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);

auto delegate = adoptNS([[CustomJavaScriptUserAgentDelegate alloc] init]);
delegate.get().setCustomUserAgent = YES;
[webView setNavigationDelegate:delegate.get()];

loadCount = 0;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"test://www.webkit.org/main.html"]];
[webView loadRequest:request];

TestWebKitAPI::Util::run(&finishedNavigation);
finishedNavigation = false;

while (loadCount != 9U)
TestWebKitAPI::Util::spinRunLoop();

EXPECT_STREQ("Foo Custom JavaScript UserAgent", [[webView stringByEvaluatingJavaScript:@"navigator.userAgent"] UTF8String]);
EXPECT_STREQ("Foo Custom JavaScript UserAgent", [[webView stringByEvaluatingJavaScript:@"subframeUserAgent"] UTF8String]);
}

@interface CustomNavigatorPlatformDelegate : NSObject <WKNavigationDelegate> {
}
@end
Expand Down

0 comments on commit 2a78f19

Please sign in to comment.