// Copyright 2004-present Facebook. All Rights Reserved.
package com.koushikdutta.async.stetho;
import android.util.Base64;
import android.util.Base64OutputStream;
import com.facebook.stetho.inspector.network.NetworkEventReporter;
import com.facebook.stetho.inspector.network.NetworkPeerManager;
import com.facebook.stetho.inspector.network.ResponseHandler;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.FilteredDataEmitter;
import com.koushikdutta.async.util.StreamUtility;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import javax.annotation.Nullable;
/**
* Implementation of {@link NetworkEventReporter} which allows callers to inform the Stetho
* system of network traffic. Callers can safely eagerly access this class and store a
* reference if they wish. When WebKit Inspector clients are connected, the internal
* implementation will be automatically wired up to them.
*/
class NetworkEventReporterWrapper implements NetworkEventReporter {
NetworkEventReporter wrapped = com.facebook.stetho.inspector.network.NetworkEventReporterImpl.get();
private static NetworkEventReporterWrapper instance;
public synchronized static NetworkEventReporterWrapper get() {
if (instance == null)
instance = new NetworkEventReporterWrapper();
return instance;
}
@Override
public boolean isEnabled() {
return wrapped.isEnabled();
}
@Override
public void requestWillBeSent(InspectorRequest inspectorRequest) {
wrapped.requestWillBeSent(inspectorRequest);
}
@Override
public void responseHeadersReceived(InspectorResponse inspectorResponse) {
wrapped.responseHeadersReceived(inspectorResponse);
}
@Override
public void httpExchangeFailed(String s, String s2) {
wrapped.httpExchangeFailed(s, s2);
}
@Nullable
@Override
public InputStream interpretResponseStream(
String requestId,
@Nullable String contentType,
@Nullable String contentEncoding,
@Nullable InputStream availableInputStream,
ResponseHandler responseHandler) {
return null;
}
@Nullable
private NetworkPeerManager getPeerManagerIfEnabled() {
NetworkPeerManager peerManager = NetworkPeerManager.getInstanceOrNull();
if (peerManager != null && peerManager.hasRegisteredPeers()) {
return peerManager;
}
return null;
}
public DataEmitter interpretResponseEmitter(final String requestId, @Nullable DataEmitter body, final boolean b64Encode) {
final NetworkPeerManager peerManager = getPeerManagerIfEnabled();
if (peerManager == null)
return null;
final WritableByteChannel channel;
try {
if (b64Encode) {
final Base64OutputStream b64out = new Base64OutputStream(peerManager.getResponseBodyFileManager().openResponseBodyFile(requestId, false), Base64.DEFAULT);
channel = Channels.newChannel(b64out);
}
else {
channel = ((FileOutputStream)peerManager.getResponseBodyFileManager().openResponseBodyFile(requestId, false)).getChannel();
}
}
catch (IOException e) {
return null;
}
FilteredDataEmitter ret = new FilteredDataEmitter() {
ByteBufferList pending = new ByteBufferList();
@Override
protected void report(Exception e) {
super.report(e);
StreamUtility.closeQuietly(channel);
if (e == null)
responseReadFinished(requestId);
else
responseReadFailed(requestId, e.toString());
}
@Override
public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
int amount = bb.remaining();
ByteBuffer[] original = bb.getAllArray();
ByteBuffer[] copy = new ByteBuffer[original.length];
for (int i = 0; i < original.length; i++) {
copy[i] = original[i].duplicate();
}
try {
for (ByteBuffer c: copy) {
channel.write(c);
}
}
catch (IOException ignored) {
StreamUtility.closeQuietly(channel);
}
pending.addAll(original);
dataReceived(requestId, amount, amount);
super.onDataAvailable(emitter, pending);
}
};
ret.setDataEmitter(body);
return ret;
}
@Override
public void responseReadFailed(String s, String s2) {
wrapped.responseReadFailed(s, s2);
}
@Override
public void responseReadFinished(String s) {
wrapped.responseReadFinished(s);
}
@Override
public void dataSent(String s, int i, int i2) {
wrapped.dataSent(s, i, i2);
}
@Override
public void dataReceived(String s, int i, int i2) {
wrapped.dataReceived(s, i, i2);
}
}