Skip to content

Commit a43c37f

Browse files
committed
fix
1 parent 1bb242a commit a43c37f

File tree

3 files changed

+71
-50
lines changed

3 files changed

+71
-50
lines changed

common4j/src/main/com/microsoft/identity/common/java/exception/ConnectionError.kt

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,19 @@
2222
// THE SOFTWARE.
2323
package com.microsoft.identity.common.java.exception
2424

25+
import java.io.EOFException
26+
import java.net.ConnectException
27+
import java.net.SocketException
28+
import java.net.SocketTimeoutException
29+
import java.net.UnknownHostException
30+
import javax.net.ssl.SSLException
31+
2532
enum class ConnectionError(val value: String) {
26-
FAILED_TO_OPEN_CONNECTION("ce_failed_to_open_connection"),
27-
FAILED_TO_SET_REQUEST_METHOD("ce_failed_to_set_request_method"),
28-
FAILED_TO_WRITE_TO_OUTPUT_STREAM("ce_failed_to_write_to_output_stream"),
29-
FAILED_TO_READ_FROM_INPUT_STREAM("ce_failed_to_read_from_input_stream"),
30-
FAILED_TO_GET_RESPONSE_CODE("ce_failed_to_get_response_code"),
33+
NO_NETWORK("ce_no_network"),
34+
NETWORK_TEMPORARILY_UNAVAILABLE("ce_network_temporarily_unavailable"),
35+
UNEXPECTED_EXCEPTION("ce_unexpected_exception"),
3136
CONNECTION_TIMEOUT("ce_connection_timeout");
3237

33-
/**
34-
* Converts this [ConnectionError] into a [ClientException]
35-
**/
36-
fun getClientException(cause: Throwable): ClientException {
37-
val e = ClientException(
38-
ClientException.IO_ERROR,
39-
"An IO error occurred in the network layer: " + cause.message,
40-
cause
41-
)
42-
e.subErrorCode = value
43-
return e
44-
}
45-
4638
/**
4739
* Returns true if the given [Throwable] is a connection error.
4840
**/
@@ -53,4 +45,46 @@ enum class ConnectionError(val value: String) {
5345

5446
return this.value == throwable.subErrorCode
5547
}
48+
49+
companion object {
50+
/**
51+
* Converts this [ConnectionError] into a [ClientException]
52+
**/
53+
@JvmStatic
54+
fun getClientException(cause: Throwable): ClientException {
55+
val e = ClientException(
56+
ClientException.IO_ERROR,
57+
"An IO error occurred in the network layer: " + cause.message,
58+
cause
59+
)
60+
61+
e.subErrorCode = getConnectionError(cause).value
62+
return e
63+
}
64+
65+
/**
66+
* Converts a [Throwable] into a suberrorCode
67+
**/
68+
private fun getConnectionError(cause: Throwable): ConnectionError {
69+
if (cause is SocketTimeoutException) {
70+
// Slow or unreliable network
71+
return CONNECTION_TIMEOUT
72+
}
73+
74+
if (cause is EOFException // Unexpected disconnect
75+
|| cause is SSLException // SSL Handshake failed
76+
|| cause is ConnectException // Remote socket connection failed
77+
) {
78+
return NETWORK_TEMPORARILY_UNAVAILABLE
79+
}
80+
81+
if (cause is UnknownHostException // Unable to query DNS for hostname
82+
|| cause is SocketException // No conn to remote socket, or Airplane mode, or no internet permission will hit this
83+
) {
84+
return NO_NETWORK
85+
}
86+
87+
return UNEXPECTED_EXCEPTION
88+
}
89+
}
5690
}

common4j/src/main/com/microsoft/identity/common/java/net/UrlConnectionHttpClient.java

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,19 @@
4848

4949
import java.io.BufferedReader;
5050
import java.io.Closeable;
51+
import java.io.EOFException;
5152
import java.io.IOException;
5253
import java.io.InputStream;
5354
import java.io.InputStreamReader;
5455
import java.io.OutputStream;
56+
import java.net.ConnectException;
5557
import java.net.HttpURLConnection;
58+
import java.net.NoRouteToHostException;
5659
import java.net.ProtocolException;
60+
import java.net.SocketException;
5761
import java.net.SocketTimeoutException;
5862
import java.net.URL;
63+
import java.net.UnknownHostException;
5964
import java.util.Date;
6065
import java.util.HashMap;
6166
import java.util.List;
@@ -66,6 +71,7 @@
6671
import javax.annotation.Nullable;
6772
import javax.net.ssl.HttpsURLConnection;
6873
import javax.net.ssl.SSLContext;
74+
import javax.net.ssl.SSLException;
6975
import javax.net.ssl.SSLSocketFactory;
7076

7177
import io.opentelemetry.api.trace.Span;
@@ -313,7 +319,7 @@ private static HttpRequest constructHttpRequest(@NonNull HttpClient.HttpMethod h
313319
* @return The converted string
314320
* @throws IOException Thrown when failing to access inputStream stream.
315321
*/
316-
private String convertStreamToString(final InputStream inputStream) throws ClientException {
322+
private String convertStreamToString(final InputStream inputStream) throws IOException {
317323
try {
318324
final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,
319325
AuthenticationConstants.CHARSET_UTF8));
@@ -326,8 +332,6 @@ private String convertStreamToString(final InputStream inputStream) throws Clien
326332
}
327333

328334
return stringBuilder.toString();
329-
} catch (IOException e) {
330-
throw ConnectionError.FAILED_TO_READ_FROM_INPUT_STREAM.getClientException(e);
331335
} finally {
332336
safeCloseStream(inputStream);
333337
}
@@ -353,31 +357,25 @@ private static void safeCloseStream(final Closeable stream) {
353357
}
354358

