Merge "mediawiki.api: Use FormData for POST requests when supported"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 10 Apr 2014 19:19:01 +0000 (19:19 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 10 Apr 2014 19:19:01 +0000 (19:19 +0000)
resources/src/mediawiki.api/mediawiki.api.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js

index f300672..b37e2a6 100644 (file)
                        var token,
                                apiDeferred = $.Deferred(),
                                msg = 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.',
-                               xhr;
+                               xhr, key, formData;
 
                        parameters = $.extend( {}, this.defaults.parameters, parameters );
                        ajaxOptions = $.extend( {}, this.defaults.ajax, ajaxOptions );
                                token = parameters.token;
                                delete parameters.token;
                        }
-                       // Some deployed MediaWiki >= 1.17 forbid periods in URLs, due to an IE XSS bug
-                       // So let's escape them here. See bug #28235
-                       // This works because jQuery accepts data as a query string or as an Object
-                       ajaxOptions.data = $.param( parameters ).replace( /\./g, '%2E' );
-
-                       // If we extracted a token parameter, add it back in.
-                       if ( token ) {
-                               ajaxOptions.data += '&token=' + encodeURIComponent( token );
+
+                       // If multipart/form-data has been requested and emulation is possible, emulate it
+                       if (
+                               ajaxOptions.type === 'POST' &&
+                               window.FormData &&
+                               ajaxOptions.contentType === 'multipart/form-data'
+                       ) {
+
+                               formData = new FormData();
+
+                               for ( key in parameters ) {
+                                       formData.append( key, parameters[key] );
+                               }
+                               // If we extracted a token parameter, add it back in.
+                               if ( token ) {
+                                       formData.append( 'token', token );
+                               }
+
+                               ajaxOptions.data = formData;
+
+                               // Prevent jQuery from mangling our FormData object
+                               ajaxOptions.processData = false;
+                               // Prevent jQuery from overriding the Content-Type header
+                               ajaxOptions.contentType = false;
+                       } else {
+                               // Some deployed MediaWiki >= 1.17 forbid periods in URLs, due to an IE XSS bug
+                               // So let's escape them here. See bug #28235
+                               // This works because jQuery accepts data as a query string or as an Object
+                               ajaxOptions.data = $.param( parameters ).replace( /\./g, '%2E' );
+
+                               // If we extracted a token parameter, add it back in.
+                               if ( token ) {
+                                       ajaxOptions.data += '&token=' + encodeURIComponent( token );
+                               }
+
+                               if ( ajaxOptions.contentType === 'multipart/form-data' ) {
+                                       // We were asked to emulate but can't, so drop the Content-Type header, otherwise
+                                       // it'll be wrong and the server will fail to decode the POST body
+                                       delete ajaxOptions.contentType;
+                               }
                        }
 
                        // Backwards compatibility: Before MediaWiki 1.20,
index dab35f6..4ee8afa 100644 (file)
                } );
        } );
 
+       QUnit.test( 'FormData support', function ( assert ) {
+               QUnit.expect( 2 );
+
+               var api = new mw.Api();
+
+               api.post( { action: 'test' }, { contentType: 'multipart/form-data' } );
+
+               this.server.respond( function ( request ) {
+                       if ( window.FormData ) {
+                               assert.ok( !request.url.match( /action=/), 'Request has no query string' );
+                               assert.ok( request.requestBody instanceof FormData, 'Request uses FormData body' );
+                       } else {
+                               assert.ok( !request.url.match( /action=test/), 'Request has no query string' );
+                               assert.equal( request.requestBody, 'action=test&format=json', 'Request uses query string body' );
+                       }
+                       request.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
+               } );
+       } );
+
        QUnit.test( 'Deprecated callback methods', function ( assert ) {
                QUnit.expect( 3 );