Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-14224] Android: xhr.abort() call makes all subsequent xhr calls fail completely

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2013-08-23T23:37:45.000+0000
Affected Version/sRelease 3.1.0
Fix Version/s2013 Sprint 17, 2013 Sprint 17 API, Release 3.2.0
ComponentsAndroid
LabelssupportTeam
ReporterEduardo Gomez
AssigneeHieu Pham
Created2013-06-13T21:26:19.000+0000
Updated2017-03-14T20:24:44.000+0000

Description

Issue

Once we call abort() method on xhr (which we need to cancel download), all the subsequent calls to xhr client are failing. The request is going to the server but from the server we are getting the below error:

stack trace

06-13 16:18:22.125: W/ResponseProcessCookies(21195): Cookie rejected: "BasicClientCookie[version=0,name=ObFormLoginCookie,domain=sso.cisco.com,path=/autho/login/loginaction.html,expiry=null]". Illegal path attribute "/autho/login/loginaction.html". Path of origin: "/obrareq.cgi"
- Thread A similar discussion about how fix this: http://stackoverflow.com/questions/8279970/accept-all-cookies-via-httpclient

Comments

  1. Ingo Muschenetz 2013-06-13

    [~egomez] is it possible to extract out an example into a short code snippet showing the failure?
  2. Vishal Duggal 2013-07-09

    Aborting the xhr request tears down the underlying TCP connection. If you actually see the response from the server after the abort you'll see the code for a Login Page (so the client needs to re-authenticate after abort). The server supports Basic Access Authentication, so setting a basic auth request header instead of the cookie information will work every time (even after abort)
       	var basic_authStr = 'Basic ' +Titanium.Utils.base64encode(USERNAME+':' + PASSWORD);
       	xhr.setRequestHeader("Authorization", basic_authStr);
       	xhr.open('GET', url);
       	xhr.send();
       
    Resolving this as not our bug
  3. Eduardo Gomez 2013-07-15

    Please see feedback to points:

    Work arounds

    (1) Do a silent login after abort.

    Feedback:

    We cannot ask user to re-login after every abort. As per Cisco policy we should not store the user credential anywhere is app, so we cannot got for Basic authentication. Our Cisco framework gives us a Cookie and which we need re-use, for further server communication. (2) Don't abort. Just ignore the results.

    Feedback:

    This will slow the app, because even we are not downloading the content the data chunk will be downloading to the device. (3) The server seems to support basic authorization. We essentially changed the code in Search.js to send an Authorization Header instead of the ObSSOCookie to get it to work fine even after abort.

    Feedback:

    As mentioned in #1, we should not store user credentials, and we should use the cookies for further server communication.

    Customer's remarks

    "Please provide us a solution to use the cookies, for further communication. This mechanism of Cookies is working fine with iOS implementation and working fine with our apps on iPhone and iPad."
  4. Hieu Pham 2013-08-07

    master PR: https://github.com/appcelerator/titanium_mobile/pull/4549
  5. Eduardo Gomez 2013-08-12

    Hi, I've tested out PR and works great. As I just wanted to make sure their app runs smoothly and without outstanding issues. I found the following outcome:

    Details

    User once logged in, attempts to get file "A". If he "aborts" current download the exception below is thrown. When he resumes (click "Download") then he won't be able to abort this file download over again (to be clear: the download will finalize successfully).

    Device stack trace

    Razr Droid 2.3.5 on TiSDK 3.2 CI build
       08-11 20:38:34.076: W/DefaultHttpClient(4586): Error consuming content after an exception.
       08-11 20:38:34.076: W/DefaultHttpClient(4586): java.net.SocketException: Socket is closed
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.checkOpen(OpenSSLSocketImpl.java:339)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.access$100(OpenSSLSocketImpl.java:57)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:776)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.AbstractSessionInputBuffer.read(AbstractSessionInputBuffer.java:134)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:174)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:188)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.ContentLengthInputStream.close(ContentLengthInputStream.java:121)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.entity.BasicHttpEntity.consumeContent(BasicHttpEntity.java:142)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.conn.BasicManagedEntity.consumeContent(BasicManagedEntity.java:114)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:662)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1277)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at java.lang.Thread.run(Thread.java:1019)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): Error consuming content after an exception.
       08-11 20:38:34.076: W/DefaultHttpClient(4586): java.net.SocketException: Socket is closed
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.checkOpen(OpenSSLSocketImpl.java:339)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.access$100(OpenSSLSocketImpl.java:57)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:776)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.AbstractSessionInputBuffer.read(AbstractSessionInputBuffer.java:134)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:174)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:188)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.io.ContentLengthInputStream.close(ContentLengthInputStream.java:121)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.entity.BasicHttpEntity.consumeContent(BasicHttpEntity.java:142)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.conn.BasicManagedEntity.consumeContent(BasicManagedEntity.java:114)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:662)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1277)
       08-11 20:38:34.076: W/DefaultHttpClient(4586): 	at java.lang.Thread.run(Thread.java:1019)
       
    Once File "A" was downloaded successfully, user attempts to get File "B". Download progress starts off. User aborts. Exception below is thrown. If he resumes by clicking "Download" button they won't be able to abort anymore. But again the file "B" will be downloaded successfully:
       08-11 20:47:24.561: D/TiHttpClient(4586): (TiHttpClient-24) [353743,546582] client is not valid, unable to clear expired and idle connections
       08-11 20:47:24.561: E/TiHttpClient(4586): (TiHttpClient-24) [0,546582] HTTP Error (java.lang.NullPointerException): java.lang.NullPointerException
       08-11 20:47:24.561: E/TiHttpClient(4586): java.lang.NullPointerException
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.finishedReceivingEntityData(TiHTTPClient.java:376)
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:308)
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:216)
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:657)
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1277)
       08-11 20:47:24.561: E/TiHttpClient(4586): 	at java.lang.Thread.run(Thread.java:1019)
       08-11 20:47:27.162: I/TiAPI(4586):  onerror ---->java.lang.NullPointerException
       

    Outcomes

    - From Android docs: http://developer.android.com/reference/org/apache/http/HttpEntity.html#consumeContent()
       This method is called to indicate that the content of this entity is no longer required. All entity implementations are expected to release all allocated resources as a result of this method invocation. Content streaming entities are also expected to dispose of the remaining content, if any. Wrapping entities should delegate this call to the wrapped entity. 
       This method is of particular importance for entities being received from a connection. The entity needs to be consumed completely in order to re-use the connection with keep-alive.
       
    Do they need to warn users Abort method would work only once? Are these entities throwing an exception when this method is called multiple times? If you need further clarity, or anymore info let me know, thanks.
  6. Ping Wang 2013-08-23

    PR: https://github.com/appcelerator/titanium_mobile/pull/4549
  7. Lee Morris 2017-03-14

    Closing ticket as fixed.

JSON Source