Skip to content

Commit

Permalink
feat: add headers support for mixpanel proxy api calls
Browse files Browse the repository at this point in the history
  • Loading branch information
abhilashdas-cred committed Mar 20, 2024
1 parent cf8840b commit 92c0afe
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import com.mixpanel.android.util.Base64Coder;
import com.mixpanel.android.util.HttpService;
import com.mixpanel.android.util.MixpanelServerCallback;
import com.mixpanel.android.util.RemoteService;

import org.json.JSONArray;
Expand Down Expand Up @@ -62,7 +63,7 @@ public void setUp() {
private void setUpInstance(boolean trackAutomaticEvents) {
final RemoteService mockPoster = new HttpService() {
@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory) {
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory) {

final String jsonData = Base64Coder.decodeString(params.get("data").toString());
assertTrue(params.containsKey("data"));
Expand Down Expand Up @@ -211,7 +212,7 @@ public void testAutomaticMultipleInstances() throws InterruptedException {

final HttpService mpSecondPoster = new HttpService() {
@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory) {
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory) {
final String jsonData = Base64Coder.decodeString(params.get("data").toString());
assertTrue(params.containsKey("data"));
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import androidx.test.platform.app.InstrumentationRegistry;

import com.mixpanel.android.util.Base64Coder;
import com.mixpanel.android.util.MixpanelServerCallback;
import com.mixpanel.android.util.RemoteService;
import com.mixpanel.android.util.HttpService;

Expand Down Expand Up @@ -61,7 +62,7 @@ public void setUp() {

final RemoteService mockPoster = new HttpService() {
@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory)
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory)
throws ServiceUnavailableException, IOException {
try {
if (mFlushResults.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.mixpanel.android.BuildConfig;
import com.mixpanel.android.util.Base64Coder;
import com.mixpanel.android.util.HttpService;
import com.mixpanel.android.util.MixpanelServerCallback;
import com.mixpanel.android.util.RemoteService;

import org.json.JSONArray;
Expand Down Expand Up @@ -702,7 +703,7 @@ public int addJSON(JSONObject message, String token, MPDbAdapter.Table table) {

final RemoteService mockPoster = new HttpService() {
@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory) {
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory) {
final boolean isIdentified = isIdentifiedRef.get();
assertTrue(params.containsKey("data"));
final String decoded = Base64Coder.decodeString(params.get("data").toString());
Expand Down Expand Up @@ -1397,7 +1398,7 @@ protected AnalyticsMessages getAnalyticsMessages() {
public void testAlias() {
final RemoteService mockPoster = new HttpService() {
@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory) {
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory) {
try {
assertTrue(params.containsKey("data"));
final String jsonData = Base64Coder.decodeString(params.get("data").toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.mixpanel.android.util.Base64Coder;
import com.mixpanel.android.util.HttpService;
import com.mixpanel.android.util.MixpanelServerCallback;
import com.mixpanel.android.util.RemoteService;

import org.json.JSONArray;
Expand Down Expand Up @@ -57,7 +58,7 @@ public void setUp() {

final RemoteService mockPoster = new HttpService() {
@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory) {
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory) {
if (params != null) {
final String jsonData = Base64Coder.decodeString(params.get("data").toString());
assertTrue(params.containsKey("data"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ private void sendData(MPDbAdapter dbAdapter, String token, MPDbAdapter.Table tab
byte[] response;
try {
final SSLSocketFactory socketFactory = mConfig.getSSLSocketFactory();
response = poster.performRequest(url, params, socketFactory);
response = poster.performRequest(url, mConfig.getMixpanelServerCallback(), params, socketFactory);
if (null == response) {
deleteEvents = false;
logAboutMessageToMixpanel("Response was null, unexpected failure posting to " + url + ".");
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/mixpanel/android/mpmetrics/MPConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.mixpanel.android.BuildConfig;
import com.mixpanel.android.util.MPConstants;
import com.mixpanel.android.util.MPLog;
import com.mixpanel.android.util.MixpanelServerCallback;
import com.mixpanel.android.util.OfflineMode;

import java.security.GeneralSecurityException;
Expand Down Expand Up @@ -303,6 +304,11 @@ public String getEventsEndpoint() {

public boolean getTrackAutomaticEvents() { return mTrackAutomaticEvents; }

public void setServerURL(String serverURL, MixpanelServerCallback callback) {
setServerURL(serverURL);
setMixpanelServerCallback(callback);
}

// In parity with iOS SDK
public void setServerURL(String serverURL) {
setEventsEndpointWithBaseURL(serverURL);
Expand Down Expand Up @@ -413,6 +419,14 @@ public synchronized OfflineMode getOfflineMode() {

///////////////////////////////////////////////

public MixpanelServerCallback getMixpanelServerCallback() {
return this.serverCallbacks;
}

public void setMixpanelServerCallback(MixpanelServerCallback callback) {
this.serverCallbacks = callback;
}

// Package access for testing only- do not call directly in library code
/* package */ static MPConfig readConfig(Context appContext, String instanceName) {
final String packageName = appContext.getPackageName();
Expand Down Expand Up @@ -472,5 +486,6 @@ public String toString() {
// Mutable, with synchronized accessor and mutator
private SSLSocketFactory mSSLSocketFactory;
private OfflineMode mOfflineMode;
private MixpanelServerCallback serverCallbacks = null;
private static final String LOGTAG = "MixpanelAPI.Conf";
}
12 changes: 12 additions & 0 deletions src/main/java/com/mixpanel/android/mpmetrics/MixpanelAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import android.os.Bundle;

import com.mixpanel.android.util.MPLog;
import com.mixpanel.android.util.MixpanelServerCallback;

import org.json.JSONArray;
import org.json.JSONException;
Expand Down Expand Up @@ -580,6 +581,17 @@ public void setServerURL(String serverURL) {
mConfig.setServerURL(serverURL);
}

/**
* Set the base URL used for Mixpanel API requests.
* Useful if you need to proxy Mixpanel requests. Defaults to https://api.mixpanel.com.
* To route data to Mixpanel's EU servers, set to https://api-eu.mixpanel.com
*
* @param serverURL the base URL used for Mixpanel API requests
* @param callback the callback for mixpanel proxy server api headers and status
*/
public void setServerURL(String serverURL, MixpanelServerCallback callback) {
mConfig.setServerURL(serverURL, callback);
}

public Boolean getTrackAutomaticEvents() { return mTrackAutomaticEvents; }
/**
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/com/mixpanel/android/util/HttpService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mixpanel.android.util;

import static com.mixpanel.android.util.MPConstants.URL.MIXPANEL_API;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
Expand Down Expand Up @@ -88,7 +90,7 @@ private boolean onOfflineMode(OfflineMode offlineMode) {
}

@Override
public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory) throws ServiceUnavailableException, IOException {
public byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory) throws ServiceUnavailableException, IOException {
MPLog.v(LOGTAG, "Attempting request to " + endpointUrl);

byte[] response = null;
Expand All @@ -112,6 +114,15 @@ public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSL
((HttpsURLConnection) connection).setSSLSocketFactory(socketFactory);
}

if (shouldProcessMixpanelCallback(endpointUrl) && callback != null) {
Map<String,String> headers = callback.getHeaders();
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
}

connection.setConnectTimeout(2000);
connection.setReadTimeout(30000);
if (null != params) {
Expand All @@ -133,6 +144,9 @@ public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSL
out.close();
out = null;
}
if (shouldProcessMixpanelCallback(endpointUrl) && callback != null) {
callback.onResponse(endpointUrl, connection.getResponseCode());
}
in = connection.getInputStream();
response = slurp(in);
in.close();
Expand Down Expand Up @@ -165,6 +179,10 @@ public byte[] performRequest(String endpointUrl, Map<String, Object> params, SSL
return response;
}

private static boolean shouldProcessMixpanelCallback(String endpointUrl) {
return !endpointUrl.toLowerCase().contains(MIXPANEL_API.toLowerCase());
}

private static byte[] slurp(final InputStream inputStream)
throws IOException {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.mixpanel.android.util;

import java.util.Map;

public interface MixpanelServerCallback {
Map<String, String> getHeaders();

void onResponse(String apiPath, int responseCode);
}
2 changes: 1 addition & 1 deletion src/main/java/com/mixpanel/android/util/RemoteService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface RemoteService {

void checkIsMixpanelBlocked();

byte[] performRequest(String endpointUrl, Map<String, Object> params, SSLSocketFactory socketFactory)
byte[] performRequest(String endpointUrl, MixpanelServerCallback callback, Map<String, Object> params, SSLSocketFactory socketFactory)
throws ServiceUnavailableException, IOException;

class ServiceUnavailableException extends Exception {
Expand Down

0 comments on commit 92c0afe

Please sign in to comment.