{ "id": "84054", "key": "TIMOB-6760", "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": [], "resolution": { "id": "2", "description": "The problem described is an issue which will never be fixed.", "name": "Won't Fix" }, "resolutiondate": "2017-08-01T22:27:01.000+0000", "created": "2011-12-19T12:00:59.000+0000", "priority": { "name": "Low", "id": "4" }, "labels": [ "api", "exalture", "parity", "supportTeam" ], "versions": [ { "id": "12570", "name": "Release 1.7.5", "archived": true, "released": true, "releaseDate": "2011-11-02" }, { "id": "12580", "description": "Dual Runtime 1.8.0", "name": "Release 1.8.0.1", "archived": true, "released": true, "releaseDate": "2011-12-22" }, { "id": "14982", "description": "Release 3.2.0", "name": "Release 3.2.0", "archived": false, "released": true, "releaseDate": "2013-12-19" }, { "id": "15856", "description": "Release 3.2.1", "name": "Release 3.2.1", "archived": false, "released": true, "releaseDate": "2014-02-10" } ], "issuelinks": [], "assignee": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2017-08-01T22:27:01.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": "h2.Problem\r\nThere seems to be an issue in XHR handling a 304 Not Modified status code on Android and iOS. \r\n\r\nh6.On Android the XHR.onerror function is called but on iOS the XHR.onload function is called.\r\n\r\nh6.Repro sequence\r\n{code:title=app.js}\r\nvar url = \"http://localhost:8080/test\";\r\nTitanium.API.debug( \"Sending GET request to \" + url );\r\n\r\nvar xhr = Titanium.Network.createHTTPClient();\r\n\r\nxhr.onload = function()\r\n{\r\n Titanium.API.debug( \"XHR onload()\" );\r\n Titanium.API.debug( xhr );\r\n Titanium.API.debug( \"Response \" + xhr.status );\r\n Titanium.API.debug( \"Response text \" + xhr.responseText )\r\n};\r\n\r\nxhr.onerror = function( e )\r\n{\r\n Titanium.API.debug( \"XHR error()\" );\r\n Titanium.API.debug( xhr );\r\n Titanium.API.debug( \"Response \" + xhr.status );\r\n Titanium.API.debug( \"Response text \" + xhr.responseText )\r\n Titanium.API.debug( e ); \r\n};\r\n\r\nxhr.open( \"GET\", url );\r\nxhr.send();\r\n{code}\r\n\r\n\r\nh2.iOS logs\r\n\r\nh6.Here is the GET request and response for the 304 Not Modified status code on iOS:\r\n\r\n{noformat}\r\nGET /test HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: Appcelerator Titanium/1.8.0.r05ee9f48.d10.17 (iPhone Simulator/5.0; iPhone OS; en_US;)\r\nAccept-Encoding: gzip\r\nX-Requested-With: XMLHttpRequest\r\nConnection: keep-alive\r\n\r\nHTTP/1.1 304 Not Modified\r\nServer: Apache-Coyote/1.1\r\nX-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1\r\nCache-Control: no-transform, no-store, no-cache, private\r\nDate: Fri, 16 Dec 2011 20:12:37 GMT\r\n{noformat}\r\n\r\n\r\nh6.Here is the output from Titanium Studio on iOS:\r\n\r\n{noformat}\r\n[DEBUG] Sending GET request to http://localhost:8080/test\r\n[DEBUG] XHR onload()\r\n[object TiNetworkClient]\r\n[DEBUG] Response 304\r\n[DEBUG] Response text undefined\r\n{noformat}\r\n\r\n\r\nh2.Android logs\r\n\r\nh6.Here is the GET request and response for the 304 Not Modified status code on Android:\r\n\r\n{noformat}\r\nGET /test HTTP/1.1\r\nX-Requested-With: XMLHttpRequest\r\nUser-Agent: \r\nHost: localhost:8080\r\nConnection: Keep-Alive\r\n\r\nHTTP/1.1 304 Not Modified\r\nServer: Apache-Coyote/1.1\r\nX-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1\r\nCache-Control: no-transform, no-store, no-cache, private\r\nDate: Fri, 16 Dec 2011 20:16:23 GMT\r\n{noformat}\r\n\r\nh6.Here is the output from Titanium Studio on Android:\r\n\r\n{noformat}\r\n[INFO] Sending GET request to http://localhost:8080/test\r\n[INFO] XHR error()\r\n[INFO] [Ti.Network.HTTPClient]\r\n[INFO] Response 304\r\n[INFO] Response text \r\n{noformat}\r\n\r\n\r\nh6.Titanium Studio also outputted the following stacktrace on Android:\r\n\r\n{noformat}\r\nE/TiHttpClient( 413): (TiHttpClient-1) [5,5480] HTTP Error (org.apache.http.client.HttpResponseException): Not Modified\r\nE/TiHttpClient( 413): org.apache.http.client.HttpResponseException: Not Modified\r\nE/TiHttpClient( 413): at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:222)\r\nE/TiHttpClient( 413): at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:182)\r\nE/TiHttpClient( 413): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:657)\r\nE/TiHttpClient( 413): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)\r\nE/TiHttpClient( 413): at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1050)\r\nE/TiHttpClient( 413): at java.lang.Thread.run(Thread.java:1019)\r\nI/TiHttpClient( 413): (TiHttpClient-1) [5,5485] Sending error Not Modified\r\nD/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [3,5488] XHR error()\r\nD/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [6,5494] [Ti.Network.HTTPClient]\r\nD/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [4,5498] Response 304\r\nD/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [2,5500] Response text \r\nD/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [3,5503] {\"error\":\"Not Modified\",\"source\":\"[Ti.Network.HTTPClient]\"}\r\n[INFO] {\"error\":\"Not Modified\",\"source\":\"[Ti.Network.HTTPClient]\"}\r\n{noformat}\r\n\r\n\r\nh3.Additional info\r\nThe Apache HTTP Client exception in the Android stack trace caused for any NON 2XX status:\r\n\r\nhttp://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/HttpResponseException.html\r\n\r\n2xx series are successful by Status Code Definitions, further reference here: \r\n\r\nhttp://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html\r\n\r\n\r\nh6.Customer's remarks\r\n\"Although Android is throwing the exception the real problem seems to be that on Android XHR.onerror is called when a 304 status code is returned but on iOS XHR.onload is called. Rather than having the same success logic in both methods we ended up reworking our solution to use a 200 OK response since both platforms handle that in the XHR.onload method. Because of the rework of this issue is no longer blocking us. I created the ticket in case other users were seeing similar behavior.\"\r\n\r\n\r\nh6.Associated HD ticket\r\nAPP-163995", "attachment": [], "flagged": false, "summary": "Parity: Inconsistent XHR behavior handling 304 Not Modified status code on Android and iOS", "creator": { "name": "egomez", "key": "egomez", "displayName": "Eduardo Gomez", "active": false, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "egomez", "key": "egomez", "displayName": "Eduardo Gomez", "active": false, "timeZone": "America/Los_Angeles" }, "environment": " Product: Mobile\r\n Titanium SDK: Mobile 1.7.5\r\n Platform OS: Android\r\n Platform OS Version: 2.3.3\r\n", "comment": { "comments": [ { "id": "176541", "author": { "name": "dthorp", "key": "dthorp", "displayName": "Don Thorp", "active": true, "timeZone": "America/Los_Angeles" }, "body": "From the XHR spec: http://www.w3.org/TR/2009/WD-XMLHttpRequest-20091119/\r\n\r\nFor 304 Not Modified responses that are a result of a user agent generated conditional request the user agent must act as if the server gave a 200 OK response with the appropriate content. The user agent must allow setRequestHeader() to override automatic cache validation by setting request headers (e.g., If-None-Match, If-Modified-Since), in which case 304 Not Modified responses must be passed through. [RFC2616]", "updateAuthor": { "name": "dthorp", "key": "dthorp", "displayName": "Don Thorp", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-12-19T12:57:05.000+0000", "updated": "2011-12-19T12:57:05.000+0000" }, { "id": "218207", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "This is happening for all non 2xx status codes as of 2.1.2.GA - you can check for error status codes in onload on iOS to work around it, but this is definitely a parity issue worth addressing.", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2012-09-10T12:20:39.000+0000", "updated": "2012-09-10T12:20:39.000+0000" }, { "id": "218208", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "FWIW I think Android is handling this correctly - the onerror callback should be fired for any non 2xx status codes.", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2012-09-10T12:22:45.000+0000", "updated": "2012-09-10T12:22:45.000+0000" }, { "id": "425214", "author": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "body": "Closing due to inactivity. If this issue still exists, please raise a new ticket.", "updateAuthor": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2017-08-01T22:27:01.000+0000", "updated": "2017-08-01T22:27:01.000+0000" } ], "maxResults": 6, "total": 6, "startAt": 0 } } }