{ "id": "90905", "key": "TIMOB-8906", "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": "13417", "description": "Sprint 2012-13 API", "name": "Sprint 2012-13 API", "archived": true, "released": true, "releaseDate": "2012-07-01" }, { "id": "13505", "description": "Release 3.0.0", "name": "Release 3.0.0", "archived": true, "released": true, "releaseDate": "2012-12-14" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2012-06-29T17:26:22.000+0000", "created": "2012-04-26T00:06:53.000+0000", "priority": { "name": "Medium", "id": "3" }, "labels": [ "api", "httpclient", "parity", "qe-port" ], "versions": [], "issuelinks": [ { "id": "17685", "type": { "id": "10002", "name": "Duplicate", "inward": "is duplicated by", "outward": "duplicates" }, "inwardIssue": { "id": "92869", "key": "TIMOB-9411", "fields": { "summary": "Android:Network:createHttpClient cannot handle Japanese Shift_JIS and EUC-JP encoding", "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": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2013-01-15T16:54:03.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": "h1. Problem\r\n\r\nTo determine the character encoding, determining sequence is as follows:\r\n\r\n* HTTP Header (Content-type: text/html; charset=utf-8)\r\n* HTML meta tag (meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\")\r\n\r\niOS handring is correct, but Android ignores HTML meta tag encoding name.\r\n\r\nh1. Test Case\r\n\r\nI make a sample code which accesses each charset sample webpage and display their results.\r\n{code:js}\r\nvar win1 = Ti.UI.createWindow({\r\n\tbackgroundColor: 'white',\r\n});\r\nvar text = Ti.UI.createLabel({\r\n\ttext: '',\r\n});\r\nwin1.add(text);\r\nwin1.open();\r\ncharsetTest(\"http://kangaechu.com/utf8.html\");\r\ncharsetTest(\"http://kangaechu.com/shiftjis.html\");\r\ncharsetTest(\"http://kangaechu.com/eucjp.html\");\r\ncharsetTest(\"http://kangaechu.com/iso2022jp.html\");\r\n\r\nfunction charsetTest(url){\r\n\tvar xhr = Ti.Network.createHTTPClient();\r\n\t\r\n\txhr.onload = function() {\r\n\t\tif(this.status == 200) {\r\n\t\t\tvar html = this.responseText;\r\n\t\t\tif(html == null){\r\n\t\t\t\ttext.text = text.text + url + ' is null.\\n\\n';\r\n\t\t\t}\r\n\t\t\telse if(html.match(/([\\s\\S]*)<\\/body>/)){\r\n\t\t\t\tvar body = RegExp.$1;\r\n\t\t\t\ttext.text = text.text + url + body;\r\n\t\t\t}else{\r\n\t\t\t\ttext.text = text.text + url + ' is 200, but no body element.\\n\\n';\r\n\t\t\t}\r\n\t\t}else{\r\n\t\t\ttext.text = text.text + url + ' status code is ' + this.status + '\\n\\n';\r\n\t\t}\r\n\t};\r\n\txhr.onerror = function() {\r\n\t\ttext.text = text.text + url + ' status code is ' + this.status + '\\n\\n';\r\n\r\n\t};\r\n\txhr.open(\"GET\", url, false);\r\n\txhr.send();\r\n\t\r\n}\r\n{code} \r\nResult and screenshot is below:\r\n||OS||UTF-8||Shift_JIS||EUC-JP||ISO-2022-JP||\r\n|Android|OK|NG|NG|NG|\r\n\r\nh1. Suggested Fix\r\n\r\nTo fix this bug, set charset in getResponseText()\r\n\r\nSee https://github.com/appcelerator/titanium_mobile/pull/590\r\n\r\n\r\n", "attachment": [ { "id": "27406", "filename": "120426-0001.png", "author": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "created": "2012-04-26T00:06:53.000+0000", "size": 63205, "mimeType": "image/png" }, { "id": "28785", "filename": "httpclient_xmlencoding_tests.js", "author": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-06-28T12:42:13.000+0000", "size": 1647, "mimeType": "text/javascript" } ], "flagged": false, "summary": "Android: createHttpClient cannot determine the charset encoding by html meta tag", "creator": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "subtasks": [], "reporter": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "environment": "* Titanium SDK version: 2.1.0 (github fork)\r\n* Android SDK version: r18\r\n* Device Details: Android emulator\r\n* Host Operating System: OSX 10.7.2\r\n* Titanium Studio version: 1.0.9.201202141208\r\n\r\n", "comment": { "comments": [ { "id": "193279", "author": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "body": "iOS can also detect [encoding|http://www.w3schools.com/xml/xml_encoding.asp] for text/xml content.\r\nWe should also support this in Android for parity.", "updateAuthor": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-05-01T08:42:37.000+0000", "updated": "2012-05-01T08:42:37.000+0000" }, { "id": "195235", "author": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "body": "The link for github is not correct.\r\nThe correct link for github is:\r\nhttps://github.com/appcelerator/titanium_mobile/pull/2143", "updateAuthor": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "created": "2012-05-17T22:41:20.000+0000", "updated": "2012-05-17T22:41:20.000+0000" }, { "id": "197706", "author": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "body": "h3. Behavior for responseText property\r\n\r\nThis is the correct behavior for getting the response text\r\nfrom the raw data and is currently implemented this way in iOS.\r\n\r\n1. Attempt to convert the data using the encoding specified in the Content-Type header.\r\n If no encoding is specified, default to UTF-8. If successful, return the generated string.\r\n2. If the data looks like a XML document (maybe use content-type MIME or scan for root xml tag), search for the encoding attribute.\r\n If found use this encoding to convert the data and return.\r\n3. If the data looks like a HTML document, try scanning for the charset attribute.\r\n If found use this encoding to convert the data and return.\r\n4. Return null if we fail to parse the data. (Maybe log an error?)\r\n", "updateAuthor": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-06-07T11:22:54.000+0000", "updated": "2012-06-07T11:22:54.000+0000" }, { "id": "200771", "author": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Attached a test case for detecting the encoding with XML document responses.\r\n\r\nTo test just run the application and select various tests from the picker. You should see the correctly decoded text.", "updateAuthor": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-06-28T12:42:13.000+0000", "updated": "2012-06-28T12:42:13.000+0000" }, { "id": "200774", "author": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Created [PR #2490|https://github.com/appcelerator/titanium_mobile/pull/2490] to resolve issue.", "updateAuthor": { "name": "joshroesslein", "key": "joshroesslein", "displayName": "Josh Roesslein", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-06-28T12:49:28.000+0000", "updated": "2012-06-28T12:49:28.000+0000" }, { "id": "201027", "author": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "body": "This patch is great, but attribute value delimiter can use only double quotation.\r\nFrom W3C, attribute delimiter can use double quotation and single quotation.\r\n\r\n{quote}\r\nBy default, SGML requires that all attribute values be delimited using either double quotation marks (ASCII decimal 34) or single quotation marks (ASCII decimal 39). \r\n{quote}\r\nhttp://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2\r\n\r\nCreated PR.\r\nhttps://github.com/appcelerator/titanium_mobile/pull/2495\r\n", "updateAuthor": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "created": "2012-07-01T22:34:39.000+0000", "updated": "2012-07-01T22:34:39.000+0000" }, { "id": "209513", "author": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "body": "New PR is below:\r\nhttps://github.com/appcelerator/titanium_mobile/pull/2644\r\n\r\nTest case code: \r\n{code:title=app.js|borderStyle=solid}\r\nvar win1 = Ti.UI.createWindow({\r\n backgroundColor: 'white',\r\n});\r\nvar text = Ti.UI.createLabel({\r\n text: '',\r\n});\r\nwin1.add(text);\r\nwin1.open();\r\ncharsetTest(\"http://kangaechu.com/timob-8906/singleQuotation.html\");\r\ncharsetTest(\"http://kangaechu.com/timob-8906/singleQuotation.xml\");\r\ncharsetTest(\"http://kangaechu.com/timob-8906/doubleQuotation.html\");\r\ncharsetTest(\"http://kangaechu.com/timob-8906/doubleQuotation.xml\");\r\n \r\nfunction charsetTest(url){\r\n var xhr = Ti.Network.createHTTPClient();\r\n \r\n xhr.onload = function() {\r\n if(this.status == 200) {\r\n var html = this.responseText;\r\n if(html == null){\r\n text.text = text.text + url + ' is null.\\n\\n';\r\n }\r\n else if(html.match(/([\\s\\S]*)<\\/body>/)){\r\n var body = RegExp.$1;\r\n text.text = text.text + url + body;\r\n }else{\r\n text.text = text.text + url + ' is 200, but no body element.\\n\\n';\r\n }\r\n }else{\r\n text.text = text.text + url + ' status code is ' + this.status + '\\n\\n';\r\n }\r\n };\r\n xhr.onerror = function() {\r\n text.text = text.text + url + ' status code is ' + this.status + '\\n\\n';\r\n \r\n };\r\n xhr.open(\"GET\", url, false);\r\n xhr.send();\r\n \r\n}\r\n{code} \r\n\r\nscreenshot\r\n\r\nbefore: \r\n\r\n!http://kangaechu.com/timob-8906/before.png! \r\n\r\nafter:\r\n\r\n!http://kangaechu.com/timob-8906/after.png! ", "updateAuthor": { "name": "kangae2", "key": "kangae2", "displayName": "Satoshi Tanaka", "active": true, "timeZone": "Asia/Tokyo" }, "created": "2012-07-25T22:43:06.000+0000", "updated": "2012-07-25T22:43:06.000+0000" }, { "id": "234495", "author": { "name": "oromero", "key": "oromero", "displayName": "Olga Romero", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Closing as fixed.\r\nTested and verified with:\r\nTitanium Studio, build: 3.0.1.201212181159\r\nTitanium SDK, build: 3.0.0.GA\r\nMountain Lion 10.8.2\r\nNexus4 Android version 4.2\r\nNexus7 Android version 4.1.2\r\nChrome 23.0\r\n", "updateAuthor": { "name": "oromero", "key": "oromero", "displayName": "Olga Romero", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-01-15T16:50:44.000+0000", "updated": "2013-01-15T16:53:23.000+0000" } ], "maxResults": 9, "total": 9, "startAt": 0 } } }