mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Ajax: Support binary data (including FormData)
Two changes have been applied: * prefilters are now applied before data is converted to a string; this allows prefilters to disable such a conversion * a prefilter for binary data is added; it disables data conversion for non-string non-plain-object `data`; for `FormData` bodies, it removes manually-set `Content-Type` header - this is required as browsers need to append their own boundary to the header Ref gh-4150 Closes gh-5197
This commit is contained in:
parent
0b9c5037f7
commit
a7ed9a7b63
@ -55,6 +55,7 @@
|
||||
"karma-qunit": "4.1.2",
|
||||
"karma-webkit-launcher": "2.1.0",
|
||||
"load-grunt-tasks": "5.1.0",
|
||||
"multiparty": "4.2.3",
|
||||
"native-promise-only": "0.8.1",
|
||||
"playwright-webkit": "1.29.2",
|
||||
"promises-aplus-tests": "2.1.2",
|
||||
|
@ -562,14 +562,14 @@ jQuery.extend( {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply prefilters
|
||||
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
|
||||
|
||||
// Convert data if not already a string
|
||||
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
||||
s.data = jQuery.param( s.data, s.traditional );
|
||||
}
|
||||
|
||||
// Apply prefilters
|
||||
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
|
||||
|
||||
// If request was aborted inside a prefilter, stop there
|
||||
if ( completed ) {
|
||||
return jqXHR;
|
||||
|
17
src/ajax/binary.js
Normal file
17
src/ajax/binary.js
Normal file
@ -0,0 +1,17 @@
|
||||
import jQuery from "../core.js";
|
||||
|
||||
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 ) ) {
|
||||
s.processData = false;
|
||||
}
|
||||
|
||||
// `Content-Type` for requests with `FormData` bodies needs to be set
|
||||
// by the browser as it needs to append the `boundary` it generated.
|
||||
if ( s.data instanceof window.FormData ) {
|
||||
s.contentType = false;
|
||||
}
|
||||
} );
|
1
src/jquery.js
vendored
1
src/jquery.js
vendored
@ -23,6 +23,7 @@ import "./ajax.js";
|
||||
import "./ajax/xhr.js";
|
||||
import "./ajax/script.js";
|
||||
import "./ajax/jsonp.js";
|
||||
import "./ajax/binary.js";
|
||||
import "./ajax/load.js";
|
||||
import "./core/parseXML.js";
|
||||
import "./core/parseHTML.js";
|
||||
|
@ -124,6 +124,17 @@ QUnit.assert.ok( true, "mock executed");';
|
||||
echo "$cleanCallback($text)\n";
|
||||
}
|
||||
|
||||
protected function formData( $req ) {
|
||||
$prefix = 'multipart/form-data; boundary=--';
|
||||
$contentTypeValue = $req->headers[ 'CONTENT-TYPE' ];
|
||||
if ( substr( $contentTypeValue, 0, strlen( $prefix ) ) === $prefix ) {
|
||||
echo 'key1 -> ' . $_POST[ 'key1' ] . ', key2 -> ' . $_POST[ 'key2' ];
|
||||
} else {
|
||||
echo 'Incorrect Content-Type: ' . $contentTypeValue .
|
||||
"\nExpected prefix: " . $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
protected function error( $req ) {
|
||||
header( 'HTTP/1.0 400 Bad Request' );
|
||||
if ( isset( $req->query['json'] ) ) {
|
||||
|
@ -174,8 +174,11 @@ function url( value ) {
|
||||
}
|
||||
|
||||
// Ajax testing helper
|
||||
this.ajaxTest = function( title, expect, options ) {
|
||||
QUnit.test( title, function( assert ) {
|
||||
this.ajaxTest = function( title, expect, options, wrapper ) {
|
||||
if ( !wrapper ) {
|
||||
wrapper = QUnit.test;
|
||||
}
|
||||
wrapper.call( QUnit, title, function( assert ) {
|
||||
assert.expect( expect );
|
||||
var requestOptions;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
const url = require( "url" );
|
||||
const fs = require( "fs" );
|
||||
const getRawBody = require( "raw-body" );
|
||||
const multiparty = require( "multiparty" );
|
||||
|
||||
let cspLog = "";
|
||||
|
||||
@ -141,6 +142,19 @@ const mocks = {
|
||||
resp.writeHead( 200 );
|
||||
resp.end( `${ cleanCallback( callback ) }(${ JSON.stringify( body ) })\n` );
|
||||
},
|
||||
formData: function( req, resp, next ) {
|
||||
const prefix = "multipart/form-data; boundary=--";
|
||||
const contentTypeValue = req.headers[ "content-type" ];
|
||||
resp.writeHead( 200 );
|
||||
if ( ( prefix || "" ).startsWith( prefix ) ) {
|
||||
getMultiPartContent( req ).then( function( { fields = {} } ) {
|
||||
resp.end( `key1 -> ${ fields.key1 }, key2 -> ${ fields.key2 }` );
|
||||
}, next );
|
||||
} else {
|
||||
resp.end( `Incorrect Content-Type: ${ contentTypeValue
|
||||
}\nExpected prefix: ${ prefix }` );
|
||||
}
|
||||
},
|
||||
error: function( req, resp ) {
|
||||
if ( req.query.json ) {
|
||||
resp.writeHead( 400, { "content-type": "application/json" } );
|
||||
@ -363,4 +377,18 @@ function getBody( req ) {
|
||||
} );
|
||||
}
|
||||
|
||||
function getMultiPartContent( req ) {
|
||||
return new Promise( function( resolve ) {
|
||||
if ( req.method !== "POST" ) {
|
||||
resolve( "" );
|
||||
return;
|
||||
}
|
||||
|
||||
const form = new multiparty.Form();
|
||||
form.parse( req, function( _err, fields, files ) {
|
||||
resolve( { fields, files } );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
module.exports = MockserverMiddlewareFactory;
|
||||
|
@ -3105,4 +3105,47 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re
|
||||
assert.ok( jQuery.active === 0, "ajax active counter should be zero: " + jQuery.active );
|
||||
} );
|
||||
|
||||
ajaxTest( "jQuery.ajax() - FormData", 1, function( assert ) {
|
||||
var formData = new FormData();
|
||||
formData.append( "key1", "value1" );
|
||||
formData.append( "key2", "value2" );
|
||||
|
||||
return {
|
||||
url: url( "mock.php?action=formData" ),
|
||||
method: "post",
|
||||
data: formData,
|
||||
success: function( data ) {
|
||||
assert.strictEqual( data, "key1 -> value1, key2 -> value2",
|
||||
"FormData sent correctly" );
|
||||
}
|
||||
};
|
||||
} );
|
||||
|
||||
ajaxTest( "jQuery.ajax() - URLSearchParams", 1, function( assert ) {
|
||||
var urlSearchParams = new URLSearchParams();
|
||||
urlSearchParams.append( "name", "peter" );
|
||||
|
||||
return {
|
||||
url: url( "mock.php?action=name" ),
|
||||
method: "post",
|
||||
data: urlSearchParams,
|
||||
success: function( data ) {
|
||||
assert.strictEqual( data, "pan", "URLSearchParams sent correctly" );
|
||||
}
|
||||
};
|
||||
}, QUnit.testUnlessIE );
|
||||
|
||||
ajaxTest( "jQuery.ajax() - Blob", 1, function( assert ) {
|
||||
var blob = new Blob( [ "name=peter" ], { type: "text/plain" } );
|
||||
|
||||
return {
|
||||
url: url( "mock.php?action=name" ),
|
||||
method: "post",
|
||||
data: blob,
|
||||
success: function( data ) {
|
||||
assert.strictEqual( data, "pan", "Blob sent correctly" );
|
||||
}
|
||||
};
|
||||
} );
|
||||
|
||||
} )();
|
||||
|
Loading…
Reference in New Issue
Block a user