{ "id": "151673", "key": "TIMOB-19661", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "14826", "description": "Release 5.1.0-remaining iOS9 features, Android M features", "name": "Release 5.1.0", "archived": false, "released": true, "releaseDate": "2015-11-20" }, { "id": "16996", "name": "Release 5.0.3", "archived": false, "released": true, "releaseDate": "2017-02-06" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2015-10-02T07:28:55.000+0000", "created": "2015-10-02T02:08:58.000+0000", "priority": { "name": "Medium", "id": "3" }, "labels": [ "android", "defect", "httpclient", "regression" ], "versions": [ { "id": "16778", "description": "Release 5.0.1", "name": "Release 5.0.1", "archived": false, "released": true, "releaseDate": "2015-09-25" }, { "id": "16904", "description": "Release 5.0.2", "name": "Release 5.0.2", "archived": true, "released": true, "releaseDate": "2015-10-01" }, { "id": "16925", "description": "WatchKit Support--all going into 5.0 now", "name": "Release 5.0.0", "archived": true, "released": true, "releaseDate": "2015-09-16" } ], "issuelinks": [ { "id": "49508", "type": { "id": "10122", "name": "Gantt: start-finish", "inward": "is triggered by", "outward": "is triggering" }, "outwardIssue": { "id": "151960", "key": "TIMOB-19817", "fields": { "summary": "Android: HTTPClient multipart header error", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "49453", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "152319", "key": "TIMOB-19784", "fields": { "summary": "Android: Cloud Files Create Error \"Invalid Name\"", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "updated": "2015-11-02T19:19:11.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "I am unable to upload data to a remote server using the HTTPClient on Titanium SDK 5.0.0 GA. The same code works correctly on SDK 4.1.0 GA.\r\n\r\nThe data object that is sent to HTTPClient looks like this:\r\n\r\n{code:javascript}\r\n\r\n var data = {\r\n \"entry.id\": entryBean.id\r\n , \"_eventName\": \"uploadPhoto\"\r\n , \"imageData\": selectedImage\r\n , \"caption\": $.caption.value\r\n , \"fileName\": getFileNameFrom(selectedImage)\r\n };\r\n\r\n{code}\r\n\r\nWhere {{imageData}} is a photo selected from the device. \r\n\r\nOn the server, it seemed like the imageData was coming through, but nothing else: {{entry.id}}, {{_eventName}}, {{caption}}, and {{fileName}} were no populated on my server-side form.\r\n\r\nIn an effort to help debug the issue, I dumped the \"raw\" incoming POST data to the server console. The results looked something like this:\r\n\r\n\r\n\r\n{code:java}\r\n--4UVkNoCkrozvPT0TuugeoVAr0YbFCJ\r\nContent-Disposition: form-data; name=\"_eventName\r\nContent-Type: ; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\nuploadPhoto\r\n--4UVkNoCkrozvPT0TuugeoVAr0YbFCJ\r\nContent-Disposition: form-data; name=\"fileName\r\nContent-Type: ; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\nIMAG0527.jpg\r\n--4UVkNoCkrozvPT0TuugeoVAr0YbFCJ\r\nContent-Disposition: form-data; name=\"entry.id\r\nContent-Type: ; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\nO1wJEoXb1lfhdYfwkn38UawovA4pG6hHecZ6DGv2-Wx0Ww-rmjihfM41D4jyCXs4\r\n--4UVkNoCkrozvPT0TuugeoVAr0YbFCJ\r\nContent-Disposition: form-data; name=\"imageData\"; filename=\"tixhr-1575133492.jpeg\"\r\nContent-Type: image/jpeg\r\nContent-Transfer-Encoding: binary\r\n\r\n(lots of binary data for the image)\r\n\r\n--4UVkNoCkrozvPT0TuugeoVAr0YbFCJ\r\nContent-Disposition: form-data; name=\"caption\r\nContent-Type: ; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\nfinal.\r\n--4UVkNoCkrozvPT0TuugeoVAr0YbFCJ--\r\n\r\n{code}\r\n\r\n\r\n\r\nI immediately saw the problem. Note how for the non-binary fields, such as {{_eventName}} at the top, the right quote is missing at the end of the name value. \r\n\r\nThis explains why my web framework was unable to correctly populate the data model with the form data; it was unable to read it due to the missing double quote.\r\n\r\nThis is a new regression from 4.1.0. It works correctly if I use the 4.1.0 SDK.\r\n\r\nFor those who are seeing this bug, one possible work around is to convert the file to be uploaded to a base64 encoded string. This is how my example from above updated to use a base64 encoded string:\r\n\r\n\r\n{code:javascript}\r\n\r\n var data = {\r\n \"entry.id\": entryBean.id\r\n , \"_eventName\": \"uploadPhoto\"\r\n // , \"imageData\": selectedImage\r\n , encodedImage: Ti.Utils.base64encode(selectedImage).toString()\r\n , \"caption\": $.caption.value\r\n , \"fileName\": getFileNameFrom(selectedImage)\r\n };\r\n\r\n{code}\r\n\r\nOf course, this only works if you also control the server-side and can handle the base64 encoded file appropriately.\r\n\r\n", "attachment": [], "flagged": false, "summary": "Android: 5.0.0 GA SDK HTTPClient Fails to POST Form Data with File Correctly", "creator": { "name": "ryan@asleson.net", "key": "ryan@asleson.net", "displayName": "Ryan Asleson", "active": true, "timeZone": "America/Chicago" }, "subtasks": [], "reporter": { "name": "ryan@asleson.net", "key": "ryan@asleson.net", "displayName": "Ryan Asleson", "active": true, "timeZone": "America/Chicago" }, "environment": "Android, Titanium SDK 5.0.0 GA", "closedSprints": [ { "id": 494, "state": "closed", "name": "2015 Sprint 20 SDK", "startDate": "2015-09-26T00:29:19.845Z", "endDate": "2015-10-10T00:29:00.000Z", "completeDate": "2015-10-12T05:33:30.964Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "365621", "author": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "body": "[~ryan@asleson.net] Thanks for the detailed investigation and ticket. It helps a lot in understanding the problem and getting it fix fast! :)\r\n\r\nWill look into this now.", "updateAuthor": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "created": "2015-10-02T06:45:21.000+0000", "updated": "2015-10-02T06:45:21.000+0000" }, { "id": "365624", "author": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "body": "Master PR: https://github.com/appcelerator/titanium_mobile/pull/7263\r\n5_0_X PR: https://github.com/appcelerator/titanium_mobile/pull/7264", "updateAuthor": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "created": "2015-10-02T06:58:36.000+0000", "updated": "2015-10-02T06:58:36.000+0000" }, { "id": "365625", "author": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "body": "Test code:\r\n{code}\r\nvar url = \"http://httpbin.org/post\";\r\nvar data = {\r\n \"entry.id\": \"data\"\r\n , \"_eventName\": \"name\"\r\n , \"caption\": \"the caption\"\r\n , \"fileName\": \"Name of file\"\r\n};\r\n\r\nvar xhr = Ti.Network.createHTTPClient();\r\n xhr.onload = function (event) {\r\n Ti.API.info(\"Received text: \" + this.responseText);\r\n alert('success');\r\n };\r\n xhr.onerror = function (event) {\r\n Ti.API.debug(e.error);\r\n alert('error');\r\n };\r\n xhr.url = url;\r\n xhr.open(\"POST\", url);\r\n xhr.send(data);\r\n{code}", "updateAuthor": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "created": "2015-10-02T07:20:08.000+0000", "updated": "2015-10-02T07:20:08.000+0000" }, { "id": "365629", "author": { "name": "cng", "key": "cng", "displayName": "Chee Kiat Ng", "active": false, "timeZone": "America/Los_Angeles" }, "body": "APPROVED. PRs merged.", "updateAuthor": { "name": "cng", "key": "cng", "displayName": "Chee Kiat Ng", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2015-10-02T07:28:46.000+0000", "updated": "2015-10-02T07:28:46.000+0000" }, { "id": "368682", "author": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Verified the fix.\r\nPOST happens successfully with file.\r\n\r\nClosing.\r\n\r\nEnvironment:\r\nAppc Studio : 4.4.0.201510290507\r\nTi SDK : 5.1.0.v20151028190028, 5.0.3.v20151028143139\r\nTi CLI : 5.0.5\r\nAlloy : 1.7.18\r\nMAC Yosemite : 10.10.5\r\nAppc NPM : 4.2.1-6\r\nAppc CLI : 5.1.0-38\r\nNode: v0.10.37\r\nNexus 5 - Android 6.0", "updateAuthor": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2015-11-02T19:18:42.000+0000", "updated": "2015-11-02T19:19:06.000+0000" } ], "maxResults": 5, "total": 5, "startAt": 0 } } }