Problem
There seems to be an issue in XHR handling a 304 Not Modified status code on Android and iOS.
On Android the XHR.onerror function is called but on iOS the XHR.onload function is called.
Repro sequence
var url = "http://localhost:8080/test";
Titanium.API.debug( "Sending GET request to " + url );
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function()
{
Titanium.API.debug( "XHR onload()" );
Titanium.API.debug( xhr );
Titanium.API.debug( "Response " + xhr.status );
Titanium.API.debug( "Response text " + xhr.responseText )
};
xhr.onerror = function( e )
{
Titanium.API.debug( "XHR error()" );
Titanium.API.debug( xhr );
Titanium.API.debug( "Response " + xhr.status );
Titanium.API.debug( "Response text " + xhr.responseText )
Titanium.API.debug( e );
};
xhr.open( "GET", url );
xhr.send();
iOS logs
Here is the GET request and response for the 304 Not Modified status code on iOS:
{noformat}
GET /test HTTP/1.1
Host: localhost:8080
User-Agent: Appcelerator Titanium/1.8.0.r05ee9f48.d10.17 (iPhone Simulator/5.0; iPhone OS; en_US;)
Accept-Encoding: gzip
X-Requested-With: XMLHttpRequest
Connection: keep-alive
HTTP/1.1 304 Not Modified
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1
Cache-Control: no-transform, no-store, no-cache, private
Date: Fri, 16 Dec 2011 20:12:37 GMT
{noformat}
Here is the output from Titanium Studio on iOS:
{noformat}
[DEBUG] Sending GET request to http://localhost:8080/test
[DEBUG] XHR onload()
[object TiNetworkClient]
[DEBUG] Response 304
[DEBUG] Response text undefined
{noformat}
Android logs
Here is the GET request and response for the 304 Not Modified status code on Android:
{noformat}
GET /test HTTP/1.1
X-Requested-With: XMLHttpRequest
User-Agent:
Host: localhost:8080
Connection: Keep-Alive
HTTP/1.1 304 Not Modified
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1
Cache-Control: no-transform, no-store, no-cache, private
Date: Fri, 16 Dec 2011 20:16:23 GMT
{noformat}
Here is the output from Titanium Studio on Android:
{noformat}
[INFO] Sending GET request to http://localhost:8080/test
[INFO] XHR error()
[INFO] [Ti.Network.HTTPClient]
[INFO] Response 304
[INFO] Response text
{noformat}
Titanium Studio also outputted the following stacktrace on Android:
{noformat}
E/TiHttpClient( 413): (TiHttpClient-1) [5,5480] HTTP Error (org.apache.http.client.HttpResponseException): Not Modified
E/TiHttpClient( 413): org.apache.http.client.HttpResponseException: Not Modified
E/TiHttpClient( 413): at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:222)
E/TiHttpClient( 413): at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:182)
E/TiHttpClient( 413): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:657)
E/TiHttpClient( 413): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
E/TiHttpClient( 413): at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1050)
E/TiHttpClient( 413): at java.lang.Thread.run(Thread.java:1019)
I/TiHttpClient( 413): (TiHttpClient-1) [5,5485] Sending error Not Modified
D/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [3,5488] XHR error()
D/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [6,5494] [Ti.Network.HTTPClient]
D/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [4,5498] Response 304
D/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [2,5500] Response text
D/TiAPI ( 413): (kroll$2: file:///android_asset/Resources/app.js) [3,5503] {"error":"Not Modified","source":"[Ti.Network.HTTPClient]"}
[INFO] {"error":"Not Modified","source":"[Ti.Network.HTTPClient]"}
{noformat}
Additional info
The Apache HTTP Client exception in the Android stack trace caused for any NON 2XX status:
http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/HttpResponseException.html
2xx series are successful by Status Code Definitions, further reference here:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Customer's remarks
"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."
Associated HD ticket
APP-163995
From the XHR spec: http://www.w3.org/TR/2009/WD-XMLHttpRequest-20091119/ For 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]
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.
FWIW I think Android is handling this correctly - the onerror callback should be fired for any non 2xx status codes.
Closing due to inactivity. If this issue still exists, please raise a new ticket.