Skip to content

Commit

Permalink
Merge pull request #852 from epicadk/ak/gzip
Browse files Browse the repository at this point in the history
feat: Enable GZIP compression for request payloads
  • Loading branch information
jaredmixpanel authored Jan 30, 2025
2 parents f81ca22 + ef90ccb commit 85b4da1
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,32 @@ public void testSetMaximumDatabaseLimit2() {
assertEquals(100000000, mixpanelAPI.getMaximumDatabaseLimit());
}

@Test
public void testShouldGzipRequestPayload() {
final Bundle metaData = new Bundle();
metaData.putBoolean("com.mixpanel.android.MPConfig.GzipRequestPayload", true);
MPConfig mpConfig = mpConfig(metaData);
assertTrue(mpConfig.shouldGzipRequestPayload());

mpConfig.setShouldGzipRequestPayload(false);
assertFalse(mpConfig.shouldGzipRequestPayload());

mpConfig.setShouldGzipRequestPayload(true);
assertTrue(mpConfig.shouldGzipRequestPayload());

// assert false by default
MPConfig mpConfig2 = mpConfig(new Bundle());
assertFalse(mpConfig2.shouldGzipRequestPayload());

MixpanelAPI mixpanelAPI = mixpanelApi(mpConfig);

assertTrue(mixpanelAPI.shouldGzipRequestPayload());

mixpanelAPI.setShouldGzipRequestPayload(false);
assertFalse(mixpanelAPI.shouldGzipRequestPayload());

}

