From ee1b6b7465e415c28f738e516de5e15372771541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven-Michael=20St=C3=BCbe?= Date: Sat, 20 Aug 2016 21:10:15 +0200 Subject: [PATCH 1/2] added proper error response handling - Removed java flame comments. - try to read use ErrorStream if error occured https://developer.android.com/reference/java/net/HttpURLConnection.html#getErrorStream() --- .../AndroidClientHandler.cs | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs b/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs index 2a6c1045e22..912d5704688 100644 --- a/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs +++ b/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs @@ -267,11 +267,8 @@ protected void AssertSelf () // HttpClientHandler throws an exception in this instance, but I think it's not a good // idea. We'll return the response message with all the information required by the // application to fill in the blanks and provide the requested credentials instead. - // - // We should return the body of the response too but, alas, the Java client will throw - // a, wait for it, FileNotFound exception if we attempt to access the input stream. So - // no body, just a dummy. Java FTW! - ret.Content = new StringContent ("Unauthorized", Encoding.ASCII); + + ret.Content = GetErrorContent(httpConnection, new StringContent ("Unauthorized", Encoding.ASCII)); CopyHeaders (httpConnection, ret); if (ret.Headers.WwwAuthenticate != null) { @@ -285,28 +282,18 @@ protected void AssertSelf () ret.RequestedAuthentication = RequestedAuthentication; return ret; } - + if (!IsErrorStatusCode (statusCode)) { if (Logger.LogNet) Logger.Log (LogLevel.Info, LOG_APP, $"Reading..."); - Stream inputStream = new BufferedStream (httpConnection.InputStream); - if (decompress_here) { - string[] encodings = httpConnection.ContentEncoding?.Split (','); - if (encodings != null) { - if (encodings.Contains (GZIP_ENCODING, StringComparer.OrdinalIgnoreCase)) - inputStream = new GZipStream (inputStream, CompressionMode.Decompress); - else if (encodings.Contains (DEFLATE_ENCODING, StringComparer.OrdinalIgnoreCase)) - inputStream = new DeflateStream (inputStream, CompressionMode.Decompress); - } - } - ret.Content = new StreamContent (inputStream); - } else { + ret.Content = GetContent(httpConnection, httpConnection.InputStream); + } + else { if (Logger.LogNet) - Logger.Log (LogLevel.Info, LOG_APP, $"Status code is {statusCode}, returning empty content"); - // For 400 >= response code <= 599 the Java client throws the FileNotFound exeption when attempting to read from the connection - // Client tests require we return no content here - ret.Content = new StringContent (String.Empty, Encoding.ASCII); + Logger.Log (LogLevel.Info, LOG_APP, $"Status code is {statusCode}, reading..."); + ret.Content = GetErrorContent(httpConnection, new StringContent (String.Empty, Encoding.ASCII)); } + CopyHeaders (httpConnection, ret); IEnumerable cookieHeaderValue; @@ -333,6 +320,32 @@ protected void AssertSelf () Logger.Log (LogLevel.Info, LOG_APP, $"Returning"); return ret; } + + private HttpContent GetErrorContent (HttpURLConnection httpConnection, HttpContent fallbackContent) + { + var contentStream = httpConnection.ErrorStream; + + if (contentStream != null) { + return GetContent(httpConnection, contentStream); + } + + return fallbackContent; + } + + private HttpContent GetContent (URLConnection httpConnection, Stream contentStream) + { + Stream inputStream = new BufferedStream(contentStream); + if (decompress_here) { + string[] encodings = httpConnection.ContentEncoding?.Split(','); + if (encodings != null) { + if (encodings.Contains(GZIP_ENCODING, StringComparer.OrdinalIgnoreCase)) + inputStream = new GZipStream(inputStream, CompressionMode.Decompress); + else if (encodings.Contains(DEFLATE_ENCODING, StringComparer.OrdinalIgnoreCase)) + inputStream = new DeflateStream(inputStream, CompressionMode.Decompress); + } + } + return new StreamContent(inputStream); + } bool HandleRedirect (HttpStatusCode redirectCode, HttpURLConnection httpConnection, RequestRedirectionState redirectState, out bool disposeRet) { From e4dc7f33869d8962c9ba4c3742b572c77c1e57d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven-Michael=20St=C3=BCbe?= Date: Mon, 22 Aug 2016 23:30:01 +0200 Subject: [PATCH 2/2] formatting according to mono guidelines as requested --- .../AndroidClientHandler.cs | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs b/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs index 912d5704688..15fc6d5e486 100644 --- a/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs +++ b/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs @@ -267,8 +267,11 @@ protected void AssertSelf () // HttpClientHandler throws an exception in this instance, but I think it's not a good // idea. We'll return the response message with all the information required by the // application to fill in the blanks and provide the requested credentials instead. - - ret.Content = GetErrorContent(httpConnection, new StringContent ("Unauthorized", Encoding.ASCII)); + // + // We return the body of the response too, but the Java client will throw + // a FileNotFound exception if we attempt to access the input stream. + // Instead we try to read the error stream and return an default message if the error stream isn't readable. + ret.Content = GetErrorContent (httpConnection, new StringContent ("Unauthorized", Encoding.ASCII)); CopyHeaders (httpConnection, ret); if (ret.Headers.WwwAuthenticate != null) { @@ -286,14 +289,16 @@ protected void AssertSelf () if (!IsErrorStatusCode (statusCode)) { if (Logger.LogNet) Logger.Log (LogLevel.Info, LOG_APP, $"Reading..."); - ret.Content = GetContent(httpConnection, httpConnection.InputStream); + ret.Content = GetContent (httpConnection, httpConnection.InputStream); } else { if (Logger.LogNet) Logger.Log (LogLevel.Info, LOG_APP, $"Status code is {statusCode}, reading..."); - ret.Content = GetErrorContent(httpConnection, new StringContent (String.Empty, Encoding.ASCII)); + // For 400 >= response code <= 599 the Java client throws the FileNotFound exception when attempting to read from the input stream. + // Instead we try to read the error stream and return an empty string if the error stream isn't readable. + ret.Content = GetErrorContent (httpConnection, new StringContent (String.Empty, Encoding.ASCII)); } - + CopyHeaders (httpConnection, ret); IEnumerable cookieHeaderValue; @@ -320,32 +325,32 @@ protected void AssertSelf () Logger.Log (LogLevel.Info, LOG_APP, $"Returning"); return ret; } - - private HttpContent GetErrorContent (HttpURLConnection httpConnection, HttpContent fallbackContent) + + HttpContent GetErrorContent (HttpURLConnection httpConnection, HttpContent fallbackContent) { var contentStream = httpConnection.ErrorStream; if (contentStream != null) { - return GetContent(httpConnection, contentStream); + return GetContent (httpConnection, contentStream); } return fallbackContent; } - private HttpContent GetContent (URLConnection httpConnection, Stream contentStream) - { - Stream inputStream = new BufferedStream(contentStream); - if (decompress_here) { - string[] encodings = httpConnection.ContentEncoding?.Split(','); - if (encodings != null) { - if (encodings.Contains(GZIP_ENCODING, StringComparer.OrdinalIgnoreCase)) - inputStream = new GZipStream(inputStream, CompressionMode.Decompress); - else if (encodings.Contains(DEFLATE_ENCODING, StringComparer.OrdinalIgnoreCase)) - inputStream = new DeflateStream(inputStream, CompressionMode.Decompress); - } - } - return new StreamContent(inputStream); - } + HttpContent GetContent (URLConnection httpConnection, Stream contentStream) + { + Stream inputStream = new BufferedStream (contentStream); + if (decompress_here) { + string[] encodings = httpConnection.ContentEncoding?.Split (','); + if (encodings != null) { + if (encodings.Contains (GZIP_ENCODING, StringComparer.OrdinalIgnoreCase)) + inputStream = new GZipStream (inputStream, CompressionMode.Decompress); + else if (encodings.Contains (DEFLATE_ENCODING, StringComparer.OrdinalIgnoreCase)) + inputStream = new DeflateStream (inputStream, CompressionMode.Decompress); + } + } + return new StreamContent (inputStream); + } bool HandleRedirect (HttpStatusCode redirectCode, HttpURLConnection httpConnection, RequestRedirectionState redirectState, out bool disposeRet) {