Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android implementation of HTTPClient throwing up java.io.IOException #2651

Closed
terrajobst opened this issue Jan 24, 2019 · 11 comments
Closed
Labels
Area: App Runtime Issues in `libmonodroid.so`. need-info Issues that need more information from the author.

Comments

@terrajobst
Copy link
Member

From @UnreachableCode on January 17, 2019 16:54

I believe this relates to the bug detailed in Xamarin's old Bugzilla:
https://bugzilla.xamarin.com/show_bug.cgi?id=41100

and is also similar to the issue discussed here:
square/okhttp#1517

Here is the main stacktrace of my issue:

LoginProvider+d__1.MoveNext () C:\source\repos{MyApp}{MyApp}{MyApp}\Services\LoginProvider.cs:35
java.io.IOException: unexpected end of stream on Connection{testclarity.i-menzies.com:443, proxy=DIRECT@ hostAddress=62.244.173.166 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=http/1.1} (recycle count=0)
com.android.okhttp.internal.http.HttpConnection.readResponse(HttpConnection.java:210)
com.android.okhttp.internal.http.HttpTransport.readResponseHeaders(HttpTransport.java:80)
com.android.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:905)
com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:789)
com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:443)
com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:388)
com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:501)
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)
com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25)
Caused by: java.io.EOFException: \n not found: size=0 content=...
com.android.okhttp.okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:200)
com.android.okhttp.internal.http.HttpConnection.readResponse(HttpConnection.java:191)

I have tried setting the connection closed header and setting chunked transfer encoding but neither of these fixes work. I would try to set the OkHTTP.setRetryOnConnectionFailure(true) but I don't think there is a way to do this in the referenced Java source.

Copied from original issue: dotnet/standard#1055

@terrajobst
Copy link
Member Author

@marek-safar is bugzilla still the right location for filing Xamarin bugs?

@terrajobst
Copy link
Member Author

From @marek-safar on January 23, 2019 8:7

No, use https://github.com/xamarin/xamarin-android/ for new issues

@jonathanpeppers
Copy link
Member

@UnreachableCode are you using ModernHttpClient?

I am confused on how okhttp is in your Java stacktrace, Xamarin.Android doesn't use that?

The options for HTTP settings here under Project Options | Android Options | Advanced:

image

None of the built-in options here use okhttp.

@jonathanpeppers jonathanpeppers added the need-info Issues that need more information from the author. label Jan 25, 2019
@jonathanpeppers jonathanpeppers added this to the far future milestone Jan 25, 2019
@jonathanpeppers jonathanpeppers added the Area: App Runtime Issues in `libmonodroid.so`. label Jan 25, 2019
@UnreachableCode
Copy link

Hi @jonathanpeppers.

Not using ModernHttpClient. Just the default HttpClient setup. I had these settings:

capture35

Which lead to okhttp appearing in my stacktraces. However, I have now changed to this:

capture36

And I seem to no longer be receiving the error, leading me to believe it's not using okhttp anymore.

@jonathanpeppers
Copy link
Member

@UnreachableCode I am wondering if you have some dependency using okhttp. A NuGet package?

I would recommend using the Android HttpClient implementation like you have above.

Closing for now, but feel free to reopen/comment if you have another issue, thanks!

@muhaym
Copy link

muhaym commented Jun 12, 2019

@jonathanpeppers, Using Android HttpClient Implementation does throw Java exceptions instead of .NET exceptions. Similarly HttpClient iOS exception is System.Web.Exception.

Is there any way that I could get the .NET Exceptions, so that I could use libraries like Polly to implement policies from .NET Standard project itself.

I don't have any reference to Okhttp, but not sure how okhttp ends up in logs like the report above.

{Java.Net.UnknownHostException: Unable to resolve host "smc.kooz.top": No address associated with hostname ---> Java.Lang.RuntimeException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
   --- End of inner exception stack trace ---
  at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <9ed4c1a7b8844cdcb5330cc881c1cd6a>:0 
  at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeAbstractVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00014] in <9ed4c1a7b8844cdcb5330cc881c1cd6a>:0 
  at Javax.Net.Ssl.HttpsURLConnectionInvoker.Connect () [0x0000a] in <a6696dd5fce04f5480364911ef1529f2>:0 
  at Xamarin.Android.Net.AndroidClientHandler+<>c__DisplayClass44_0.<ConnectAsync>b__0 () [0x0005a] in <a6696dd5fce04f5480364911ef1529f2>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <3a61d48d66dd458fa0b64990b6c8f8cc>:0 
  at System.Threading.Tasks.Task.Execute () [0x00000] in <3a61d48d66dd458fa0b64990b6c8f8cc>:0 
