Make network a separate plugin
Summary: Per title. Reviewed By: jknoxville Differential Revision: D17419678 fbshipit-source-id: aee00f077b7ed955c60884853dc1128d27366ee8
This commit is contained in:
committed by
Facebook Github Bot
parent
7ac82bec4e
commit
c4a9b603e2
25
android/plugins/network/build.gradle
Normal file
25
android/plugins/network/build.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the LICENSE
|
||||
* file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.compileSdkVersion
|
||||
buildToolsVersion rootProject.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.minSdkVersion
|
||||
targetSdkVersion rootProject.targetSdkVersion
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':android')
|
||||
implementation deps.okhttp3
|
||||
compileOnly deps.jsr305
|
||||
}
|
||||
}
|
||||
11
android/plugins/network/src/main/AndroidManifest.xml
Normal file
11
android/plugins/network/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Facebook, Inc. and its affiliates.
|
||||
~
|
||||
~ This source code is licensed under the MIT license found in the LICENSE
|
||||
~ file in the root directory of this source tree.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.facebook.flipper.plugins.network">
|
||||
</manifest>
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the LICENSE
|
||||
* file in the root directory of this source tree.
|
||||
*/
|
||||
package com.facebook.flipper.plugins.network;
|
||||
|
||||
import com.facebook.flipper.plugins.network.NetworkReporter.RequestInfo;
|
||||
import com.facebook.flipper.plugins.network.NetworkReporter.ResponseInfo;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okio.Buffer;
|
||||
import okio.BufferedSource;
|
||||
|
||||
public class FlipperOkhttpInterceptor implements Interceptor {
|
||||
|
||||
public @Nullable NetworkFlipperPlugin plugin;
|
||||
|
||||
public FlipperOkhttpInterceptor() {
|
||||
this.plugin = null;
|
||||
}
|
||||
|
||||
public FlipperOkhttpInterceptor(NetworkFlipperPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Interceptor.Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
String identifier = UUID.randomUUID().toString();
|
||||
plugin.reportRequest(convertRequest(request, identifier));
|
||||
Response response = chain.proceed(request);
|
||||
ResponseBody body = response.body();
|
||||
ResponseInfo responseInfo = convertResponse(response, body, identifier);
|
||||
plugin.reportResponse(responseInfo);
|
||||
return response;
|
||||
}
|
||||
|
||||
private static byte[] bodyToByteArray(final Request request) throws IOException {
|
||||
final Buffer buffer = new Buffer();
|
||||
request.body().writeTo(buffer);
|
||||
return buffer.readByteArray();
|
||||
}
|
||||
|
||||
private RequestInfo convertRequest(Request request, String identifier) throws IOException {
|
||||
List<NetworkReporter.Header> headers = convertHeader(request.headers());
|
||||
RequestInfo info = new RequestInfo();
|
||||
info.requestId = identifier;
|
||||
info.timeStamp = System.currentTimeMillis();
|
||||
info.headers = headers;
|
||||
info.method = request.method();
|
||||
info.uri = request.url().toString();
|
||||
if (request.body() != null) {
|
||||
info.body = bodyToByteArray(request);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private ResponseInfo convertResponse(Response response, ResponseBody body, String identifier)
|
||||
throws IOException {
|
||||
List<NetworkReporter.Header> headers = convertHeader(response.headers());
|
||||
ResponseInfo info = new ResponseInfo();
|
||||
info.requestId = identifier;
|
||||
info.timeStamp = response.receivedResponseAtMillis();
|
||||
info.statusCode = response.code();
|
||||
info.headers = headers;
|
||||
BufferedSource source = body.source();
|
||||
source.request(Long.MAX_VALUE);
|
||||
Buffer buffer = source.buffer().clone();
|
||||
info.body = buffer.readByteArray();
|
||||
return info;
|
||||
}
|
||||
|
||||
private List<NetworkReporter.Header> convertHeader(Headers headers) {
|
||||
List<NetworkReporter.Header> list = new ArrayList<>();
|
||||
|
||||
Set<String> keys = headers.names();
|
||||
for (String key : keys) {
|
||||
list.add(new NetworkReporter.Header(key, headers.get(key)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the LICENSE
|
||||
* file in the root directory of this source tree.
|
||||
*/
|
||||
package com.facebook.flipper.plugins.network;
|
||||
|
||||
import android.util.Base64;
|
||||
import com.facebook.flipper.core.ErrorReportingRunnable;
|
||||
import com.facebook.flipper.core.FlipperArray;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.plugins.common.BufferingFlipperPlugin;
|
||||
import java.util.List;
|
||||
|
||||
public class NetworkFlipperPlugin extends BufferingFlipperPlugin implements NetworkReporter {
|
||||
public static final String ID = "Network";
|
||||
|
||||
private final List<NetworkResponseFormatter> mFormatters;
|
||||
|
||||
public NetworkFlipperPlugin() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public NetworkFlipperPlugin(List<NetworkResponseFormatter> formatters) {
|
||||
this.mFormatters = formatters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportRequest(RequestInfo requestInfo) {
|
||||
final FlipperObject request =
|
||||
new FlipperObject.Builder()
|
||||
.put("id", requestInfo.requestId)
|
||||
.put("timestamp", requestInfo.timeStamp)
|
||||
.put("method", requestInfo.method)
|
||||
.put("url", requestInfo.uri)
|
||||
.put("headers", toFlipperObject(requestInfo.headers))
|
||||
.put("data", toBase64(requestInfo.body))
|
||||
.build();
|
||||
|
||||
send("newRequest", request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportResponse(final ResponseInfo responseInfo) {
|
||||
final Runnable job =
|
||||
new ErrorReportingRunnable(getConnection()) {
|
||||
@Override
|
||||
protected void runOrThrow() throws Exception {
|
||||
if (shouldStripResponseBody(responseInfo)) {
|
||||
responseInfo.body = null;
|
||||
}
|
||||
|
||||
final FlipperObject response =
|
||||
new FlipperObject.Builder()
|
||||
.put("id", responseInfo.requestId)
|
||||
.put("timestamp", responseInfo.timeStamp)
|
||||
.put("status", responseInfo.statusCode)
|
||||
.put("reason", responseInfo.statusReason)
|
||||
.put("headers", toFlipperObject(responseInfo.headers))
|
||||
.put("data", toBase64(responseInfo.body))
|
||||
.build();
|
||||
|
||||
send("newResponse", response);
|
||||
}
|
||||
};
|
||||
|
||||
if (mFormatters != null) {
|
||||
for (NetworkResponseFormatter formatter : mFormatters) {
|
||||
if (formatter.shouldFormat(responseInfo)) {
|
||||
formatter.format(
|
||||
responseInfo,
|
||||
new NetworkResponseFormatter.OnCompletionListener() {
|
||||
@Override
|
||||
public void onCompletion(final String json) {
|
||||
responseInfo.body = json.getBytes();
|
||||
job.run();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
job.run();
|
||||
}
|
||||
|
||||
private String toBase64(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
return new String(Base64.encode(bytes, Base64.DEFAULT));
|
||||
}
|
||||
|
||||
private FlipperArray toFlipperObject(List<Header> headers) {
|
||||
final FlipperArray.Builder list = new FlipperArray.Builder();
|
||||
|
||||
for (Header header : headers) {
|
||||
list.put(new FlipperObject.Builder().put("key", header.name).put("value", header.value));
|
||||
}
|
||||
|
||||
return list.build();
|
||||
}
|
||||
|
||||
private static boolean shouldStripResponseBody(ResponseInfo responseInfo) {
|
||||
final Header contentType = responseInfo.getFirstHeader("content-type");
|
||||
if (contentType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return contentType.value.contains("image/")
|
||||
|| contentType.value.contains("video/")
|
||||
|| contentType.value.contains("application/zip");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the LICENSE
|
||||
* file in the root directory of this source tree.
|
||||
*/
|
||||
package com.facebook.flipper.plugins.network;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public interface NetworkReporter {
|
||||
void reportRequest(RequestInfo requestInfo);
|
||||
|
||||
void reportResponse(ResponseInfo responseInfo);
|
||||
|
||||
public class Header {
|
||||
public final String name;
|
||||
public final String value;
|
||||
|
||||
public Header(final String name, final String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Header{" + name + ": " + value + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public class RequestInfo {
|
||||
public String requestId;
|
||||
public long timeStamp;
|
||||
public List<Header> headers = new ArrayList<>();
|
||||
public String method;
|
||||
public String uri;
|
||||
public byte[] body;
|
||||
|
||||
public Header getFirstHeader(final String name) {
|
||||
for (Header header : headers) {
|
||||
if (name.equalsIgnoreCase(header.name)) {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ResponseInfo {
|
||||
public String requestId;
|
||||
public long timeStamp;
|
||||
public int statusCode;
|
||||
public String statusReason;
|
||||
public List<Header> headers = new ArrayList<>();
|
||||
public byte[] body;
|
||||
|
||||
public Header getFirstHeader(final String name) {
|
||||
for (Header header : headers) {
|
||||
if (name.equalsIgnoreCase(header.name)) {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the LICENSE
|
||||
* file in the root directory of this source tree.
|
||||
*/
|
||||
package com.facebook.flipper.plugins.network;
|
||||
|
||||
import com.facebook.flipper.plugins.network.NetworkReporter.ResponseInfo;
|
||||
|
||||
public interface NetworkResponseFormatter {
|
||||
|
||||
interface OnCompletionListener {
|
||||
void onCompletion(String json);
|
||||
}
|
||||
|
||||
boolean shouldFormat(ResponseInfo response);
|
||||
|
||||
void format(ResponseInfo response, OnCompletionListener onCompletionListener);
|
||||
}
|
||||
Reference in New Issue
Block a user