diff --git a/src/manipulation.js b/src/manipulation.js index 8eca61add..7838e2293 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -157,7 +157,8 @@ function domManip( collection, args, callback, ignored ) { // Optional AJAX dependency, but won't run scripts if not present if ( jQuery._evalUrl && !node.noModule ) { jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) + nonce: node.nonce || node.getAttribute( "nonce" ), + crossOrigin: node.crossOrigin }, doc ); } } else { diff --git a/src/manipulation/_evalUrl.js b/src/manipulation/_evalUrl.js index 0f7559ff0..8a8d63d9d 100644 --- a/src/manipulation/_evalUrl.js +++ b/src/manipulation/_evalUrl.js @@ -10,6 +10,7 @@ jQuery._evalUrl = function( url, options, doc ) { cache: true, async: false, global: false, + scriptAttrs: options.crossOrigin ? { "crossOrigin": options.crossOrigin } : undefined, // Only evaluate the response if it is successful (gh-4126) // dataFilter is not invoked for failure responses, so using it instead diff --git a/test/data/mock.php b/test/data/mock.php index b76fd521c..24302e6bc 100644 --- a/test/data/mock.php +++ b/test/data/mock.php @@ -54,7 +54,21 @@ class MockServer { } else { header( 'Content-type: text/html' ); } - echo 'QUnit.assert.ok( true, "mock executed" );'; + + if ( !empty( $req->query['cors'] ) ) { + header( "Access-Control-Allow-Origin: *" ); + } + + if ( !empty( $req->query['callback'] ) ) { + $headers = array_combine( + array_map( 'strtolower', array_keys( $req->headers ) ), + array_values( $req->headers ) + ); + + echo $req->query['callback'] . "(" . json_encode( [ 'headers' => $headers ] ) . ")"; + } else { + echo 'QUnit.assert.ok( true, "mock executed" );'; + } } // Used to be in test.js, but was renamed to testbar.php diff --git a/test/middleware-mockserver.js b/test/middleware-mockserver.js index b3f630dd5..863aaf6bd 100644 --- a/test/middleware-mockserver.js +++ b/test/middleware-mockserver.js @@ -67,7 +67,18 @@ var mocks = { } else { resp.writeHead( 200, { "content-type": "text/html" } ); } - resp.end( "QUnit.assert.ok( true, \"mock executed\" );" ); + + if ( req.query.cors ) { + resp.writeHead( 200, { "access-control-allow-origin": "*" } ); + } + + if ( req.query.callback ) { + resp.end( req.query.callback + "(" + JSON.stringify( { + headers: req.headers + } ) + ")" ); + } else { + resp.end( "QUnit.assert.ok( true, \"mock executed\" );" ); + } }, testbar: function( req, resp ) { resp.writeHead( 200 ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index a4a46f924..9058c1649 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2295,6 +2295,39 @@ testIframe( QUnit[ jQuery.ajax ? "test" : "skip" ] ); + +// We need to simulate cross-domain requests with the feature that +// both 127.0.0.1 and localhost point to the mock http server. +// Skip the the test if we are not in localhost but make sure we run +// it in Karma. +QUnit[ + jQuery.ajax && ( window.__karma__ || location.hostname === "localhost" ) ? + "test" : + "skip" +]( "jQuery.append with crossorigin attribute", function( assert ) { + assert.expect( 1 ); + + var done = assert.async(), + timeout; + + Globals.register( "corsCallback" ); + window.corsCallback = function( response ) { + assert.ok( typeof response.headers.origin === "string", "Origin header sent" ); + window.clearTimeout( timeout ); + done(); + }; + + var src = baseURL + "mock.php?action=script&cors=1&callback=corsCallback"; + src = src.replace( "localhost", "127.0.0.1" ); + var html = "