From f3edfb36db4638b3c3352ca8ff7476074e44f76a Mon Sep 17 00:00:00 2001 From: Chaiwat Ekkaewnumchai Date: Wed, 22 Apr 2020 09:26:01 -0700 Subject: [PATCH] Fix Stream Closed IOException Summary: Original Issue: https://github.com/facebook/flipper/issues/993 The exception occurs when OkHttp and we try to read request body twice, while it can be only read once. Hence, we will read request body after it is processed by OkHttp. Tradeoff for this is requests on Flipper will not appear immediately after fired, but they will appear together with their responses. There are ways we can get rid of the tradeoff. For example, as demonstrated in D21167308, OkHttp ^3.14.0 contains method `isOneShot`, which can be used to check if we can read request body more than once. Another example is to change server side to accept nullable variable so that we can send request body and others separately. Reviewed By: passy Differential Revision: D21175341 fbshipit-source-id: 053789a2c2f28cd8149ea1bb36fd0cfe1c668df7 --- .../network/FlipperOkhttpInterceptor.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/android/plugins/network/src/main/java/com/facebook/flipper/plugins/network/FlipperOkhttpInterceptor.java b/android/plugins/network/src/main/java/com/facebook/flipper/plugins/network/FlipperOkhttpInterceptor.java index 01b4b62b8..929cf82a2 100644 --- a/android/plugins/network/src/main/java/com/facebook/flipper/plugins/network/FlipperOkhttpInterceptor.java +++ b/android/plugins/network/src/main/java/com/facebook/flipper/plugins/network/FlipperOkhttpInterceptor.java @@ -87,7 +87,7 @@ public class FlipperOkhttpInterceptor public Response intercept(Interceptor.Chain chain) throws IOException { final Request request = chain.request(); final String identifier = UUID.randomUUID().toString(); - mPlugin.reportRequest(convertRequest(request, identifier)); + final RequestInfo requestInfo = convertRequestWithoutBody(request, identifier); // Check if there is a mock response final Response mockResponse = mIsMockResponseSupported ? getMockResponse(request) : null; @@ -95,6 +95,15 @@ public class FlipperOkhttpInterceptor final ResponseBody body = response.body(); final ResponseInfo responseInfo = convertResponse(response, body, identifier); responseInfo.isMock = mockResponse != null; + // Add request body + try { + if (request.body() != null) { + requestInfo.body = bodyToByteArray(request, mMaxBodyBytes); + } + } catch (IOException e) { + // We can safely ignore this as some requests don't allow their body to be read more than once + } + mPlugin.reportRequest(requestInfo); mPlugin.reportResponse(responseInfo); return response; } @@ -108,7 +117,8 @@ public class FlipperOkhttpInterceptor return buffer.readByteArray(Math.min(buffer.size(), maxBodyBytes)); } - private RequestInfo convertRequest(Request request, String identifier) throws IOException { + private RequestInfo convertRequestWithoutBody(Request request, String identifier) + throws IOException { final List headers = convertHeader(request.headers()); final RequestInfo info = new RequestInfo(); info.requestId = identifier; @@ -116,9 +126,6 @@ public class FlipperOkhttpInterceptor info.headers = headers; info.method = request.method(); info.uri = request.url().toString(); - if (request.body() != null) { - info.body = bodyToByteArray(request, mMaxBodyBytes); - } return info; }