Skip to content

Commit

Permalink
[Mono.Android] Read error response in AndroidClientHandler (#180)
Browse files Browse the repository at this point in the history
Improve error response handling, using [`ErrorStream`][0] if an
error occurs.

> **Response Handling**  
> `HttpURLConnection` will follow up to five HTTP redirects.
> It will > follow redirects from one origin server to another.
> This implementation doesn't follow redirects from HTTPS to HTTP or
> vice versa.
> If the HTTP response indicates that an error occurred,
> `InputStream` will throw an `IOException`.
> Use `ErrorStream` to read the error response.


[0]: https://developer.android.com/reference/java/net/HttpURLConnection.html#getErrorStream()
  • Loading branch information
smstuebe authored and jonpryor committed Aug 26, 2016
1 parent 08ff8ba commit 5a4d965
Showing 1 changed file with 39 additions and 21 deletions.
60 changes: 39 additions & 21 deletions src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ protected void AssertSelf ()
// 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);
// 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) {
Expand All @@ -285,28 +285,20 @@ 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...");
// 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 <string> cookieHeaderValue;
Expand Down Expand Up @@ -334,6 +326,32 @@ protected void AssertSelf ()
return ret;
}

HttpContent GetErrorContent (HttpURLConnection httpConnection, HttpContent fallbackContent)
{
var contentStream = httpConnection.ErrorStream;

if (contentStream != null) {
return GetContent (httpConnection, contentStream);
}

return fallbackContent;
}

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)
{
if (!AllowAutoRedirect) {
Expand Down

0 comments on commit 5a4d965

Please sign in to comment.