From 68b4ec59c8f290d680e9db4bc980655660817dd1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Tue, 1 Sep 2020 00:02:44 +0200 Subject: [PATCH] Ajax: Make responseJSON work for erroneous same-domain JSONP requests Don't use a script tag for JSONP requests unless for cross-domain requests or if scriptAttrs are provided. This makes the `responseJSON` property available in JSONP error callbacks. This fixes a regression from jQuery 3.5.0 introduced in gh-4379 which made erroneous script responses to not be executed to follow native behavior. The 3.x-stable branch doesn't need this fix as it doesn't use script tags for regular async requests. Closes gh-4778 Ref gh-4771 Ref gh-4773 Ref gh-4379 --- src/ajax/script.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ajax/script.js b/src/ajax/script.js index 54bfecf2e..203ea08e0 100644 --- a/src/ajax/script.js +++ b/src/ajax/script.js @@ -3,6 +3,22 @@ import document from "../var/document.js"; import "../ajax.js"; +function canUseScriptTag( s ) { + + // A script tag can only be used for async, cross domain or forced-by-attrs requests. + // Sync requests remain handled differently to preserve strict script ordering. + return s.crossDomain || s.scriptAttrs || + + // When dealing with JSONP (`s.dataTypes` include "json" then) + // don't use a script tag so that error responses still may have + // `responseJSON` set. Continue using a script tag for JSONP requests that: + // * are cross-domain as AJAX requests won't work without a CORS setup + // * have `scriptAttrs` set as that's a script-only functionality + // Note that this means JSONP requests violate strict CSP script-src settings. + // A proper solution is to migrate from using JSONP to a CORS setup. + ( s.async && jQuery.inArray( "json", s.dataTypes ) < 0 ); +} + // Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) jQuery.ajaxPrefilter( function( s ) { if ( s.crossDomain ) { @@ -35,17 +51,14 @@ jQuery.ajaxPrefilter( "script", function( s ) { // These types of requests are handled via a script tag // so force their methods to GET. - if ( s.crossDomain || s.async || s.scriptAttrs ) { + if ( canUseScriptTag( s ) ) { s.type = "GET"; } } ); // Bind script tag hack transport jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with async, cross domain or forced-by-attrs requests. - // Sync requests remain handled differently to preserve strict script ordering. - if ( s.crossDomain || s.async || s.scriptAttrs ) { + if ( canUseScriptTag( s ) ) { var script, callback; return { send: function( _, complete ) { -- 2.39.5