@@ -5,7 +5,11 @@ import { migrateWarn, migratePatchAndWarnFunc, migratePatchFunc } from "../main.
55if ( jQuery . ajax ) {
66
77var oldAjax = jQuery . ajax ,
8- rjsonp = / ( = ) \? (? = & | $ ) | \? \? / ;
8+ oldCallbacks = [ ] ,
9+ guid = "migrate-" + Date . now ( ) ,
10+ origJsonpCallback = jQuery . ajaxSettings . jsonpCallback ,
11+ rjsonp = / ( = ) \? (? = & | $ ) | \? \? / ,
12+ rquery = / \? / ;
913
1014migratePatchFunc ( jQuery , "ajax" , function ( ) {
1115 var jQXHR = oldAjax . apply ( this , arguments ) ;
@@ -23,16 +27,120 @@ migratePatchFunc( jQuery, "ajax", function() {
2327 return jQXHR ;
2428} , "jqXHR-methods" ) ;
2529
26- // Only trigger the logic in jQuery <4 as the JSON-to-JSONP auto-promotion
27- // behavior is gone in jQuery 4.0 and as it has security implications, we don't
28- // want to restore the legacy behavior.
29- if ( ! jQueryVersionSince ( "4.0.0" ) ) {
30+ jQuery . ajaxSetup ( {
31+ jsonpCallback : function ( ) {
3032
31- // Register this prefilter before the jQuery one. Otherwise, a promoted
32- // request is transformed into one with the script dataType and we can't
33- // catch it anymore.
33+ // Source is virtually the same as in Core, but we need to duplicate
34+ // to maintain a proper `oldCallbacks` reference.
35+ if ( jQuery . migrateIsPatchEnabled ( "jsonp-promotion" ) ) {
36+ var callback = oldCallbacks . pop ( ) || ( jQuery . expando + "_" + ( guid ++ ) ) ;
37+ this [ callback ] = true ;
38+ return callback ;
39+ } else {
40+ return origJsonpCallback . apply ( this , arguments ) ;
41+ }
42+ }
43+ } ) ;
44+
45+ // Register this prefilter before the jQuery one. Otherwise, a promoted
46+ // request is transformed into one with the script dataType, and we can't
47+ // catch it anymore.
48+ if ( jQueryVersionSince ( "4.0.0" ) ) {
49+
50+ // Code mostly from:
51+ // https://github.com/jquery/jquery/blob/fa0058af426c4e482059214c29c29f004254d9a1/src/ajax/jsonp.js#L20-L97
52+ jQuery . ajaxPrefilter ( "+json" , function ( s , originalSettings , jqXHR ) {
53+
54+ if ( ! jQuery . migrateIsPatchEnabled ( "jsonp-promotion" ) ) {
55+ return ;
56+ }
57+
58+ var callbackName , overwritten , responseContainer ,
59+ jsonProp = s . jsonp !== false && ( rjsonp . test ( s . url ) ?
60+ "url" :
61+ typeof s . data === "string" &&
62+ ( s . contentType || "" )
63+ . indexOf ( "application/x-www-form-urlencoded" ) === 0 &&
64+ rjsonp . test ( s . data ) && "data"
65+ ) ;
66+
67+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
68+ if ( jsonProp || s . dataTypes [ 0 ] === "jsonp" ) {
69+ migrateWarn ( "jsonp-promotion" , "JSON-to-JSONP auto-promotion is deprecated" ) ;
70+
71+ // Get callback name, remembering preexisting value associated with it
72+ callbackName = s . jsonpCallback = typeof s . jsonpCallback === "function" ?
73+ s . jsonpCallback ( ) :
74+ s . jsonpCallback ;
75+
76+ // Insert callback into url or form data
77+ if ( jsonProp ) {
78+ s [ jsonProp ] = s [ jsonProp ] . replace ( rjsonp , "$1" + callbackName ) ;
79+ } else if ( s . jsonp !== false ) {
80+ s . url += ( rquery . test ( s . url ) ? "&" : "?" ) + s . jsonp + "=" + callbackName ;
81+ }
82+
83+ // Use data converter to retrieve json after script execution
84+ s . converters [ "script json" ] = function ( ) {
85+ if ( ! responseContainer ) {
86+ jQuery . error ( callbackName + " was not called" ) ;
87+ }
88+ return responseContainer [ 0 ] ;
89+ } ;
90+
91+ // Force json dataType
92+ s . dataTypes [ 0 ] = "json" ;
93+
94+ // Install callback
95+ overwritten = window [ callbackName ] ;
96+ window [ callbackName ] = function ( ) {
97+ responseContainer = arguments ;
98+ } ;
99+
100+ // Clean-up function (fires after converters)
101+ jqXHR . always ( function ( ) {
102+
103+ // If previous value didn't exist - remove it
104+ if ( overwritten === undefined ) {
105+ jQuery ( window ) . removeProp ( callbackName ) ;
106+
107+ // Otherwise restore preexisting value
108+ } else {
109+ window [ callbackName ] = overwritten ;
110+ }
111+
112+ // Save back as free
113+ if ( s [ callbackName ] ) {
114+
115+ // Make sure that re-using the options doesn't screw things around
116+ s . jsonpCallback = originalSettings . jsonpCallback ;
117+
118+ // Save the callback name for future use
119+ oldCallbacks . push ( callbackName ) ;
120+ }
121+
122+ // Call if it was a function and we have a response
123+ if ( responseContainer && typeof overwritten === "function" ) {
124+ overwritten ( responseContainer [ 0 ] ) ;
125+ }
126+
127+ responseContainer = overwritten = undefined ;
128+ } ) ;
129+
130+ // Delegate to script
131+ return "script" ;
132+ }
133+ } ) ;
134+ } else {
135+
136+ // jQuery <4 already contains this prefixer; don't duplicate the whole logic,
137+ // but only enough to know when to warn.
34138 jQuery . ajaxPrefilter ( "+json" , function ( s ) {
35139
140+ if ( ! jQuery . migrateIsPatchEnabled ( "jsonp-promotion" ) ) {
141+ return ;
142+ }
143+
36144 // Warn if JSON-to-JSONP auto-promotion happens.
37145 if ( s . jsonp !== false && ( rjsonp . test ( s . url ) ||
38146 typeof s . data === "string" &&
@@ -45,4 +153,12 @@ if ( !jQueryVersionSince( "4.0.0" ) ) {
45153 } ) ;
46154}
47155
156+
157+ // Don't trigger the above logic in jQuery >=4 by default as the JSON-to-JSONP
158+ // auto-promotion behavior is gone in jQuery 4.0 and as it has security implications,
159+ // we don't want to restore the legacy behavior by default.
160+ if ( jQueryVersionSince ( "4.0.0" ) ) {
161+ jQuery . migrateDisablePatches ( "jsonp-promotion" ) ;
162+ }
163+
48164}
0 commit comments