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-qunit": "4.1.2",
|
||||||
"karma-webkit-launcher": "2.1.0",
|
"karma-webkit-launcher": "2.1.0",
|
||||||
"load-grunt-tasks": "5.1.0",
|
"load-grunt-tasks": "5.1.0",
|
||||||
|
"multiparty": "4.2.3",
|
||||||
"native-promise-only": "0.8.1",
|
"native-promise-only": "0.8.1",
|
||||||
"playwright-webkit": "1.29.2",
|
"playwright-webkit": "1.29.2",
|
||||||
"promises-aplus-tests": "2.1.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
|
// Convert data if not already a string
|
||||||
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
||||||
s.data = jQuery.param( s.data, s.traditional );
|
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 request was aborted inside a prefilter, stop there
|
||||||
if ( completed ) {
|
if ( completed ) {
|
||||||
return jqXHR;
|
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/xhr.js";
|
||||||
import "./ajax/script.js";
|
import "./ajax/script.js";
|
||||||
import "./ajax/jsonp.js";
|
import "./ajax/jsonp.js";
|
||||||
|
import "./ajax/binary.js";
|
||||||
import "./ajax/load.js";
|
import "./ajax/load.js";
|
||||||
import "./core/parseXML.js";
|
import "./core/parseXML.js";
|
||||||
import "./core/parseHTML.js";
|
import "./core/parseHTML.js";
|
||||||
|
@ -124,6 +124,17 @@ QUnit.assert.ok( true, "mock executed");';
|
|||||||
echo "$cleanCallback($text)\n";
|
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 ) {
|
protected function error( $req ) {
|
||||||
header( 'HTTP/1.0 400 Bad Request' );
|
header( 'HTTP/1.0 400 Bad Request' );
|
||||||
if ( isset( $req->query['json'] ) ) {
|
if ( isset( $req->query['json'] ) ) {
|
||||||
|
@ -174,8 +174,11 @@ function url( value ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ajax testing helper
|
// Ajax testing helper
|
||||||
this.ajaxTest = function( title, expect, options ) {
|
this.ajaxTest = function( title, expect, options, wrapper ) {
|
||||||
QUnit.test( title, function( assert ) {
|
if ( !wrapper ) {
|
||||||
|
wrapper = QUnit.test;
|
||||||
|
}
|
||||||
|
wrapper.call( QUnit, title, function( assert ) {
|
||||||
assert.expect( expect );
|
assert.expect( expect );
|
||||||
var requestOptions;
|
var requestOptions;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
const url = require( "url" );
|
const url = require( "url" );
|
||||||
const fs = require( "fs" );
|
const fs = require( "fs" );
|
||||||
const getRawBody = require( "raw-body" );
|
const getRawBody = require( "raw-body" );
|
||||||
|
const multiparty = require( "multiparty" );
|
||||||
|
|
||||||
let cspLog = "";
|
let cspLog = "";
|
||||||
|
|
||||||
@ -141,6 +142,19 @@ const mocks = {
|
|||||||
resp.writeHead( 200 );
|
resp.writeHead( 200 );
|
||||||
resp.end( `${ cleanCallback( callback ) }(${ JSON.stringify( body ) })\n` );
|
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 ) {
|
error: function( req, resp ) {
|
||||||
if ( req.query.json ) {
|
if ( req.query.json ) {
|
||||||
resp.writeHead( 400, { "content-type": "application/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;
|
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 );
|
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