#include "config.h"
#include "Navigator.h"
#include "Chrome.h"
#include "CookieJar.h"
#include "DOMMimeTypeArray.h"
#include "DOMPluginArray.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "Geolocation.h"
#include "JSDOMPromiseDeferred.h"
#include "LoaderStrategy.h"
#include "Page.h"
#include "PlatformStrategies.h"
#include "PluginData.h"
#include "ResourceLoadObserver.h"
#include "RuntimeEnabledFeatures.h"
#include "ScriptController.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#include <wtf/Language.h>
#include <wtf/StdLibExtras.h>
#include <wtf/WeakPtr.h>
namespace WebCore {
using namespace WTF;
Navigator::Navigator(ScriptExecutionContext* context, DOMWindow& window)
: NavigatorBase(context)
, DOMWindowProperty(&window)
{
}
Navigator::~Navigator() = default;
static bool shouldHideFourDot(Frame& frame)
{
auto* sourceURL = frame.script().sourceURL();
if (!sourceURL)
return false;
if (!(sourceURL->endsWith("/dqm_script.js") || sourceURL->endsWith("/dqm_loader.js") || sourceURL->endsWith("/tdqm_loader.js")))
return false;
return frame.settings().needsSiteSpecificQuirks();
}
String Navigator::appVersion() const
{
auto* frame = this->frame();
if (!frame)
return String();
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::AppVersion);
String appVersion = NavigatorBase::appVersion();
if (shouldHideFourDot(*frame))
appVersion.replace("4.", "4_");
return appVersion;
}
const String& Navigator::userAgent() const
{
auto* frame = this->frame();
if (!frame || !frame->page())
return m_userAgent;
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::UserAgent);
if (m_userAgent.isNull())
m_userAgent = frame->loader().userAgent(frame->document()->url());
return m_userAgent;
}
const String& Navigator::platform() const
{
auto* frame = this->frame();
if (!frame || !frame->page())
return m_platform;
if (m_platform.isNull())
m_platform = frame->loader().navigatorPlatform();
if (m_platform.isNull())
m_platform = NavigatorBase::platform();
return m_platform;
}
void Navigator::userAgentChanged()
{
m_userAgent = String();
}
bool Navigator::onLine() const
{
return platformStrategies()->loaderStrategy()->isOnLine();
}
void Navigator::share(ScriptExecutionContext& context, ShareData data, Ref<DeferredPromise>&& promise)
{
auto* frame = this->frame();
if (!frame || !frame->page()) {
promise->reject(TypeError);
return;
}
if (data.title.isEmpty() && data.url.isEmpty() && data.text.isEmpty()) {
promise->reject(TypeError);
return;
}
Optional<URL> url;
if (!data.url.isEmpty()) {
url = context.completeURL(data.url);
if (!url->isValid()) {
promise->reject(TypeError);
return;
}
}
if (!UserGestureIndicator::processingUserGesture()) {
promise->reject(NotAllowedError);
return;
}
ShareDataWithParsedURL shareData = {
data,
url,
};
frame->page()->chrome().showShareSheet(shareData, [promise = WTFMove(promise)] (bool completed) {
if (completed) {
promise->resolve();
return;
}
promise->reject(Exception { AbortError, "Abort due to cancellation of share."_s });
});
}
DOMPluginArray& Navigator::plugins()
{
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
if (auto* frame = this->frame())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::Plugins);
}
if (!m_plugins)
m_plugins = DOMPluginArray::create(m_window);
return *m_plugins;
}
DOMMimeTypeArray& Navigator::mimeTypes()
{
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
if (auto* frame = this->frame())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::MimeTypes);
}
if (!m_mimeTypes)
m_mimeTypes = DOMMimeTypeArray::create(m_window);
return *m_mimeTypes;
}
bool Navigator::cookieEnabled() const
{
auto* frame = this->frame();
if (!frame)
return false;
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::CookieEnabled);
if (frame->page() && !frame->page()->settings().cookieEnabled())
return false;
auto* document = frame->document();
if (!document)
return false;
return cookiesEnabled(*document);
}
bool Navigator::javaEnabled() const
{
auto* frame = this->frame();
if (!frame)
return false;
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logNavigatorAPIAccessed(*frame->document(), ResourceLoadStatistics::NavigatorAPI::JavaEnabled);
if (!frame->settings().isJavaEnabled())
return false;
if (frame->document()->securityOrigin().isLocal() && !frame->settings().isJavaEnabledForLocalFiles())
return false;
return true;
}
#if PLATFORM(IOS_FAMILY)
bool Navigator::standalone() const
{
auto* frame = this->frame();
return frame && frame->settings().standalone();
}
#endif
void Navigator::getStorageUpdates()
{
}
}