NetworkingModule extends ReactContextBaseJavaModule { @ReactMethod public void sendRequest( final ExecutorToken executorToken, String method, String url, final int requestId, ReadableArray headers, ReadableMap data, final boolean useIncrementalUpdates, int timeout) { Request.Builder requestBuilder = new Request.Builder().url(url); if (requestId != 0) { requestBuilder.tag(requestId); } OkHttpClient client = mClient; if (timeout != mClient.getConnectTimeout()) { client = mClient.clone(); client.setReadTimeout(timeout, TimeUnit.MILLISECONDS); } Headers requestHeaders = extractHeaders(headers, data); if (requestHeaders == null) { onRequestError(executorToken, requestId, "Unrecognized headers format"); return; } String contentType = requestHeaders.get(CONTENT_TYPE_HEADER_NAME); String contentEncoding = requestHeaders.get(CONTENT_ENCODING_HEADER_NAME); requestBuilder.headers(requestHeaders); if (data == null) { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { onRequestError( executorToken, requestId, "Payload is set but no content-type header specified"); return; } String body = data.getString(REQUEST_BODY_KEY_STRING); MediaType contentMediaType = MediaType.parse(contentType); if (RequestBodyUtil.isGzipEncoding(contentEncoding)) { RequestBody requestBody = RequestBodyUtil.createGzip(contentMediaType, body); if (requestBody == null) { onRequestError(executorToken, requestId, "Failed to gzip request body"); return; } requestBuilder.method(method, requestBody); } else { requestBuilder.method(method, RequestBody.create(contentMediaType, body)); } } else if (data.hasKey(REQUEST_BODY_KEY_URI)) { if (contentType == null) { onRequestError( executorToken, requestId, "Payload is set but no content-type header specified"); return; } String uri = data.getString(REQUEST_BODY_KEY_URI); InputStream fileInputStream = RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); if (fileInputStream == null) { onRequestError(executorToken, requestId, "Could not retrieve file for uri " + uri); return; } requestBuilder.method( method, RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; } ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA); MultipartBuilder multipartBuilder = constructMultipartBody(executorToken, parts, contentType, requestId); if (multipartBuilder == null) { return; } requestBuilder.method(method, multipartBuilder.build()); } else { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } client.newCall(requestBuilder.build()).enqueue( new Callback() { @Override public void onFailure(Request request, IOException e) { if (mShuttingDown) { return; } onRequestError(executorToken, requestId, e.getMessage()); } @Override public void onResponse(Response response) throws IOException { if (mShuttingDown) { return; } onResponseReceived(executorToken, requestId, response); ResponseBody responseBody = response.body(); try { if (useIncrementalUpdates) { readWithProgress(executorToken, requestId, responseBody); onRequestSuccess(executorToken, requestId); } else { onDataReceived(executorToken, requestId, responseBody.string()); onRequestSuccess(executorToken, requestId); } } catch (IOException e) { onRequestError(executorToken, requestId, e.getMessage()); } } }); } NetworkingModule(
      ReactApplicationContext reactContext,
      @Nullable String defaultUserAgent,
      OkHttpClient client);  NetworkingModule(final ReactApplicationContext context);  NetworkingModule(ReactApplicationContext context, String defaultUserAgent);  NetworkingModule(ReactApplicationContext reactContext, OkHttpClient client); @Override void initialize(); @Override String getName(); @Override void onCatalystInstanceDestroy(); @ReactMethod /** * @param timeout value of 0 results in no timeout */ void sendRequest(
      final ExecutorToken executorToken,
      String method,
      String url,
      final int requestId,
      ReadableArray headers,
      ReadableMap data,
      final boolean useIncrementalUpdates,
      int timeout); @ReactMethod void abortRequest(ExecutorToken executorToken, final int requestId); @ReactMethod void clearCookies(
      ExecutorToken executorToken,
      com.facebook.react.bridge.Callback callback); @Override boolean supportsWebWorkers();  }
