/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.stetho.inspector.network;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.InflaterOutputStream;
/**
* Helper which manages provides computed request sizes as well as transparent decompression.
* Note that request compression is not officially part of the HTTP standard however it is
* commonly in use and can be conveniently supported here.
* <p />
* To use, invoke {@link #createBodySink} to prepare an output stream where the raw body can be
* written. Then invoke {@link #getDisplayBody()} to retrieve the possibly decoded body.
* Finally, {@link #reportDataSent()} can be called to report to Stetho the raw and decompressed
* payload sizes.
*/
public class RequestBodyHelper {
private final NetworkEventReporter mEventReporter;
private final String mRequestId;
private ByteArrayOutputStream mDeflatedOutput;
private CountingOutputStream mDeflatingOutput;
public RequestBodyHelper(NetworkEventReporter eventReporter, String requestId) {
mEventReporter = eventReporter;
mRequestId = requestId;
}
public OutputStream createBodySink(@Nullable String contentEncoding) throws IOException {
OutputStream deflatingOutput;
ByteArrayOutputStream deflatedOutput = new ByteArrayOutputStream();
if (DecompressionHelper.GZIP_ENCODING.equals(contentEncoding)) {
deflatingOutput = GunzippingOutputStream.create(deflatedOutput);
} else if (DecompressionHelper.DEFLATE_ENCODING.equals(contentEncoding)) {
deflatingOutput = new InflaterOutputStream(deflatedOutput);
} else {
deflatingOutput = deflatedOutput;
}
mDeflatingOutput = new CountingOutputStream(deflatingOutput);
mDeflatedOutput = deflatedOutput;
return mDeflatingOutput;
}
public byte[] getDisplayBody() {
throwIfNoBody();
return mDeflatedOutput.toByteArray();
}
public boolean hasBody() {
return mDeflatedOutput != null;
}
public void reportDataSent() {
throwIfNoBody();
mEventReporter.dataSent(
mRequestId,
mDeflatedOutput.size(),
(int)mDeflatingOutput.getCount());
}
private void throwIfNoBody() {
if (!hasBody()) {
throw new IllegalStateException("No body found; has createBodySink been called?");
}
}
}