private MPConfig mpConfig(final Bundle metaData) {
return new MPConfig(metaData, InstrumentationRegistry.getInstrumentation().getContext(), null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ protected MPDbAdapter makeDbAdapter(Context context) {
}

protected RemoteService getPoster() {
return new HttpService();
return new HttpService(mConfig.shouldGzipRequestPayload());
}

////////////////////////////////////////////////////
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/mixpanel/android/mpmetrics/MPConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ public synchronized void setOfflineMode(OfflineMode offlineMode) {
mBulkUploadLimit = metaData.getInt("com.mixpanel.android.MPConfig.BulkUploadLimit", 40); // 40 records default
mFlushInterval = metaData.getInt("com.mixpanel.android.MPConfig.FlushInterval", 60 * 1000); // one minute default
mFlushBatchSize = metaData.getInt("com.mixpanel.android.MPConfig.FlushBatchSize", 50); // flush 50 events at a time by default
shouldGzipRequestPayload = metaData.getBoolean("com.mixpanel.android.MPConfig.GzipRequestPayload", false);
mFlushOnBackground = metaData.getBoolean("com.mixpanel.android.MPConfig.FlushOnBackground", true);
mMinimumDatabaseLimit = metaData.getInt("com.mixpanel.android.MPConfig.MinimumDatabaseLimit", 20 * 1024 * 1024); // 20 Mb
mMaximumDatabaseLimit = metaData.getInt("com.mixpanel.android.MPConfig.MaximumDatabaseLimit", Integer.MAX_VALUE); // 2 Gb
Expand Down Expand Up @@ -277,6 +278,10 @@ public int getFlushBatchSize() {
public void setFlushBatchSize(int flushBatchSize) {
mFlushBatchSize = flushBatchSize;
}
public boolean shouldGzipRequestPayload() { return shouldGzipRequestPayload; }

public void setShouldGzipRequestPayload(Boolean shouldGzip) { shouldGzipRequestPayload = shouldGzip; }


// Throw away records that are older than this in milliseconds. Should be below the server side age limit for events.
public long getDataExpiration() {
Expand Down Expand Up @@ -476,6 +481,7 @@ public String toString() {
private String mPeopleEndpoint;
private String mGroupsEndpoint;
private int mFlushBatchSize;
private boolean shouldGzipRequestPayload;

private final String mResourcePackageName;
private final int mMinSessionDuration;
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/mixpanel/android/mpmetrics/MixpanelAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,24 @@ public int getFlushBatchSize() {
return mConfig.getFlushBatchSize();
}

/**
* Set whether the request payload should be GZIP-compressed before being sent.
*
* @param shouldGzipRequestPayload boolean, true to enable GZIP compression, false otherwise.
*/
public void setShouldGzipRequestPayload(boolean shouldGzipRequestPayload) {
mConfig.setShouldGzipRequestPayload(shouldGzipRequestPayload);
}

/**
* Get whether the request payload is currently set to be GZIP-compressed.
*
* @return boolean, whether GZIP compression is enabled
*/
public boolean shouldGzipRequestPayload() {
return mConfig.shouldGzipRequestPayload();
}

/**
* Set an integer number of bytes, the maximum size limit to the Mixpanel database.
*
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/com/mixpanel/android/util/HttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.net.InetAddress;
import java.net.URL;
import java.util.Map;
import java.util.zip.GZIPOutputStream;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
Expand All @@ -27,10 +28,20 @@
*/
public class HttpService implements RemoteService {


private final boolean shouldGzipRequestPayload;

private static boolean sIsMixpanelBlocked;
private static final int MIN_UNAVAILABLE_HTTP_RESPONSE_CODE = HttpURLConnection.HTTP_INTERNAL_ERROR;
private static final int MAX_UNAVAILABLE_HTTP_RESPONSE_CODE = 599;

public HttpService(boolean shouldGzipRequestPayload) {
this.shouldGzipRequestPayload = shouldGzipRequestPayload;
}

public HttpService() {
this(false);
}
@Override
public void checkIsMixpanelBlocked() {
Thread t = new Thread(new Runnable() {
Expand Down Expand Up @@ -104,7 +115,7 @@ public byte[] performRequest(String endpointUrl, ProxyServerInteractor interacto
while (retries < 3 && !succeeded) {
InputStream in = null;
OutputStream out = null;
BufferedOutputStream bout = null;
OutputStream bout = null;
HttpURLConnection connection = null;

try {
Expand All @@ -131,12 +142,15 @@ public byte[] performRequest(String endpointUrl, ProxyServerInteractor interacto
builder.appendQueryParameter(param.getKey(), param.getValue().toString());
}
String query = builder.build().getEncodedQuery();

connection.setFixedLengthStreamingMode(query.getBytes().length);
if (shouldGzipRequestPayload) {
connection.setRequestProperty(CONTENT_ENCODING_HEADER, GZIP_CONTENT_TYPE_HEADER);
} else {
connection.setFixedLengthStreamingMode(query.getBytes().length);
}
connection.setDoOutput(true);
connection.setRequestMethod("POST");
out = connection.getOutputStream();
bout = new BufferedOutputStream(out);
bout = getBufferedOutputStream(out);
bout.write(query.getBytes("UTF-8"));
bout.flush();
bout.close();
Expand Down Expand Up @@ -179,6 +193,14 @@ public byte[] performRequest(String endpointUrl, ProxyServerInteractor interacto
return response;
}

private OutputStream getBufferedOutputStream(OutputStream out) throws IOException {
if(shouldGzipRequestPayload) {
return new GZIPOutputStream(new BufferedOutputStream(out), HTTP_OUTPUT_STREAM_BUFFER_SIZE);
} else {
return new BufferedOutputStream(out);
}
}

private static boolean isProxyRequest(String endpointUrl) {
return !endpointUrl.toLowerCase().contains(MIXPANEL_API.toLowerCase());
}
Expand All @@ -199,4 +221,7 @@ private static byte[] slurp(final InputStream inputStream)
}

private static final String LOGTAG = "MixpanelAPI.Message";
private static final int HTTP_OUTPUT_STREAM_BUFFER_SIZE = 8192;
private static final String CONTENT_ENCODING_HEADER = "Content-Encoding";
private static final String GZIP_CONTENT_TYPE_HEADER = "gzip";
}

0 comments on commit 85b4da1

Please sign in to comment.