Titanium JIRA Archive
Appcelerator Community (AC)

[AC-1709] HttpClient.send() changes order of POST values

GitHub Issuen/a
TypeBug
Priorityn/a
StatusClosed
ResolutionCannot Reproduce
Resolution Date2016-01-31T06:54:40.000+0000
Affected Version/sn/a
Fix Version/sn/a
ComponentsTitanium SDK & CLI
LabelsHttpClient
ReporterStephen Ostrow
AssigneeShak Hossain
Created2016-01-22T06:04:22.000+0000
Updated2016-03-08T07:38:12.000+0000

Description

HttpClient.send() does not respect the order of the array of data given to it. When using a pre-authorized POST url for Amazon's AWS S3 the order of the POST fields matters. For instance
var httpClient = Ti.Network.createHTTPClient({
						onload: function(e) {
							Ti.API.info("Upload file responseText: " + this.responseText);
		    				_encodedFilename = awsPolicyFields.formInputs.key;
		                    callback(true);
						},
			            onerror : function(e) {
	            			Ti.API.error("Error uploading file: " + e.error);
							Ti.API.debug("Upload file responseText: " + this.responseText);
			               	callback(false);
			            },
					    onsendstream : function(e) {  
					        var progress = parseFloat(e.progress);
					        Ti.API.trace("Upload progress: " + (progress * 100));
					        Ti.App.fireEvent('progress_update', {'progress' : progress});
					    },
			            validatesSecureCertificate : _validatesSSL
					});
					
					var args = {
						'key': awsPolicyFields.formInputs['key'],
						'policy' : awsPolicyFields.formInputs['policy'],
						'signature' : awsPolicyFields.formInputs['signature'],
						'AWSAccessKeyId' : awsPolicyFields.formInputs['AWSAccessKeyId'],
						'success_action_status' : awsPolicyFields.formInputs['success_action_status'],
						'x-amz-server-side-encryption' : awsPolicyFields.formInputs['x-amz-server-side-encryption'],
						'Content-Type' : awsPolicyFields.formInputs['Content-Type'],
						'file' : videoFile,
					};
					
					httpClient.open(awsPolicyFields.formAttributes.method, awsPolicyFields.formAttributes.action);
					httpClient.send(args);
			        networkManager.addRequest(httpClient);
sent the following request
=============== New Request at 2016-01-22T03:02:08+00:00 ===================
POST /endpoint
x-newrelic-id: XXXXXXXXXXXX=
Accept-Encoding: identity
X-Titanium-Id: XXXXXXXXXXXXXXXXXXXX
Content-Type: multipart/form-data; boundary=j6FN2IMH7hRNiksUXnkOufIDEOdD4CH9jEHbdh
X-Requested-With: XMLHttpRequest
User-Agent: Appcelerator Titanium/5.1.2 (Android SDK built for x86_64; Android API Level: 22; en-US;)
Host: example.org
Connection: Keep-Alive
Content-Length: 279029
--------------------- php://input -----------------
--------------------- $_POST -----------------
AWSAccessKeyId: XXXXXXXXXXXXX
Content-Type: video/mp4
key: keydir/XXXXXX/sadfsdaf.mp4
signature: a+TJ/dJX/ei76vm4EURakrg7q+s=
policy: eyJleHBpcmF0aW9uIjoiMjAxNi0wMS0yMlQwNDowMTo0NloiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJXXXXXXXXXXXXXXXXXXXXXXvbl9zdGF0dXMiOiIyMDAifSx7ImtleSI6ImRlbW9cL2Z0cF91cGxvYWRzXC84LWdlbmVyYWwtbWFuYWdlclwvc2FkZnNkYWYubXA0In0seyJ4LWXXXXXXXXXXXXXXXXXXXB0aW9uIjoiQUVTMjU2In0seyJDb250ZW50LVR5cGUiOiJ2aWRlb1wvbXA0In1dfQ==
success_action_status: 200
x-amz-server-side-encryption: AES256
--------------------- $_FILE -----------------
file:
array (
  'name' => 'VID_20160121_220135.mp4',
  'type' => 'application/octet-stream',
  'tmp_name' => '/tmp/phpOI761z',
  'error' => 0,
  'size' => 277413,
)

Comments

  1. Stephen Ostrow 2016-01-22

    I believe this is due to ti.modules.titanium.network.TiHTTPClient using a HashMap for parts https://github.com/appcelerator/titanium_mobile/blob/master/android/modules/network/src/java/ti/modules/titanium/network/TiHTTPClient.java#L139 A HashMap does not guarantee ordering and it appears every time you add to it you mach the ordering of it.
  2. Jebun Naher 2016-01-27

    Hello, I tried to test the ordering of the post data using below code but couldn't reproduce it. It would be helpful if you attach a complete test code and steps to reproduce this issue. *Testing Environment:* Appcelerator Studio, build: 4.4.0.201511241829 Appcelerator Command-Line Interface, version 5.1.0 Titanium Command-Line Interface, CLI version 5.0.5, Titanium SDK version : 5.1.2 GA Mac OS X : 10.11.1 (EI Capitan) Node.js Version = 0.12.7 Java Development Kit= 1.7.0_65 VirtualBox Version = 4.3.28r100309 *Test Code:* index.xml
       <Alloy>
       	<Window id="todoWin" title="Todo" platform="android,ios">
       		<Button id="button" onClick="postData">
       			Post
       		</Button>
       	</Window>
       </Alloy>
       
    index.js
       $.todoWin.open();
       function postData() {
       var xhr = Ti.Network.createHTTPClient({
       		onload : function() {
       			Ti.API.info("STATUS: " + this.status);
       			alert("TEXT:   " + this.responseText);
       			//json = JSON.parse(this.responseText);
       },
       		onerror : function(e) {
       			Ti.API.info("STATUS: " + this.status);
       			Ti.API.info("TEXT:   " + this.responseText);
       			Ti.API.info("ERROR:  " + e.error);
       			alert(L('network_problem'));
       		},
       		timeout : 50000
       	});
       var data = {
       		Name : 'username',
       		password : 'password',
       		city : 'select city',
       		country : 'select country',
       		order : 'order 1'
       	};
       	alert('data' + JSON.stringify(data));
       	xhr.open('POST', encodeURI('http://localhost/Test/postdata.php'));
       	xhr.setRequestHeader('Content-Type', 'application/json');
       	xhr.send(JSON.stringify(data));
       }
       
    postdata.php
       <?php
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
               $params = file_get_contents('php://input');
               $params = json_decode(str_replace('\"', '"', $params));
                 echo json_encode($params);
              
           } else {
               echo json_encode((object) array('error' => 'invalid verb'));
           } 
       ?>
       
    *Output:*
       {"Name":"username","password":"password","city":"select city","country":"select country","order":"order 1"}
       
    Thanks.

JSON Source