@Test public void testGetWithoutHeaders() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http: 0, JavaOnlyArray.of(), null, true, 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http: assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(1); assertThat(argumentCaptor.getValue().method()).isEqualTo("GET"); }
@Test public void testFailGetWithInvalidHeadersStruct() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); List<JavaOnlyArray> invalidHeaders = Arrays.asList(JavaOnlyArray.of("foo")); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http: 0, JavaOnlyArray.from(invalidHeaders), null, true, 0); verifyErrorEmit(emitter, 0); }
@Test public void testFailPostWithoutContentType() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); JavaOnlyMap body = new JavaOnlyMap(); body.putString("string", "This is request body"); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http: 0, JavaOnlyArray.of(), body, true, 0); verifyErrorEmit(emitter, 0); }
@Test public void testSuccessfulPostRequest() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient); JavaOnlyMap body = new JavaOnlyMap(); body.putString("string", "This is request body"); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http: 0, JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "text/plain")), body, true, 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http: assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(2); assertThat(argumentCaptor.getValue().method()).isEqualTo("POST"); assertThat(argumentCaptor.getValue().body().contentType().type()).isEqualTo("text"); assertThat(argumentCaptor.getValue().body().contentType().subtype()).isEqualTo("plain"); Buffer contentBuffer = new Buffer(); argumentCaptor.getValue().body().writeTo(contentBuffer); assertThat(contentBuffer.readUtf8()).isEqualTo("This is request body"); }
@Test public void testHeaders() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient); List<JavaOnlyArray> headers = Arrays.asList( JavaOnlyArray.of("Accept", "text/plain"), JavaOnlyArray.of("User-Agent", "React test agent/1.0")); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http: 0, JavaOnlyArray.from(headers), null, true, 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); Headers requestHeaders = argumentCaptor.getValue().headers(); assertThat(requestHeaders.size()).isEqualTo(2); assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain"); assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0"); }
@Test public void testMultipartPostRequestSimple() throws Exception { PowerMockito.mockStatic(RequestBodyUtil.class); when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class))) .thenReturn(mock(InputStream.class)); when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class))) .thenReturn(mock(RequestBody.class)); JavaOnlyMap body = new JavaOnlyMap(); JavaOnlyArray formData = new JavaOnlyArray(); JavaOnlyMap bodyPart = new JavaOnlyMap(); bodyPart.putString("string", "value"); bodyPart.putArray( "headers", JavaOnlyArray.from( Arrays.asList( JavaOnlyArray.of("content-disposition", "name")))); formData.pushMap(bodyPart); body.putArray("formData", formData); OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http: 0, new JavaOnlyArray(), body, true, 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http: assertThat(argumentCaptor.getValue().method()).isEqualTo("POST"); assertThat(argumentCaptor.getValue().body().contentType().type()). isEqualTo(MultipartBuilder.FORM.type()); assertThat(argumentCaptor.getValue().body().contentType().subtype()). isEqualTo(MultipartBuilder.FORM.subtype()); Headers requestHeaders = argumentCaptor.getValue().headers(); assertThat(requestHeaders.size()).isEqualTo(1); }
@Test public void testMultipartPostRequestHeaders() throws Exception { PowerMockito.mockStatic(RequestBodyUtil.class); when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class))) .thenReturn(mock(InputStream.class)); when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class))) .thenReturn(mock(RequestBody.class)); List<JavaOnlyArray> headers = Arrays.asList( JavaOnlyArray.of("Accept", "text/plain"), JavaOnlyArray.of("User-Agent", "React test agent/1.0"), JavaOnlyArray.of("content-type", "multipart/form-data")); JavaOnlyMap body = new JavaOnlyMap(); JavaOnlyArray formData = new JavaOnlyArray(); JavaOnlyMap bodyPart = new JavaOnlyMap(); bodyPart.putString("string", "value"); bodyPart.putArray( "headers", JavaOnlyArray.from( Arrays.asList( JavaOnlyArray.of("content-disposition", "name")))); formData.pushMap(bodyPart); body.putArray("formData", formData); OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http: 0, JavaOnlyArray.from(headers), body, true, 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http: assertThat(argumentCaptor.getValue().method()).isEqualTo("POST"); assertThat(argumentCaptor.getValue().body().contentType().type()). isEqualTo(MultipartBuilder.FORM.type()); assertThat(argumentCaptor.getValue().body().contentType().subtype()). isEqualTo(MultipartBuilder.FORM.subtype()); Headers requestHeaders = argumentCaptor.getValue().headers(); assertThat(requestHeaders.size()).isEqualTo(3); assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain"); assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0"); assertThat(requestHeaders.get("content-type")).isEqualTo("multipart/form-data"); }
@Test public void testMultipartPostRequestBody() throws Exception { InputStream inputStream = mock(InputStream.class); PowerMockito.mockStatic(RequestBodyUtil.class); when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class))) .thenReturn(inputStream); when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class))).thenCallRealMethod(); when(inputStream.available()).thenReturn("imageUri".length()); final MultipartBuilder multipartBuilder = mock(MultipartBuilder.class); PowerMockito.whenNew(MultipartBuilder.class).withNoArguments().thenReturn(multipartBuilder); when(multipartBuilder.type(any(MediaType.class))).thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return multipartBuilder; } }); when(multipartBuilder.addPart(any(Headers.class), any(RequestBody.class))).thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return multipartBuilder; } }); when(multipartBuilder.build()).thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return mock(RequestBody.class); } }); List<JavaOnlyArray> headers = Arrays.asList( JavaOnlyArray.of("content-type", "multipart/form-data")); JavaOnlyMap body = new JavaOnlyMap(); JavaOnlyArray formData = new JavaOnlyArray(); body.putArray("formData", formData); JavaOnlyMap bodyPart = new JavaOnlyMap(); bodyPart.putString("string", "locale"); bodyPart.putArray( "headers", JavaOnlyArray.from( Arrays.asList( JavaOnlyArray.of("content-disposition", "user")))); formData.pushMap(bodyPart); JavaOnlyMap imageBodyPart = new JavaOnlyMap(); imageBodyPart.putString("uri", "imageUri"); imageBodyPart.putArray( "headers", JavaOnlyArray.from( Arrays.asList( JavaOnlyArray.of("content-type", "image/jpg"), JavaOnlyArray.of("content-disposition", "filename=photo.jpg")))); formData.pushMap(imageBodyPart); OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http: 0, JavaOnlyArray.from(headers), body, true, 0); PowerMockito.verifyStatic(times(1)); RequestBodyUtil.getFileInputStream(any(ReactContext.class), eq("imageUri")); PowerMockito.verifyStatic(times(1)); RequestBodyUtil.create(MediaType.parse("image/jpg"), inputStream); verify(multipartBuilder).build(); verify(multipartBuilder).type(MultipartBuilder.FORM); ArgumentCaptor<Headers> headersArgumentCaptor = ArgumentCaptor.forClass(Headers.class); ArgumentCaptor<RequestBody> bodyArgumentCaptor = ArgumentCaptor.forClass(RequestBody.class); verify(multipartBuilder, times(2)). addPart(headersArgumentCaptor.capture(), bodyArgumentCaptor.capture()); List<Headers> bodyHeaders = headersArgumentCaptor.getAllValues(); assertThat(bodyHeaders.size()).isEqualTo(2); List<RequestBody> bodyRequestBody = bodyArgumentCaptor.getAllValues(); assertThat(bodyRequestBody.size()).isEqualTo(2); assertThat(bodyHeaders.get(0).get("content-disposition")).isEqualTo("user"); assertThat(bodyRequestBody.get(0).contentType()).isNull(); assertThat(bodyRequestBody.get(0).contentLength()).isEqualTo("locale".getBytes().length); assertThat(bodyHeaders.get(1).get("content-disposition")).isEqualTo("filename=photo.jpg"); assertThat(bodyRequestBody.get(1).contentType()).isEqualTo(MediaType.parse("image/jpg")); assertThat(bodyRequestBody.get(1).contentLength()).isEqualTo("imageUri".getBytes().length); }