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
This commit is contained in:
Michał Gołębiowski-Owczarek 2020-09-01 00:02:44 +02:00 committed by GitHub
parent 1a5fff4c16
commit 68b4ec59c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,6 +3,22 @@ import document from "../var/document.js";
import "../ajax.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) // Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
jQuery.ajaxPrefilter( function( s ) { jQuery.ajaxPrefilter( function( s ) {
if ( s.crossDomain ) { if ( s.crossDomain ) {
@ -35,17 +51,14 @@ jQuery.ajaxPrefilter( "script", function( s ) {
// These types of requests are handled via a script tag // These types of requests are handled via a script tag
// so force their methods to GET. // so force their methods to GET.
if ( s.crossDomain || s.async || s.scriptAttrs ) { if ( canUseScriptTag( s ) ) {
s.type = "GET"; s.type = "GET";
} }
} ); } );
// Bind script tag hack transport // Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) { jQuery.ajaxTransport( "script", function( s ) {
if ( canUseScriptTag( 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 ) {
var script, callback; var script, callback;
return { return {
send: function( _, complete ) { send: function( _, complete ) {