From 8df358e48b75e78b6414d9188b03cf0fe5a89ad5 Mon Sep 17 00:00:00 2001 From: Brian Brazil Date: Mon, 29 Jul 2019 11:15:24 +0100 Subject: [PATCH] Handle slashes in pgw grouping label values. Good base64 support was only added in Java 8, we support back to Java 6 so this is a little unclean. Signed-off-by: Brian Brazil --- .../client/exporter/PushGateway.java | 26 ++++++++++++++++--- .../client/exporter/PushGatewayTest.java | 8 +++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/simpleclient_pushgateway/src/main/java/io/prometheus/client/exporter/PushGateway.java b/simpleclient_pushgateway/src/main/java/io/prometheus/client/exporter/PushGateway.java index 25894f683..161871acf 100644 --- a/simpleclient_pushgateway/src/main/java/io/prometheus/client/exporter/PushGateway.java +++ b/simpleclient_pushgateway/src/main/java/io/prometheus/client/exporter/PushGateway.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.MalformedURLException; @@ -15,6 +16,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import javax.xml.bind.DatatypeConverter; import io.prometheus.client.Collector; import io.prometheus.client.CollectorRegistry; @@ -79,7 +81,7 @@ public PushGateway(String address) { * @param serverBaseURL the base URL and optional context path of the Pushgateway server. */ public PushGateway(URL serverBaseURL) { - this.gatewayBaseURL = URI.create(serverBaseURL.toString() + "/metrics/job/") + this.gatewayBaseURL = URI.create(serverBaseURL.toString() + "/metrics/") .normalize() .toString(); } @@ -275,11 +277,20 @@ public void delete(String job, String instance) throws IOException { } void doRequest(CollectorRegistry registry, String job, Map groupingKey, String method) throws IOException { - String url = gatewayBaseURL + URLEncoder.encode(job, "UTF-8"); + String url = gatewayBaseURL; + if (job.contains("/")) { + url += "job@base64/" + base64url(job); + } else { + url += "job/" + URLEncoder.encode(job, "UTF-8"); + } if (groupingKey != null) { for (Map.Entry entry: groupingKey.entrySet()) { - url += "/" + entry.getKey() + "/" + URLEncoder.encode(entry.getValue(), "UTF-8"); + if (entry.getValue().contains("/")) { + url += "/" + entry.getKey() + "@base64/" + base64url(entry.getValue()); + } else { + url += "/" + entry.getKey() + "/" + URLEncoder.encode(entry.getValue(), "UTF-8"); + } } } HttpURLConnection connection = connectionFactory.create(url); @@ -318,6 +329,15 @@ void doRequest(CollectorRegistry registry, String job, Map group } } + private static String base64url(String v) { + // Per RFC4648 table 2. We support Java 6, and java.util.Base64 was only added in Java 8, + try { + return DatatypeConverter.printBase64Binary(v.getBytes("UTF-8")).replace("+", "-").replace("/", "_"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // Unreachable. + } + } + /** * Returns a grouping key with the instance label set to the machine's IP address. *

diff --git a/simpleclient_pushgateway/src/test/java/io/prometheus/client/exporter/PushGatewayTest.java b/simpleclient_pushgateway/src/test/java/io/prometheus/client/exporter/PushGatewayTest.java index 2445d61f9..e3be4dde5 100644 --- a/simpleclient_pushgateway/src/test/java/io/prometheus/client/exporter/PushGatewayTest.java +++ b/simpleclient_pushgateway/src/test/java/io/prometheus/client/exporter/PushGatewayTest.java @@ -45,7 +45,7 @@ public void testInvalidURLThrowsRuntimeException() { public void testMultipleSlashesAreStrippedFromURL() { final PushGateway pushGateway = new PushGateway("example.com:1234/context///path//"); Assert.assertEquals( - "http://example.com:1234/context/path/metrics/job/", + "http://example.com:1234/context/path/metrics/", pushGateway.gatewayBaseURL ); } @@ -106,9 +106,9 @@ public void testPushWithGroupingKeyWithSlashes() throws IOException { mockServerClient.when( request() .withMethod("PUT") - .withPath("/metrics/job/a%2Fb/l/v/l2/v%2F2") + .withPath("/metrics/job@base64/YS9i/l/v/l2@base64/75-_Lw==") ).respond(response().withStatusCode(202)); - groupingKey.put("l2", "v/2"); + groupingKey.put("l2", "\uF7FF/"); pg.push(registry, "a/b", groupingKey); } @@ -219,7 +219,7 @@ public void testOldPushWithSlashes() throws IOException { mockServerClient.when( request() .withMethod("PUT") - .withPath("/metrics/job/a%2Fb/instance/c%2Fd") + .withPath("/metrics/job@base64/YS9i/instance@base64/Yy9k") ).respond(response().withStatusCode(202)); pg.push(registry, "a/b", "c/d"); }