123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- import { WEB_VIEW_ATTRIBUTES, WEB_VIEW_ERROR_MESSAGES } from '@electron/internal/renderer/web-view/web-view-constants';
- import type { WebViewImpl } from '@electron/internal/renderer/web-view/web-view-impl';
- const resolveURL = function (url?: string | null) {
- return url ? new URL(url, location.href).href : '';
- };
- interface MutationHandler {
- handleMutation (_oldValue: any, _newValue: any): any;
- }
- // Attribute objects.
- // Default implementation of a WebView attribute.
- export class WebViewAttribute implements MutationHandler {
- public value: any;
- public ignoreMutation = false;
- constructor (public name: string, public webViewImpl: WebViewImpl) {
- this.name = name;
- this.value = (webViewImpl.webviewNode as Record<string, any>)[name] || '';
- this.webViewImpl = webViewImpl;
- this.defineProperty();
- }
- // Retrieves and returns the attribute's value.
- public getValue () {
- return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value;
- }
- // Sets the attribute's value.
- public setValue (value: any) {
- this.webViewImpl.webviewNode.setAttribute(this.name, value || '');
- }
- // Changes the attribute's value without triggering its mutation handler.
- public setValueIgnoreMutation (value: any) {
- this.ignoreMutation = true;
- this.setValue(value);
- this.ignoreMutation = false;
- }
- // Defines this attribute as a property on the webview node.
- public defineProperty () {
- return Object.defineProperty(this.webViewImpl.webviewNode, this.name, {
- get: () => {
- return this.getValue();
- },
- set: (value) => {
- return this.setValue(value);
- },
- enumerable: true
- });
- }
- // Called when the attribute's value changes.
- public handleMutation: MutationHandler['handleMutation'] = () => undefined;
- }
- // An attribute that is treated as a Boolean.
- class BooleanAttribute extends WebViewAttribute {
- getValue () {
- return this.webViewImpl.webviewNode.hasAttribute(this.name);
- }
- setValue (value: boolean) {
- if (value) {
- this.webViewImpl.webviewNode.setAttribute(this.name, '');
- } else {
- this.webViewImpl.webviewNode.removeAttribute(this.name);
- }
- }
- }
- // Attribute representing the state of the storage partition.
- export class PartitionAttribute extends WebViewAttribute {
- public validPartitionId = true;
- constructor (public webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.PARTITION, webViewImpl);
- }
- public handleMutation = (oldValue: any, newValue: any) => {
- newValue = newValue || '';
- // The partition cannot change if the webview has already navigated.
- if (!this.webViewImpl.beforeFirstNavigation) {
- console.error(WEB_VIEW_ERROR_MESSAGES.ALREADY_NAVIGATED);
- this.setValueIgnoreMutation(oldValue);
- return;
- }
- if (newValue === 'persist:') {
- this.validPartitionId = false;
- console.error(WEB_VIEW_ERROR_MESSAGES.INVALID_PARTITION_ATTRIBUTE);
- }
- };
- }
- // Attribute that handles the location and navigation of the webview.
- export class SrcAttribute extends WebViewAttribute {
- public observer!: MutationObserver;
- constructor (public webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.SRC, webViewImpl);
- this.setupMutationObserver();
- }
- public getValue () {
- if (this.webViewImpl.webviewNode.hasAttribute(this.name)) {
- return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name));
- } else {
- return this.value;
- }
- }
- public setValueIgnoreMutation (value: any) {
- super.setValueIgnoreMutation(value);
- // takeRecords() is needed to clear queued up src mutations. Without it, it
- // is possible for this change to get picked up asynchronously by src's
- // mutation observer |observer|, and then get handled even though we do not
- // want to handle this mutation.
- this.observer.takeRecords();
- }
- public handleMutation = (oldValue: any, newValue: any) => {
- // Once we have navigated, we don't allow clearing the src attribute.
- // Once <webview> enters a navigated state, it cannot return to a
- // placeholder state.
- if (!newValue && oldValue) {
- // src attribute changes normally initiate a navigation. We suppress
- // the next src attribute handler call to avoid reloading the page
- // on every guest-initiated navigation.
- this.setValueIgnoreMutation(oldValue);
- return;
- }
- this.parse();
- };
- // The purpose of this mutation observer is to catch assignment to the src
- // attribute without any changes to its value. This is useful in the case
- // where the webview guest has crashed and navigating to the same address
- // spawns off a new process.
- public setupMutationObserver () {
- this.observer = new MutationObserver((mutations) => {
- for (const mutation of mutations) {
- const { oldValue } = mutation;
- const newValue = this.getValue();
- if (oldValue !== newValue) {
- return;
- }
- this.handleMutation(oldValue, newValue);
- }
- });
- const params = {
- attributes: true,
- attributeOldValue: true,
- attributeFilter: [this.name]
- };
- this.observer.observe(this.webViewImpl.webviewNode, params);
- }
- public parse () {
- if (!this.webViewImpl.elementAttached || !(this.webViewImpl.attributes.get(WEB_VIEW_ATTRIBUTES.PARTITION) as PartitionAttribute).validPartitionId || !this.getValue()) {
- return;
- }
- if (this.webViewImpl.guestInstanceId == null) {
- if (this.webViewImpl.beforeFirstNavigation) {
- this.webViewImpl.beforeFirstNavigation = false;
- this.webViewImpl.createGuest();
- }
- return;
- }
- // Navigate to |this.src|.
- const opts: Record<string, string> = {};
- const httpreferrer = this.webViewImpl.attributes.get(WEB_VIEW_ATTRIBUTES.HTTPREFERRER)!.getValue();
- if (httpreferrer) {
- opts.httpReferrer = httpreferrer;
- }
- const useragent = this.webViewImpl.attributes.get(WEB_VIEW_ATTRIBUTES.USERAGENT)!.getValue();
- if (useragent) {
- opts.userAgent = useragent;
- }
- (this.webViewImpl.webviewNode as Electron.WebviewTag).loadURL(this.getValue(), opts)
- .catch(err => {
- console.error('Unexpected error while loading URL', err);
- });
- }
- }
- // Attribute specifies HTTP referrer.
- class HttpReferrerAttribute extends WebViewAttribute {
- constructor (webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.HTTPREFERRER, webViewImpl);
- }
- }
- // Attribute specifies user agent
- class UserAgentAttribute extends WebViewAttribute {
- constructor (webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.USERAGENT, webViewImpl);
- }
- }
- // Attribute that set preload script.
- class PreloadAttribute extends WebViewAttribute {
- constructor (webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.PRELOAD, webViewImpl);
- }
- public getValue () {
- if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) {
- return this.value;
- }
- let preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name));
- const protocol = preload.substr(0, 5);
- if (protocol !== 'file:') {
- console.error(WEB_VIEW_ERROR_MESSAGES.INVALID_PRELOAD_ATTRIBUTE);
- preload = '';
- }
- return preload;
- }
- }
- // Attribute that specifies the blink features to be enabled.
- class BlinkFeaturesAttribute extends WebViewAttribute {
- constructor (webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.BLINKFEATURES, webViewImpl);
- }
- }
- // Attribute that specifies the blink features to be disabled.
- class DisableBlinkFeaturesAttribute extends WebViewAttribute {
- constructor (webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.DISABLEBLINKFEATURES, webViewImpl);
- }
- }
- // Attribute that specifies the web preferences to be enabled.
- class WebPreferencesAttribute extends WebViewAttribute {
- constructor (webViewImpl: WebViewImpl) {
- super(WEB_VIEW_ATTRIBUTES.WEBPREFERENCES, webViewImpl);
- }
- }
- // Sets up all of the webview attributes.
- export function setupWebViewAttributes (self: WebViewImpl) {
- return new Map<string, WebViewAttribute>([
- [WEB_VIEW_ATTRIBUTES.PARTITION, new PartitionAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.SRC, new SrcAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.HTTPREFERRER, new HttpReferrerAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.USERAGENT, new UserAgentAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.NODEINTEGRATION, new BooleanAttribute(WEB_VIEW_ATTRIBUTES.NODEINTEGRATION, self)],
- [WEB_VIEW_ATTRIBUTES.NODEINTEGRATIONINSUBFRAMES, new BooleanAttribute(WEB_VIEW_ATTRIBUTES.NODEINTEGRATIONINSUBFRAMES, self)],
- [WEB_VIEW_ATTRIBUTES.PLUGINS, new BooleanAttribute(WEB_VIEW_ATTRIBUTES.PLUGINS, self)],
- [WEB_VIEW_ATTRIBUTES.DISABLEWEBSECURITY, new BooleanAttribute(WEB_VIEW_ATTRIBUTES.DISABLEWEBSECURITY, self)],
- [WEB_VIEW_ATTRIBUTES.ALLOWPOPUPS, new BooleanAttribute(WEB_VIEW_ATTRIBUTES.ALLOWPOPUPS, self)],
- [WEB_VIEW_ATTRIBUTES.PRELOAD, new PreloadAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.BLINKFEATURES, new BlinkFeaturesAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.DISABLEBLINKFEATURES, new DisableBlinkFeaturesAttribute(self)],
- [WEB_VIEW_ATTRIBUTES.WEBPREFERENCES, new WebPreferencesAttribute(self)]
- ]);
- }
|