--- End of stack trace from previous location where exception was thrown ---

  at Xamarin.Android.Net.AndroidClientHandler.DoProcessRequest (System.Net.Http.HttpRequestMessage request, Java.Net.URL javaUrl, Java.Net.HttpURLConnection httpConnection, System.Threading.CancellationToken cancellationToken, Xamarin.Android.Net.AndroidClientHandler+RequestRedirectionState redirectState) [0x0012e] in <a6696dd5fce04f5480364911ef1529f2>:0 
  at Xamarin.Android.Net.AndroidClientHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x002be] in <a6696dd5fce04f5480364911ef1529f2>:0 
  at System.Net.Http.HttpClient.SendAsyncWorker (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) [0x000ca] in <162fad71ed6e4a3cb7598d196d170e1b>:0 
  at SpotMyCourt.Services.CommonFiles.Services.RequestProvider.PostAsync[TRequest,TResult] (System.String uri, TRequest data, System.String token) [0x00188] in C:\Projects\SpotMyCourt\SpotMyCourt.Services\CommonFiles\Services\RequestProvider.cs:99 
  --- End of managed Java.Net.UnknownHostException stack trace ---
java.net.UnknownHostException: Unable to resolve host "smc.kooz.top": No address associated with hostname
	at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:141)
	at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
	at java.net.InetAddress.getAllByName(InetAddress.java:787)
	at com.android.okhttp.Dns$1.lookup(Dns.java:39)
	at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
	at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
	at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
	at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
	at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
	at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
	at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
	at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
	at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
	at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(Unknown Source:0)
Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
	at libcore.io.Linux.android_getaddrinfo(Native Method)
	at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:58)
	at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:122)
	... 15 more
}

@jonathanpeppers
Copy link
Member

@muhaym I am not familiar with Polly, but the exception will come through as Java.Net.UnknownHostException, a type you won't have a reference to in your netstandard project. Unfortunately, this is the result of running on different platforms, we don't map the native exception types back to .NET standard ones.

Does Polly have a way to retry based on the type name? As a string? Not ideal, but a workaround for now.

Can you file an issue on https://github.com/xamarin/xamarin-android/issues explaining the difference in exceptions you see in regular .NET vs iOS vs Android?

@muhaym
Copy link

muhaym commented Jun 13, 2019

@jonathanpeppers Thanks for the reply. Polly have a generic system to get the exception. Any way the matter of concern is not the ability to use Polly, but the ability to understand the core issue of exception from .NET Standard shared code.

I have enough data of various exception for iOS and Android project from a live project. Should I file iOS and Android separately, or what will be the right place to discuss this issue?

Ideally mapping to .NET Standard exception is what a developer can rely on, otherwise, the code duplication and writing separate interface for the httpclient for native platforms are double efforts of the same code.

@jonathanpeppers
Copy link
Member

It seemed like iOS you are getting WebException, so that seems reasonable to deal with--maybe you don't need to file an iOS bug? Android, for sure, it seems weird you have no way to catch Java.Lang.FooException types.

@muhaym
Copy link

muhaym commented Jun 13, 2019

Yes, I'll proceed with an issue in this repo.

@theo-albers
Copy link

theo-albers commented Oct 20, 2019

Since AndroidClientHandler is the default HTTP handler in Xamarin Forms projects, it's at least interesting there is no reference in the documentation about native Java exceptions bubbling up. This was a big surprise to me when some devices like the Samsung Galaxy S9 with Android 9 started showing up in AppCenter with crashes, specifically around
image
There are other exceptions as discussed here 3216.
As Xamarin Forms developer writing a netstandard shared project, I would have expected catching the typical HTTP managed exceptions like WebException, etc. would be good enough. That's how it works for iOS as well after all. Catching System.Exception was not good enough either.
For me the workaround was to extend AndroidClientHandler, since I'm spinning up the AndroidClientHandler in the Android project:

    public class WorkaroundAndroidClientHandler : AndroidClientHandler
    {
        public WorkaroundAndroidClientHandler()
        {
            this.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // The native Android HTTP client handler bubbles up Java exceptions in contrast to the iOS native handler.
            // See for instance https://github.com/xamarin/xamarin-android/issues/3216.
            // We see this behavior on a Samsung 9 with Android 9.
            // Remedy is to explicitly catch expected native network exceptions.
            try
            {
                return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
            }
            catch (Java.Net.SocketException ex)
            {
                throw new WebException($"Native SocketException on HTTP request: {ex.Message}", ex);
            }
            catch (Java.IO.IOException ex)
            {
                throw new WebException($"Native IOException on HTTP request: {ex.Message}", ex);
            }
            catch (Java.Lang.Exception ex)
            {
                throw new WebException($"Native Exception on HTTP request: {ex.Message}", ex);
            }
        }
    }

@ghost ghost locked as resolved and limited conversation to collaborators Jun 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Area: App Runtime Issues in `libmonodroid.so`. need-info Issues that need more information from the author.
Projects
None yet
Development

No branches or pull requests

5 participants