mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Fix #11743: Don't mask script errors in jQuery.ajax, closes gh-795.
This commit is contained in:
parent
2d37b6ccb8
commit
742872984e
155
src/ajax.js
155
src/ajax.js
@ -319,6 +319,7 @@ jQuery.extend({
|
|||||||
username: null,
|
username: null,
|
||||||
password: null,
|
password: null,
|
||||||
cache: null,
|
cache: null,
|
||||||
|
throws: false,
|
||||||
traditional: false,
|
traditional: false,
|
||||||
headers: {},
|
headers: {},
|
||||||
*/
|
*/
|
||||||
@ -480,6 +481,8 @@ jQuery.extend({
|
|||||||
// It is defined here because jslint complains if it is declared
|
// It is defined here because jslint complains if it is declared
|
||||||
// at the end of the function (which would be more logical and readable)
|
// at the end of the function (which would be more logical and readable)
|
||||||
function done( status, nativeStatusText, responses, headers ) {
|
function done( status, nativeStatusText, responses, headers ) {
|
||||||
|
var isSuccess, success, error, response, modified,
|
||||||
|
statusText = nativeStatusText;
|
||||||
|
|
||||||
// Called once
|
// Called once
|
||||||
if ( state === 2 ) {
|
if ( state === 2 ) {
|
||||||
@ -504,13 +507,10 @@ jQuery.extend({
|
|||||||
// Set readyState
|
// Set readyState
|
||||||
jqXHR.readyState = status > 0 ? 4 : 0;
|
jqXHR.readyState = status > 0 ? 4 : 0;
|
||||||
|
|
||||||
var isSuccess,
|
// Get response data
|
||||||
success,
|
if ( responses ) {
|
||||||
error,
|
response = ajaxHandleResponses( s, jqXHR, responses );
|
||||||
statusText = nativeStatusText,
|
}
|
||||||
response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
|
|
||||||
lastModified,
|
|
||||||
etag;
|
|
||||||
|
|
||||||
// If successful, handle type chaining
|
// If successful, handle type chaining
|
||||||
if ( status >= 200 && status < 300 || status === 304 ) {
|
if ( status >= 200 && status < 300 || status === 304 ) {
|
||||||
@ -518,11 +518,13 @@ jQuery.extend({
|
|||||||
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
||||||
if ( s.ifModified ) {
|
if ( s.ifModified ) {
|
||||||
|
|
||||||
if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
|
modified = jqXHR.getResponseHeader("Last-Modified");
|
||||||
jQuery.lastModified[ ifModifiedKey ] = lastModified;
|
if ( modified ) {
|
||||||
|
jQuery.lastModified[ ifModifiedKey ] = modified;
|
||||||
}
|
}
|
||||||
if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
|
modified = jqXHR.getResponseHeader("Etag");
|
||||||
jQuery.etag[ ifModifiedKey ] = etag;
|
if ( modified ) {
|
||||||
|
jQuery.etag[ ifModifiedKey ] = modified;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,15 +537,11 @@ jQuery.extend({
|
|||||||
// If we have data
|
// If we have data
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
try {
|
isSuccess = ajaxConvert( s, response );
|
||||||
success = ajaxConvert( s, response );
|
statusText = isSuccess.state;
|
||||||
statusText = "success";
|
success = isSuccess.data;
|
||||||
isSuccess = true;
|
error = isSuccess.error;
|
||||||
} catch(e) {
|
isSuccess = !error;
|
||||||
// We have a parsererror
|
|
||||||
statusText = "parsererror";
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We extract error from statusText
|
// We extract error from statusText
|
||||||
@ -913,86 +911,87 @@ function ajaxHandleResponses( s, jqXHR, responses ) {
|
|||||||
// Chain conversions given the request and the original response
|
// Chain conversions given the request and the original response
|
||||||
function ajaxConvert( s, response ) {
|
function ajaxConvert( s, response ) {
|
||||||
|
|
||||||
|
var conv, conv2, current, tmp,
|
||||||
|
// Work with a copy of dataTypes in case we need to modify it for conversion
|
||||||
|
dataTypes = s.dataTypes.slice(),
|
||||||
|
prev = dataTypes[ 0 ],
|
||||||
|
converters = {},
|
||||||
|
i = 0;
|
||||||
|
|
||||||
// Apply the dataFilter if provided
|
// Apply the dataFilter if provided
|
||||||
if ( s.dataFilter ) {
|
if ( s.dataFilter ) {
|
||||||
response = s.dataFilter( response, s.dataType );
|
response = s.dataFilter( response, s.dataType );
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataTypes = s.dataTypes,
|
// Create converters map with lowercased keys
|
||||||
converters = {},
|
if ( dataTypes[ 1 ] ) {
|
||||||
i,
|
for ( conv in s.converters ) {
|
||||||
key,
|
converters[ conv.toLowerCase() ] = s.converters[ conv ];
|
||||||
length = dataTypes.length,
|
|
||||||
tmp,
|
|
||||||
// Current and previous dataTypes
|
|
||||||
current = dataTypes[ 0 ],
|
|
||||||
prev,
|
|
||||||
// Conversion expression
|
|
||||||
conversion,
|
|
||||||
// Conversion function
|
|
||||||
conv,
|
|
||||||
// Conversion functions (transitive conversion)
|
|
||||||
conv1,
|
|
||||||
conv2;
|
|
||||||
|
|
||||||
// For each dataType in the chain
|
|
||||||
for ( i = 1; i < length; i++ ) {
|
|
||||||
|
|
||||||
// Create converters map
|
|
||||||
// with lowercased keys
|
|
||||||
if ( i === 1 ) {
|
|
||||||
for ( key in s.converters ) {
|
|
||||||
if ( typeof key === "string" ) {
|
|
||||||
converters[ key.toLowerCase() ] = s.converters[ key ];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the dataTypes
|
// Convert to each sequential dataType, tolerating list modification
|
||||||
prev = current;
|
for ( ; (current = dataTypes[++i]); ) {
|
||||||
current = dataTypes[ i ];
|
|
||||||
|
|
||||||
// If current is auto dataType, update it to prev
|
// There's only work to do if current dataType is non-auto
|
||||||
if ( current === "*" ) {
|
if ( current !== "*" ) {
|
||||||
current = prev;
|
|
||||||
// If no auto and dataTypes are actually different
|
|
||||||
} else if ( prev !== "*" && prev !== current ) {
|
|
||||||
|
|
||||||
// Get the converter
|
// Convert response if prev dataType is non-auto and differs from current
|
||||||
conversion = prev + " " + current;
|
if ( prev !== "*" && prev !== current ) {
|
||||||
conv = converters[ conversion ] || converters[ "* " + current ];
|
|
||||||
|
|
||||||
// If there is no direct converter, search transitively
|
// Seek a direct converter
|
||||||
|
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
|
||||||
|
|
||||||
|
// If none found, seek a pair
|
||||||
if ( !conv ) {
|
if ( !conv ) {
|
||||||
conv2 = undefined;
|
for ( conv2 in converters ) {
|
||||||
for ( conv1 in converters ) {
|
|
||||||
tmp = conv1.split( " " );
|
// If conv2 outputs current
|
||||||
if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
|
tmp = conv2.split(" ");
|
||||||
conv2 = converters[ tmp[1] + " " + current ];
|
if ( tmp[ 1 ] === current ) {
|
||||||
if ( conv2 ) {
|
|
||||||
conv1 = converters[ conv1 ];
|
// If prev can be converted to accepted input
|
||||||
if ( conv1 === true ) {
|
conv = converters[ prev + " " + tmp[ 0 ] ] ||
|
||||||
conv = conv2;
|
converters[ "* " + tmp[ 0 ] ];
|
||||||
} else if ( conv2 === true ) {
|
if ( conv ) {
|
||||||
conv = conv1;
|
// Condense equivalence converters
|
||||||
|
if ( conv === true ) {
|
||||||
|
conv = converters[ conv2 ];
|
||||||
|
|
||||||
|
// Otherwise, insert the intermediate dataType
|
||||||
|
} else if ( converters[ conv2 ] !== true ) {
|
||||||
|
current = tmp[ 0 ];
|
||||||
|
dataTypes.splice( i--, 0, current );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we found no converter, dispatch an error
|
|
||||||
if ( !( conv || conv2 ) ) {
|
// Apply converter (if not an equivalence)
|
||||||
jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
|
|
||||||
}
|
|
||||||
// If found converter is not an equivalence
|
|
||||||
if ( conv !== true ) {
|
if ( conv !== true ) {
|
||||||
// Convert with 1 or 2 converters accordingly
|
|
||||||
response = conv ? conv( response ) : conv2( conv1(response) );
|
// Unless errors are allowed to bubble, catch and return them
|
||||||
|
if ( conv && s.throws ) {
|
||||||
|
response = conv( response );
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
response = conv( response );
|
||||||
|
} catch ( e ) {
|
||||||
|
return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response;
|
}
|
||||||
|
|
||||||
|
// Update prev for next iteration
|
||||||
|
prev = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { state: "success", data: response };
|
||||||
}
|
}
|
||||||
|
|
||||||
})( jQuery );
|
})( jQuery );
|
||||||
|
@ -343,11 +343,12 @@ jQuery.fn.extend({
|
|||||||
jQuery.each( scripts, function( i, elem ) {
|
jQuery.each( scripts, function( i, elem ) {
|
||||||
if ( elem.src ) {
|
if ( elem.src ) {
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
type: "GET",
|
|
||||||
global: false,
|
|
||||||
url: elem.src,
|
url: elem.src,
|
||||||
|
type: "GET",
|
||||||
|
dataType: "script",
|
||||||
async: false,
|
async: false,
|
||||||
dataType: "script"
|
global: false,
|
||||||
|
throws: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
|
jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
|
||||||
|
@ -1 +1 @@
|
|||||||
{bad: 1}
|
{bad: toTheBone}
|
||||||
|
@ -1746,6 +1746,28 @@ test("jQuery.ajax() - malformed JSON", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - script, throws exception (#11743)", function() {
|
||||||
|
expect(1);
|
||||||
|
|
||||||
|
raises(function() {
|
||||||
|
jQuery.ajax({
|
||||||
|
url: "data/badjson.js",
|
||||||
|
dataType: "script",
|
||||||
|
throws: true,
|
||||||
|
// TODO find a way to test this asynchronously, too
|
||||||
|
async: false,
|
||||||
|
// Global events get confused by the exception
|
||||||
|
global: false,
|
||||||
|
success: function() {
|
||||||
|
ok( false, "Success." );
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
ok( false, "Error." );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, "exception bubbled" );
|
||||||
|
});
|
||||||
|
|
||||||
test("jQuery.ajax() - script by content-type", function() {
|
test("jQuery.ajax() - script by content-type", function() {
|
||||||
expect(2);
|
expect(2);
|
||||||
|
|
||||||
|
@ -1796,3 +1796,17 @@ test("Ensure oldIE creates a new set on appendTo (#8894)", function() {
|
|||||||
strictEqual( jQuery("<bdi/>").clone().addClass("test").appendTo("<div/>").end().hasClass("test"), false, "Check jQuery.fn.appendTo after clone html5 element" );
|
strictEqual( jQuery("<bdi/>").clone().addClass("test").appendTo("<div/>").end().hasClass("test"), false, "Check jQuery.fn.appendTo after clone html5 element" );
|
||||||
strictEqual( jQuery("<p/>").appendTo("<div/>").end().length, jQuery("<p>test</p>").appendTo("<div/>").end().length, "Elements created with createElement and with createDocumentFragment should be treated alike" );
|
strictEqual( jQuery("<p/>").appendTo("<div/>").end().length, jQuery("<p>test</p>").appendTo("<div/>").end().length, "Elements created with createElement and with createDocumentFragment should be treated alike" );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("html() - script exceptions bubble (#11743)", function() {
|
||||||
|
expect(2);
|
||||||
|
|
||||||
|
raises(function() {
|
||||||
|
jQuery("#qunit-fixture").html("<script>undefined(); ok( false, 'error not thrown' );</script>");
|
||||||
|
ok( false, "error ignored" );
|
||||||
|
}, "exception bubbled from inline script" );
|
||||||
|
|
||||||
|
raises(function() {
|
||||||
|
jQuery("#qunit-fixture").html("<script src='data/badjson.js'></script>");
|
||||||
|
ok( false, "error ignored" );
|
||||||
|
}, "exception bubbled from remote script" );
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user