355359
private HttpResponse executeHttpSend(HttpRequest request, Consumer<HttpResponse> completionCallback) throws ClientException {
356-
final HttpURLConnection urlConnection = setupConnection(request);
357-
358-
sendRequest(urlConnection, request.getRequestContent(), request.getRequestHeaders().get(HttpConstants.HeaderField.CONTENT_TYPE));
359-
360360
InputStream responseStream = null;
361361
HttpResponse response = null;
362362
try {
363+
final HttpURLConnection urlConnection = setupConnection(request);
364+
sendRequest(urlConnection, request.getRequestContent(), request.getRequestHeaders().get(HttpConstants.HeaderField.CONTENT_TYPE));
365+
363366
try {
364367
responseStream = urlConnection.getInputStream();
365368
} catch (final SocketTimeoutException e) {
366369
// SocketTimeoutExcetion is thrown when connection timeout happens. For connection
367370
// timeout, we want to retry once. Throw the exception to the upper layer, and the
368371
// upper layer will handle the retry.
369-
throw ConnectionError.CONNECTION_TIMEOUT.getClientException(e);
372+
throw ConnectionError.getClientException(e);
370373
} catch (final IOException ioException) {
371374
// 404, for example, will generate an exception. We should catch it.
372375
responseStream = urlConnection.getErrorStream();
373376
}
374377

375-
final int statusCode;
376-
try {
377-
statusCode = urlConnection.getResponseCode();
378-
} catch (IOException e) {
379-
throw ConnectionError.FAILED_TO_GET_RESPONSE_CODE.getClientException(e);
380-
}
378+
final int statusCode = urlConnection.getResponseCode();
381379

382380
final Date date = new Date(urlConnection.getDate());
383381

@@ -419,7 +417,8 @@ private HttpResponse executeHttpSend(HttpRequest request, Consumer<HttpResponse>
419417
AttributeName.http_status_code.name(),
420418
response.getStatusCode()
421419
);
422-
420+
} catch (final IOException e) {
421+
throw ConnectionError.getClientException(e);
423422
} finally {
424423
completionCallback.accept(response);
425424
safeCloseStream(responseStream);
@@ -428,14 +427,9 @@ private HttpResponse executeHttpSend(HttpRequest request, Consumer<HttpResponse>
428427
return response;
429428
}
430429

431-
private HttpURLConnection setupConnection(HttpRequest request) throws ClientException {
430+
private HttpURLConnection setupConnection(HttpRequest request) throws IOException {
432431
final String methodName = ":setupConnection";
433-
final HttpURLConnection urlConnection;
434-
try {
435-
urlConnection = HttpUrlConnectionFactory.createHttpURLConnection(request.getRequestUrl());
436-
} catch (IOException e) {
437-
throw ConnectionError.FAILED_TO_OPEN_CONNECTION.getClientException(e);
438-
}
432+
final HttpURLConnection urlConnection = HttpUrlConnectionFactory.createHttpURLConnection(request.getRequestUrl());
439433

440434
// Apply request headers and update the headers with default attributes first
441435
final Set<Map.Entry<String, String>> headerEntries = request.getRequestHeaders().entrySet();
@@ -454,12 +448,7 @@ private HttpURLConnection setupConnection(HttpRequest request) throws ClientExce
454448
Logger.warn(TAG + methodName, "gets a request from an unexpected protocol: " + request.getRequestUrl().getProtocol());
455449
}
456450

457-
try {
458-
urlConnection.setRequestMethod(request.getRequestMethod());
459-
} catch (ProtocolException e) {
460-
throw ConnectionError.FAILED_TO_SET_REQUEST_METHOD.getClientException(e);
461-
}
462-
451+
urlConnection.setRequestMethod(request.getRequestMethod());
463452
urlConnection.setConnectTimeout(getConnectTimeoutMs());
464453
urlConnection.setReadTimeout(getReadTimeoutMs());
465454
urlConnection.setInstanceFollowRedirects(true);
@@ -479,7 +468,7 @@ private int getConnectTimeoutMs() {
479468

480469
private static void sendRequest(@NonNull final HttpURLConnection connection,
481470
final byte[] contentRequest,
482-
final String requestContentType) throws ClientException {
471+
final String requestContentType) throws IOException {
483472
if (contentRequest == null) {
484473
return;
485474
}
@@ -497,8 +486,6 @@ private static void sendRequest(@NonNull final HttpURLConnection connection,
497486
try {
498487
out = connection.getOutputStream();
499488
out.write(contentRequest);
500-
} catch (IOException e) {
501-
throw ConnectionError.FAILED_TO_WRITE_TO_OUTPUT_STREAM.getClientException(e);
502489
} finally {
503490
safeCloseStream(out);
504491
}

common4j/src/test/com/microsoft/identity/common/java/net/UrlConnectionHttpClientTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,7 @@ public void testConnectingToTLS13ServerWhileEnforcing12OnClientSide() throws Cli
12181218
);
12191219
Assert.fail();
12201220
} catch (ClientException e){
1221-
Assert.assertTrue(ConnectionError.FAILED_TO_GET_RESPONSE_CODE.compare(e));
1221+
Assert.assertTrue(ConnectionError.NETWORK_TEMPORARILY_UNAVAILABLE.compare(e));
12221222
}
12231223
}
12241224

0 commit comments

Comments
 (0)