Repository: Unleash/unleash-client-java
Pull request #35 (2017-06-15 23:57:07)

Add support for custom HTTP headers in API calls
This commit adds a map of custom HTTP headers to UnleashConfig, and
includes these headers in calls to the Unleash server. This may be used
to, e.g., add an `Authorization` field if the server is behind a wrapper
or proxy which requires authentication.

See Unleash/unleash#222 on GitHub for background discussion.


Patch:
diff --git a/src/main/java/no/finn/unleash/metric/UnleashMetricsSender.java b/src/main/java/no/finn/unleash/metric/UnleashMetricsSender.java
index 209adaa3..00d354de 100644
--- a/src/main/java/no/finn/unleash/metric/UnleashMetricsSender.java
+++ b/src/main/java/no/finn/unleash/metric/UnleashMetricsSender.java
@@ -75,8 +75,7 @@ public class UnleashMetricsSender {
             connection.setRequestMethod("POST");
             connection.setRequestProperty("Accept", "application/json");
             connection.setRequestProperty("Content-Type", "application/json");
-            connection.setRequestProperty("UNLEASH-APPNAME", this.unleashConfig.getAppName());
-            connection.setRequestProperty("UNLEASH-INSTANCEID", this.unleashConfig.getInstanceId());
+            UnleashConfig.setRequestProperties(connection, this.unleashConfig);
             connection.setUseCaches (false);
             connection.setDoInput(true);
             connection.setDoOutput(true);
diff --git a/src/main/java/no/finn/unleash/repository/HttpToggleFetcher.java b/src/main/java/no/finn/unleash/repository/HttpToggleFetcher.java
index dd397c0e..d4e5c1c1 100644
--- a/src/main/java/no/finn/unleash/repository/HttpToggleFetcher.java
+++ b/src/main/java/no/finn/unleash/repository/HttpToggleFetcher.java
@@ -31,9 +31,7 @@ public final class HttpToggleFetcher implements ToggleFetcher {
             connection.setReadTimeout(CONNECT_TIMEOUT);
             connection.setRequestProperty("Accept", "application/json");
             connection.setRequestProperty("Content-Type", "application/json");
-            connection.setRequestProperty("UNLEASH-APPNAME", this.unleashConfig.getAppName());
-            connection.setRequestProperty("UNLEASH-INSTANCEID", this.unleashConfig.getInstanceId());
-
+            UnleashConfig.setRequestProperties(connection, this.unleashConfig);
             connection.setRequestProperty("If-None-Match", etag);
             connection.setUseCaches(true);
             connection.connect();
diff --git a/src/main/java/no/finn/unleash/util/UnleashConfig.java b/src/main/java/no/finn/unleash/util/UnleashConfig.java
index 3ef02253..830a5222 100644
--- a/src/main/java/no/finn/unleash/util/UnleashConfig.java
+++ b/src/main/java/no/finn/unleash/util/UnleashConfig.java
@@ -1,15 +1,22 @@
 package no.finn.unleash.util;
 
 import java.io.File;
+import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
 
 import no.finn.unleash.UnleashContextProvider;
 
 public class UnleashConfig {
+    static final String UNLEASH_APP_NAME_HEADER = "UNLEASH-APPNAME";
+    static final String UNLEASH_INSTANCE_ID_HEADER = "UNLEASH-INSTANCEID";
+
     private final URI unleashAPI;
     private final UnleashURLs unleashURLs;
+    private final Map<String, String> customHttpHeaders;
     private final String appName;
     private final String instanceId;
     private final String backupFile;
@@ -20,6 +27,7 @@ public class UnleashConfig {
 
     public UnleashConfig(
             URI unleashAPI,
+            Map<String, String> customHttpHeaders,
             String appName,
             String instanceId,
             String backupFile,
@@ -38,6 +46,7 @@ public class UnleashConfig {
         }
 
         this.unleashAPI = unleashAPI;
+        this.customHttpHeaders = customHttpHeaders;
         this.unleashURLs = new UnleashURLs(unleashAPI);
         this.appName = appName;
         this.instanceId = instanceId;
@@ -52,6 +61,10 @@ public class UnleashConfig {
         return unleashAPI;
     }
 
+    public Map<String, String> getCustomHttpHeaders() {
+        return customHttpHeaders;
+    }
+
     public String getAppName() {
         return appName;
     }
@@ -88,8 +101,18 @@ public class UnleashConfig {
         return contextProvider;
     }
 
+    public static void setRequestProperties(HttpURLConnection connection, UnleashConfig config) {
+        connection.setRequestProperty(UNLEASH_APP_NAME_HEADER, config.getAppName());
+        connection.setRequestProperty(UNLEASH_INSTANCE_ID_HEADER, config.getInstanceId());
+        connection.setRequestProperty("User-Agent", config.getAppName());
+        config.getCustomHttpHeaders().forEach((name, value) -> {
+            connection.setRequestProperty(name, value);
+        });
+    }
+
     public static class Builder {
         private URI unleashAPI;
+        private Map<String, String> customHttpHeaders = new HashMap<>();
         private String appName;
         private String instanceId = getDefaultInstanceId();
         private String backupFile;
@@ -118,6 +141,11 @@ public class UnleashConfig {
             return this;
         }
 
+        public Builder customHttpHeader(String name, String value) {
+            this.customHttpHeaders.put(name, value);
+            return this;
+        }
+
         public Builder appName(String appName) {
             this.appName = appName;
             return this;
@@ -165,6 +193,7 @@ public class UnleashConfig {
         public UnleashConfig build() {
             return new UnleashConfig(
                     unleashAPI,
+                    customHttpHeaders,
                     appName,
                     instanceId,
                     getBackupFile(),


Test patch:
diff --git a/src/test/java/no/finn/unleash/util/UnleashConfigTest.java b/src/test/java/no/finn/unleash/util/UnleashConfigTest.java
index 82410017..8bb41361 100644
--- a/src/test/java/no/finn/unleash/util/UnleashConfigTest.java
+++ b/src/test/java/no/finn/unleash/util/UnleashConfigTest.java
@@ -1,9 +1,13 @@
 package no.finn.unleash.util;
 
-import org.junit.Test;
-
+import java.io.IOException;
+import java.net.HttpURLConnection;
 import java.net.URI;
+import java.net.URL;
+import org.junit.Test;
 
+import static no.finn.unleash.util.UnleashConfig.UNLEASH_APP_NAME_HEADER;
+import static no.finn.unleash.util.UnleashConfig.UNLEASH_INSTANCE_ID_HEADER;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
 
@@ -59,4 +63,45 @@ public class UnleashConfigTest {
         assertThat(config.getAppName(), is("my-app"));
         assertThat(config.getBackupFile(), is("/test/unleash-backup.json"));
     }
-}
\ No newline at end of file
+
+    @Test
+    public void should_add_app_name_and_instance_id_and_user_agent_to_connection() throws IOException {
+        String appName = "my-app";
+        String instanceId = "my-instance-1";
+        String unleashAPI = "http://unleash.org";
+
+        UnleashConfig unleashConfig = UnleashConfig.builder()
+                .appName(appName)
+                .instanceId(instanceId)
+                .unleashAPI(unleashAPI)
+                .build();
+
+        URL someUrl = new URL(unleashAPI + "/some/arbitrary/path");
+        HttpURLConnection connection = (HttpURLConnection) someUrl.openConnection();
+
+        UnleashConfig.setRequestProperties(connection, unleashConfig);
+        assertThat(connection.getRequestProperty(UNLEASH_APP_NAME_HEADER), is(appName));
+        assertThat(connection.getRequestProperty(UNLEASH_INSTANCE_ID_HEADER), is(instanceId));
+        assertThat(connection.getRequestProperty("User-Agent"), is(appName));
+    }
+
+    @Test
+    public void should_add_custom_headers_to_connection_if_present() throws IOException {
+        String unleashAPI = "http://unleash.org";
+        String headerName = "UNLEASH-CUSTOM-TEST-HEADER";
+        String headerValue = "Some value";
+
+        UnleashConfig unleashConfig = UnleashConfig.builder()
+                .appName("my-app")
+                .instanceId("my-instance-1")
+                .unleashAPI(unleashAPI)
+                .customHttpHeader(headerName, headerValue)
+                .build();
+
+        URL someUrl = new URL(unleashAPI + "/some/arbitrary/path");
+        HttpURLConnection connection = (HttpURLConnection) someUrl.openConnection();
+
+        UnleashConfig.setRequestProperties(connection, unleashConfig);
+        assertThat(connection.getRequestProperty(headerName), is(headerValue));
+    }
+}