Okhttp 3.4.1 inconsistent with throwing IOException? - android

I'm seeing this really bizarre issue with okhttp. I am using okhttp to upload files to the server via post streaming. It's the same code as in okhttp recipes for post streaming:
while ((count = source.read(buffer)) != -1) {
sink.write(buffer, 0, count);
}
This works fine. The loop is inside writeTo method, which is part of the RequestBody - all like in the recipe. The body is wrapped into try/catch block and on IOException I fail my upload task and move on. This worked perfectly with okhttp 3.0.1.
I've now updated to okhttp 3.4.1 and I'm getting a really weird and inconsistent behavior. I'm testing with switching on the airplane mode mid upload and expecting to get IOException to fail the upload, but sometimes I'm getting it and sometimes not. I can't really figure out what this behavior is connected with. Just killing the app and repeating the test case will throw the expected exception once every 5 times or so.
Wondering if anyone else has seen similar behaviour and if there are any workaround apart from downgrading back to 3.0.1?
EDIT:
It looks like there are several exceptions that are all extending IOExceptions but not all of them make it out of the okhttp land.
These two are never reaching my try/catch block:
java.io.IOException: closed
at okhttp3.internal.framed.Http2$Writer.data(Http2.java:482)
at okhttp3.internal.framed.FramedConnection.writeData(FramedConnection.java:332)
at okhttp3.internal.framed.FramedStream$FramedDataSink.emitDataFrame(FramedStream.java:516)
at okhttp3.internal.framed.FramedStream$FramedDataSink.write(FramedStream.java:489)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:176)
at okio.RealBufferedSink.write(RealBufferedSink.java:96)
at okio.RealBufferedSink.write(RealBufferedSink.java:96)
javax.net.ssl.SSLException: Write error: ssl=0x9bad4480: I/O error during system call, Connection timed out
at com.android.org.conscrypt.NativeCrypto.SSL_write(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:771)
at okio.Okio$1.write(Okio.java:78)
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:171)
at okio.RealBufferedSink.write(RealBufferedSink.java:41)
at okhttp3.internal.framed.Http2$Writer.dataFrame(Http2.java:494)
at okhttp3.internal.framed.Http2$Writer.data(Http2.java:487)
at okhttp3.internal.framed.FramedConnection.writeData(FramedConnection.java:311)
at okhttp3.internal.framed.FramedStream$FramedDataSink.emitDataFrame(FramedStream.java:515)
at okhttp3.internal.framed.FramedStream$FramedDataSink.write(FramedStream.java:488)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:171)
at okio.RealBufferedSink.write(RealBufferedSink.java:91)
However, this one seems to be getting all the way to my try/catch block:
okhttp3.internal.framed.StreamResetException: stream was reset: CANCEL
at okhttp3.internal.framed.FramedStream.checkOutNotClosed(FramedStream.java:574)
at okhttp3.internal.framed.FramedStream.access$1200(FramedStream.java:34)
at okhttp3.internal.framed.FramedStream$FramedDataSink.emitDataFrame(FramedStream.java:508)
at okhttp3.internal.framed.FramedStream$FramedDataSink.write(FramedStream.java:488)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:171)
at okio.RealBufferedSink.write(RealBufferedSink.java:91)
I have a feeling this might be something to do with my okhttp client being set to retryOnConnectionFailure(true), but if that is the case, why a total loss of connectivity (airplane mode) is considered a recoverable failure?
EDIT 2:
Did some testing with retryOnConnectionFailure(false) and all of the above exceptions are now making it to my try/catch block. Also added an interceptor (network) and set retryOnConnectionFailure(true), repeated the test and noticed that okhttp goes into an endless loop of sending out requests to my server. Bug or a feature and I'm not using it correctly? Really confused with this behaviour..

Related

Mockwebserver and OkHttpIdlingResrouce Connect Exception

I am writing instrumentation tests using Square's MockWebServer to mock server responses and OkHttpIdlingResource to wait for OkHttp to finish work until the remaining test steps continue. I am also using a MockWebServer dispatcher so that I can respond to certain requests differently depending on the path.
I am running into an issue where the tests work for some Android API versions and they don't work for others.
On Marshmallow the tests pass as expected. When I run on Android Pie, the MockWebServer responds to several requests, but then, for some reason, OkHttp throws a java.net.ConnectException.
If I hit my real web server everything works fine for any app version, it's only when using MockWebServer that I see this issue.
I have no idea what would cause this and the logs are not surfacing anything useful. In the failure case I can see that the MockWebServer has several successful 200 responses, but for some reason a ConnectException occurs during one of the calls.
The only weird thing I can see in the logs is that an Espresso ViewAssertion is logged before the last, failing, OkHttp request is logged. So it may be that the OkHttpIdlingResource is saying that it is idle when it really isn't.
Any ideas on what could be wrong?

Unexpected end of stream ksoap2-android with gsoap

