Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-6760] Parity: Inconsistent XHR behavior handling 304 Not Modified status code on Android and iOS

GitHub Issuen/a
TypeBug
PriorityLow
StatusClosed
ResolutionWon't Fix
Resolution Date2017-08-01T22:27:01.000+0000
Affected Version/sRelease 1.7.5, Release 1.8.0.1, Release 3.2.0, Release 3.2.1
Fix Version/sn/a
ComponentsAndroid
Labelsapi, exalture, parity, supportTeam
ReporterEduardo Gomez
AssigneeIngo Muschenetz
Created2011-12-19T12:00:59.000+0000
Updated2017-08-01T22:27:01.000+0000

Description

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

Comments

  1. Don Thorp 2011-12-19

    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]
  2. Kevin Whinnery 2012-09-10

    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.
  3. Kevin Whinnery 2012-09-10

    FWIW I think Android is handling this correctly - the onerror callback should be fired for any non 2xx status codes.
  4. Lee Morris 2017-08-01

    Closing due to inactivity. If this issue still exists, please raise a new ticket.

JSON Source