Skip to content

Commit

Permalink
Ajax: Don't treat array data as binary
Browse files Browse the repository at this point in the history
PR jquerygh-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.

Ref jquerygh-5197
  • Loading branch information
mgol committed Feb 6, 2023
1 parent 7e7bd06 commit 517a1e1
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 68 deletions.
3 changes: 2 additions & 1 deletion src/ajax/binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import "../ajax.js";
jQuery.ajaxPrefilter( function( s ) {

// 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 ) ) {
s.processData = false;
}

Expand Down
268 changes: 201 additions & 67 deletions test/unit/ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 [
{
url: baseURL + "name.html#foo",
Expand Down Expand Up @@ -429,6 +429,25 @@ QUnit.module( "ajax", {
},
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",
data: {
Expand Down Expand Up @@ -1489,43 +1508,92 @@ QUnit.module( "ajax", {
};
} );

ajaxTest( "jQuery.ajax() - JSON by content-type", 5, function( assert ) {
return {
url: baseURL + "mock.php?action=json",
data: {
"header": "json",
"array": "1"
ajaxTest( "jQuery.ajax() - JSON by content-type", 10, function( assert ) {
return [
{
url: baseURL + "mock.php?action=json",
data: {
"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" );
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" );
{
url: baseURL + "mock.php?action=json",
data: [
{
name: "header",
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 ) {
return {
url: url( "mock.php?action=json" ),
data: {
"header": "json",
"array": "1"
},
contents: {
"json": false
ajaxTest( "jQuery.ajax() - JSON by content-type disabled with options", 12, function( assert ) {
return [
{
url: url( "mock.php?action=json" ),
data: {
"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" );
}
},
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" );
{
url: url( "mock.php?action=json" ),
data: [
{
name: "header",
value: "json"
},
{
name: "array",
value: "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" );
}
}
};
];
} );

ajaxTest( "jQuery.ajax() - simple get", 1, function( assert ) {
Expand Down Expand Up @@ -1573,18 +1641,36 @@ QUnit.module( "ajax", {
};
} );

ajaxTest( "jQuery.ajax() - data - text/plain (gh-2658)", 1, function( assert ) {
return {
url: "bogus.html",
data: { devo: "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;
ajaxTest( "jQuery.ajax() - data - text/plain (gh-2658)", 2, function( assert ) {
return [
{
url: "bogus.html",
data: { devo: "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
},
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 ) {
Expand Down Expand Up @@ -1633,34 +1719,82 @@ QUnit.module( "ajax", {
};
} );

ajaxTest( "jQuery.ajax() - data - no processing POST", 1, function( assert ) {
return {
url: "bogus.html",
data: { devo: "A Beautiful World" },
type: "post",
contentType: "x-special-sauce",
processData: false,
beforeSend: function( _, s ) {
assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" );
return false;
ajaxTest( "jQuery.ajax() - data - no processing POST", 2, function( assert ) {
return [
{
url: "bogus.html",
data: { devo: "A Beautiful World" },
type: "post",
contentType: "x-special-sauce",
processData: false,
beforeSend: function( _, s ) {
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 ) {
return {
url: "bogus.html",
data: { devo: "A Beautiful World" },
type: "get",
contentType: "x-something-else",
processData: false,
beforeSend: function( _, s ) {
assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" );
return false;
ajaxTest( "jQuery.ajax() - data - no processing GET", 2, function( assert ) {
return [
{
url: "bogus.html",
data: { devo: "A Beautiful World" },
type: "get",
contentType: "x-something-else",
processData: false,
beforeSend: function( _, s ) {
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 ) {
Expand Down

0 comments on commit 517a1e1

Please sign in to comment.