Ajax: Don't treat array data as binary

PR gh-5197 started treating all non-string non-plain-object
`data` values as binary. However, `jQuery.ajax` also supports
arrays as values of `data`. This change makes regular arrays
no longer be considered binary data.

Surprisingly, we had no tests for array `data` values; otherwise,
we'd detect the issue earlier. This change also adds
a few such missing tests.

Closes gh-5203
Ref gh-5197
This commit is contained in:
Michał Gołębiowski-Owczarek 2023-03-21 00:36:00 +01:00 committed by GitHub
parent e77bd9d64f
commit 992a1911d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 202 additions and 67 deletions

View File

@ -6,6 +6,7 @@ jQuery.ajaxPrefilter( function( s, origOptions ) {
// Binary data needs to be passed to XHR as-is without stringification. // Binary data needs to be passed to XHR as-is without stringification.
if ( typeof s.data !== "string" && !jQuery.isPlainObject( s.data ) && if ( typeof s.data !== "string" && !jQuery.isPlainObject( s.data ) &&
!Array.isArray( s.data ) &&
// Don't disable data processing if explicitly set by the user. // Don't disable data processing if explicitly set by the user.
!( "processData" in origOptions ) ) { !( "processData" in origOptions ) ) {

View File

@ -397,7 +397,7 @@ QUnit.module( "ajax", {
}; };
} ); } );
ajaxTest( "jQuery.ajax() - URL fragment component preservation", 4, function( assert ) { ajaxTest( "jQuery.ajax() - URL fragment component preservation", 5, function( assert ) {
return [ return [
{ {
url: baseURL + "name.html#foo", url: baseURL + "name.html#foo",
@ -429,6 +429,25 @@ QUnit.module( "ajax", {
}, },
error: true error: true
}, },
{
url: baseURL + "name.html?abc#foo",
data: [
{
name: "test",
value: 123
},
{
name: "devo",
value: "hat"
}
],
beforeSend: function( xhr, settings ) {
assert.equal( settings.url, baseURL + "name.html?abc&test=123&devo=hat#foo",
"hash preserved for request with query component and array data." );
return false;
},
error: true
},
{ {
url: baseURL + "name.html?abc#brownies", url: baseURL + "name.html?abc#brownies",
data: { data: {
@ -1489,43 +1508,92 @@ QUnit.module( "ajax", {
}; };
} ); } );
ajaxTest( "jQuery.ajax() - JSON by content-type", 5, function( assert ) { ajaxTest( "jQuery.ajax() - JSON by content-type", 10, function( assert ) {
return { return [
url: baseURL + "mock.php?action=json", {
data: { url: baseURL + "mock.php?action=json",
"header": "json", data: {
"array": "1" "header": "json",
"array": "1"
},
success: function( json ) {
assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" );
}
}, },
success: function( json ) { {
assert.ok( json.length >= 2, "Check length" ); url: baseURL + "mock.php?action=json",
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); data: [
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); {
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); name: "header",
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); value: "json"
},
{
name: "array",
value: "1"
}
],
success: function( json ) {
assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" );
}
} }
}; ];
} ); } );
ajaxTest( "jQuery.ajax() - JSON by content-type disabled with options", 6, function( assert ) { ajaxTest( "jQuery.ajax() - JSON by content-type disabled with options", 12, function( assert ) {
return { return [
url: url( "mock.php?action=json" ), {
data: { url: url( "mock.php?action=json" ),
"header": "json", data: {
"array": "1" "header": "json",
"array": "1"
},
contents: {
"json": false
},
success: function( text ) {
assert.strictEqual( typeof text, "string", "json wasn't auto-determined" );
var json = JSON.parse( text );
assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" );
}
}, },
contents: { {
"json": false url: url( "mock.php?action=json" ),
}, data: [
success: function( text ) { {
assert.strictEqual( typeof text, "string", "json wasn't auto-determined" ); name: "header",
var json = JSON.parse( text ); value: "json"
assert.ok( json.length >= 2, "Check length" ); },
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" ); {
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" ); name: "array",
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" ); value: "1"
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" ); }
],
contents: {
"json": false
},
success: function( text ) {
assert.strictEqual( typeof text, "string", "json wasn't auto-determined" );
var json = JSON.parse( text );
assert.ok( json.length >= 2, "Check length" );
assert.strictEqual( json[ 0 ][ "name" ], "John", "Check JSON: first, name" );
assert.strictEqual( json[ 0 ][ "age" ], 21, "Check JSON: first, age" );
assert.strictEqual( json[ 1 ][ "name" ], "Peter", "Check JSON: second, name" );
assert.strictEqual( json[ 1 ][ "age" ], 25, "Check JSON: second, age" );
}
} }
}; ];
} ); } );
ajaxTest( "jQuery.ajax() - simple get", 1, function( assert ) { ajaxTest( "jQuery.ajax() - simple get", 1, function( assert ) {
@ -1573,18 +1641,36 @@ QUnit.module( "ajax", {
}; };
} ); } );
ajaxTest( "jQuery.ajax() - data - text/plain (gh-2658)", 1, function( assert ) { ajaxTest( "jQuery.ajax() - data - text/plain (gh-2658)", 2, function( assert ) {
return { return [
url: "bogus.html", {
data: { devo: "A Beautiful World" }, url: "bogus.html",
type: "post", data: { devo: "A Beautiful World" },
contentType: "text/plain", type: "post",
beforeSend: function( _, s ) { contentType: "text/plain",
assert.strictEqual( s.data, "devo=A%20Beautiful%20World", "data is %20-encoded" ); beforeSend: function( _, s ) {
return false; assert.strictEqual( s.data, "devo=A%20Beautiful%20World", "data is %20-encoded" );
return false;
},
error: true
}, },
error: true {
}; url: "bogus.html",
data: [
{
name: "devo",
value: "A Beautiful World"
}
],
type: "post",
contentType: "text/plain",
beforeSend: function( _, s ) {
assert.strictEqual( s.data, "devo=A%20Beautiful%20World", "data is %20-encoded" );
return false;
},
error: true
}
];
} ); } );
ajaxTest( "jQuery.ajax() - don't escape %20 with contentType override (gh-4119)", 1, function( assert ) { ajaxTest( "jQuery.ajax() - don't escape %20 with contentType override (gh-4119)", 1, function( assert ) {
@ -1633,34 +1719,82 @@ QUnit.module( "ajax", {
}; };
} ); } );
ajaxTest( "jQuery.ajax() - data - no processing POST", 1, function( assert ) { ajaxTest( "jQuery.ajax() - data - no processing POST", 2, function( assert ) {
return { return [
url: "bogus.html", {
data: { devo: "A Beautiful World" }, url: "bogus.html",
type: "post", data: { devo: "A Beautiful World" },
contentType: "x-special-sauce", type: "post",
processData: false, contentType: "x-special-sauce",
beforeSend: function( _, s ) { processData: false,
assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" ); beforeSend: function( _, s ) {
return false; assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" );
return false;
},
error: true
}, },
error: true {
}; url: "bogus.html",
data: [
{
name: "devo",
value: "A Beautiful World"
}
],
type: "post",
contentType: "x-special-sauce",
processData: false,
beforeSend: function( _, s ) {
assert.deepEqual( s.data, [
{
name: "devo",
value: "A Beautiful World"
}
], "data is not processed" );
return false;
},
error: true
}
];
} ); } );
ajaxTest( "jQuery.ajax() - data - no processing GET", 1, function( assert ) { ajaxTest( "jQuery.ajax() - data - no processing GET", 2, function( assert ) {
return { return [
url: "bogus.html", {
data: { devo: "A Beautiful World" }, url: "bogus.html",
type: "get", data: { devo: "A Beautiful World" },
contentType: "x-something-else", type: "get",
processData: false, contentType: "x-something-else",
beforeSend: function( _, s ) { processData: false,
assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" ); beforeSend: function( _, s ) {
return false; assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" );
return false;
},
error: true
}, },
error: true {
}; url: "bogus.html",
data: [
{
name: "devo",
value: "A Beautiful World"
}
],
type: "get",
contentType: "x-something-else",
processData: false,
beforeSend: function( _, s ) {
assert.deepEqual( s.data, [
{
name: "devo",
value: "A Beautiful World"
}
], "data is not processed" );
return false;
},
error: true
}
];
} ); } );
ajaxTest( "jQuery.ajax() - data - process string with GET", 2, function( assert ) { ajaxTest( "jQuery.ajax() - data - process string with GET", 2, function( assert ) {