From 3dedc3f2d46d38296f6867ca69c970e512f87e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 10 Feb 2020 19:17:22 +0100 Subject: [PATCH] Core: Fire iframe script in its context, add doc param in globalEval 1. Support passing custom document to jQuery.globalEval; the script will be invoked in the context of this document. 2. Fire external scripts appended to iframe contents in that iframe context; this was already supported & tested for inline scripts but not for external ones. Fixes gh-4518 Closes gh-4601 (cherry picked from commit 4592595b478be979141ce35c693dbc6b65647173) --- src/core.js | 7 ++++--- src/manipulation.js | 2 +- src/manipulation/_evalUrl.js | 4 ++-- test/data/core/globaleval-context.html | 15 +++++++++++++ .../manipulation/set-global-scripttest.js | 2 ++ test/data/testinit.js | 20 ++++++++++++++---- test/unit/core.js | 13 ++++++++++++ test/unit/manipulation.js | 21 +++++++++++++++++++ 8 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 test/data/core/globaleval-context.html create mode 100644 test/data/manipulation/set-global-scripttest.js diff --git a/src/core.js b/src/core.js index f57075ce7..3c8c661bd 100644 --- a/src/core.js +++ b/src/core.js @@ -245,9 +245,10 @@ jQuery.extend( { return true; }, - // Evaluates a script in a global context - globalEval: function( code, options ) { - DOMEval( code, { nonce: options && options.nonce } ); + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); }, each: function( obj, callback ) { diff --git a/src/manipulation.js b/src/manipulation.js index 1026eaf54..892ab621c 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -201,7 +201,7 @@ function domManip( collection, args, callback, ignored ) { if ( jQuery._evalUrl && !node.noModule ) { jQuery._evalUrl( node.src, { nonce: node.nonce || node.getAttribute( "nonce" ) - } ); + }, doc ); } } else { DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); diff --git a/src/manipulation/_evalUrl.js b/src/manipulation/_evalUrl.js index 9a4d2ac6f..6163b68c4 100644 --- a/src/manipulation/_evalUrl.js +++ b/src/manipulation/_evalUrl.js @@ -4,7 +4,7 @@ define( [ "use strict"; -jQuery._evalUrl = function( url, options ) { +jQuery._evalUrl = function( url, options, doc ) { return jQuery.ajax( { url: url, @@ -22,7 +22,7 @@ jQuery._evalUrl = function( url, options ) { "text script": function() {} }, dataFilter: function( response ) { - jQuery.globalEval( response, options ); + jQuery.globalEval( response, options, doc ); } } ); }; diff --git a/test/data/core/globaleval-context.html b/test/data/core/globaleval-context.html new file mode 100644 index 000000000..1b75e3a0a --- /dev/null +++ b/test/data/core/globaleval-context.html @@ -0,0 +1,15 @@ + + + + + body + + +
+ + + + + diff --git a/test/data/manipulation/set-global-scripttest.js b/test/data/manipulation/set-global-scripttest.js new file mode 100644 index 000000000..7fdbf9d72 --- /dev/null +++ b/test/data/manipulation/set-global-scripttest.js @@ -0,0 +1,2 @@ +window.scriptTest = true; +parent.finishTest(); diff --git a/test/data/testinit.js b/test/data/testinit.js index 6938fed24..cfbee6d73 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -262,12 +262,24 @@ this.testIframe = function( title, fileName, func, wrapper ) { args.unshift( assert ); setTimeout( function() { + var result; + this.iframeCallback = undefined; - func.apply( this, args ); - func = function() {}; - $iframe.remove(); - done(); + result = func.apply( this, args ); + + function finish() { + func = function() {}; + $iframe.remove(); + done(); + } + + // Wait for promises returned by `func`. + if ( result && result.then ) { + result.then( finish ); + } else { + finish(); + } } ); }; diff --git a/test/unit/core.js b/test/unit/core.js index 05ea4337e..1c3dc7365 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -197,6 +197,19 @@ QUnit.test( "globalEval execution after script injection (#7862)", function( ass assert.ok( window.strictEvalTest - now < 500, "Code executed synchronously" ); } ); +testIframe( + "globalEval with custom document context", + "core/globaleval-context.html", + function( assert, framejQuery, frameWindow, frameDocument ) { + assert.expect( 2 ); + + jQuery.globalEval( "window.scriptTest = true;", {}, frameDocument ); + assert.ok( !window.scriptTest, "script executed in iframe context" ); + assert.ok( frameWindow.scriptTest, "script executed in iframe context" ); + } +); + + QUnit.test( "noConflict", function( assert ) { assert.expect( 7 ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index b7fc95a0a..3cf5cf77e 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2315,6 +2315,27 @@ testIframe( } ); +testIframe( + "domManip executes external scripts in iframes in the iframes' context", + "manipulation/scripts-context.html", + function( assert, framejQuery, frameWindow, frameDocument ) { + assert.expect( 2 ); + + Globals.register( "finishTest" ); + + return new Promise( function( resolve ) { + window.finishTest = resolve; + jQuery( frameDocument.body ).append( + "" ); + assert.ok( !window.scriptTest, "script executed in iframe context" ); + assert.ok( frameWindow.scriptTest, "script executed in iframe context" ); + } ); + }, + + // The AJAX module is needed for jQuery._evalUrl. + QUnit[ jQuery.ajax ? "test" : "skip" ] +); + QUnit.test( "jQuery.clone - no exceptions for object elements #9587", function( assert ) { assert.expect( 1 );