We have an android app that uses soap to communicate with an API implemented in C++ with gsoap. The android application uses the ksoap2-android library for soap communications.
When the android app runs on an actual device and communicates over wifi everything seems to work as it should. However when run in the emulater (virtualized x86 image) requests with longer replies often fail with a ProtocolException unexpected end of stream.
This error and because it only tends to happen with long responses let me to the believe that on the gsoap side the socket gets closed to soon. I have tried somethings.
default accept_flags on the gsoap side didn't work
explicitly remove SO_LINGER flags from accept_flags in gsoap, didn't solve the issue (I was worried it might set linger with a timeout of zero which would result in exactly my problem)
explicitly specify the SO_LINGER flag in the accept flags and a timeout of 10, didn't solve the issue
Then i tried adding a sleep for 1 second right before shutdown in gsoaps tcp_disconnect function. That solved the problem but sleeping is no good ofcourse.
As sleeping is not a good solution I ended up using select which seems to work ok but I'm not 100% confident in this solution.
Here is the actual code change. These are the last lines of the tcp_disconnect function in stdsoap2.cpp. The tcp_select call is what I have added.
if (soap_valid_socket(soap->socket) && !(soap->omode & SOAP_IO_UDP))
{
tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, 5);
soap->fshutdownsocket(soap, soap->socket, SOAP_SHUT_RDWR);
soap->fclosesocket(soap, soap->socket);
soap->socket = SOAP_INVALID_SOCKET;
}
return SOAP_OK;
}
Is this the right solution?

Android Retrofit I sometimes get ECONNRESET, and I don't know why

I receive pseudo-randomely ECONNRESET from my backend's company. I say pseudo random because althought It doesn't happend the same way I can provoque it almost every time by launching a large amount of request.
I typicaly launch downloads from activity's life cycles events and therefore I use Retrofit's Call.enqueue() to network on background. In the part of the code that seems to cause trouble, I'm launching a series of download (~15 REST routes for jsons and 5-6 files) from a background thread. With that scenario, the ECONNRESET apears 2 out of 3 try on one of the called REST route.
There is no more explanation server side the only thing that we logged was read/write ECONNRESET.
Here is what I've tried :
Update to okhttp 3.5.0 (from 3.2.0) and retrofit 2.1.0 (from 2.0.2)
I added "Connection:close" int my requests header to prevent keep alive.
I reduced my total pool to 1 :
.connectionPool(new ConnectionPool(0, 1, TimeUnit.SECONDS))
It happend on my phone (Android 6), I don't have other phone to test the code. I've some unrelated trouble with my AVD that prevent me for testing on different android versions (soon to be fixed).
Would you know what could provoque this ?
Thanks,
For the records, I was using HttpURLConnection in my file download method (whearas my REST api was questioned throught retrofit and okhttp), I changed it to okHttp and it's all good now.

loopj infinite loop when host not found

I am trying to make use of loopj's Async HTTP library, but I encountered quite critical problem. When I am making a request to a host that does not exist it goes into infinite loop.
I tried debugging the code, but I didn't find much:
com.loopj.android.http.AsyncHttpRequest.run() runs and calls com.loopj.android.http.AsyncHttpRequest.makeRequestWithRetries()
Then inside makeRequestWithRetries() com.loopj.android.http.AsyncHttpRequest.makeRequest() is called which throws ConnectTimeoutException that looks like it is being caught by IOException catch and com.loopj.android.http.RetryHandler.retryRequest(IOException, int, HttpContext) is called.
Then I app is not caught in any previous breakpoints, not even com.loopj.android.http.AsyncHttpResponseHandler.handleMessage(Message) and no message is fired, it just gets stuck.
However I am able to cancel this request with com.loopj.android.http.AsyncHttpClient.cancelRequests(Context, boolean).
I have te newest possible code, because I got it yesterday from github and build myself.
I appreciate any help.
Mentioned this in a comment, but I was having the same issue, and can confirm that the latest version of the library fixes this issue.
See this pull request: https://github.com/loopj/android-async-http/commit/87a615c3b86c3e33bd885435f98ab33483f874e9

RestSharp & MonoDroid: Error getting response stream (ReadDone2): ReceiveFailure

I have a similiar situation like this: How do I handle/fix "Error getting response stream (ReadDone2): ReceiveFailure" when using MonoTouch? but I'm only GETing a list, not posting anything in the body.
Furthermore, I'm using RestSharp, and it works in almost all the cases, but every once in a while I receive Error getting response stream (ReadDone2): ReceiveFailure.
What can possibly be the problem?
(ps: the exact same code on Wp7 doesn't cause any errors)
There is a bug report (https://bugzilla.xamarin.com/show_bug.cgi?id=19673) which appears to have a reproducible example. So, at the least, you could add yourself to the CC list for it.
(BTW, I get the error (also using restsharp) under Linux (Mint/17, Mono 3.2.8), so it is not specific to Android. It is hard to reproduce: for me it is simply happening after between 1000 and 10,000 web service calls, and it always works when restarting. I am not seeing a CPU or memory problem. It could be some buffer build-up, or might simply be a network failure, or even remote server problem?)

Categories

Resources