From 6b0c7c912ec9126277d217026b1f745cc59a31be Mon Sep 17 00:00:00 2001 From: Ajay Date: Fri, 7 Dec 2018 15:26:06 -0500 Subject: [PATCH 1/7] Fix PathTemplate matcher to match path with protocol and hostname --- .../java/com/google/api/pathtemplate/PathTemplate.java | 9 ++++++--- .../com/google/api/pathtemplate/PathTemplateTest.java | 10 ++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index 9ed440bcf..dd9161cf8 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -132,6 +132,9 @@ public class PathTemplate { // A regexp to match a custom verb at the end of a path. private static final Pattern CUSTOM_VERB_PATTERN = Pattern.compile(":([^/*}{=]+)$"); + // A regex to match a hostname with or without protocol. + private static final Pattern HOSTNAME_PATTERN = Pattern.compile("^(\\w+:)?//"); + // A splitter on slash. private static final Splitter SLASH_SPLITTER = Splitter.on('/').trimResults(); @@ -533,10 +536,10 @@ private Map match(String path, boolean forceHostName) { path = path.substring(0, matcher.start(0)); } - // Do full match. - boolean withHostName = path.startsWith("//"); + Matcher matcher = HOSTNAME_PATTERN.matcher(path); + boolean withHostName = matcher.find(); if (withHostName) { - path = path.substring(2); + path = matcher.replaceFirst(""); } List input = SLASH_SPLITTER.splitToList(path); int inPos = 0; diff --git a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java index b5149ddb2..563f0338a 100644 --- a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java +++ b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java @@ -83,6 +83,16 @@ public void matchWithHostName() { Truth.assertThat(match.get("$1")).isEqualTo("o"); } + @Test + public void matchWithHostNameAndProtocol() { + PathTemplate template = PathTemplate.create("buckets/*/objects/*"); + Map match = template.match("http://somewhere.io/buckets/b/objects/o"); + Truth.assertThat(match).isNotNull(); + Truth.assertThat(match.get(PathTemplate.HOSTNAME_VAR)).isEqualTo("http://somewhere.io"); + Truth.assertThat(match.get("$0")).isEqualTo("b"); + Truth.assertThat(match.get("$1")).isEqualTo("o"); + } + @Test public void matchWithCustomMethod() { PathTemplate template = PathTemplate.create("buckets/*/objects/*:custom"); From 476770b14208a1aa53c863e18acb15a1a5585de2 Mon Sep 17 00:00:00 2001 From: Ajay Date: Fri, 7 Dec 2018 15:42:37 -0500 Subject: [PATCH 2/7] fix hostname --- src/main/java/com/google/api/pathtemplate/PathTemplate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index dd9161cf8..129d84c1e 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -551,7 +551,7 @@ private Map match(String path, boolean forceHostName) { String hostName = input.get(inPos++); if (withHostName) { // Put the // back, so we can distinguish this case from forceHostName. - hostName = "//" + hostName; + hostName = matcher.group(0) + hostName; } values.put(HOSTNAME_VAR, hostName); } From d362f46639f07ca322ccaa643e0ce24da657cf33 Mon Sep 17 00:00:00 2001 From: Ajay Date: Fri, 7 Dec 2018 23:28:31 -0500 Subject: [PATCH 3/7] fix and add test case for compute project zone parsing --- .../com/google/api/pathtemplate/PathTemplate.java | 13 +++++++++++++ .../google/api/pathtemplate/PathTemplateTest.java | 11 ++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index 129d84c1e..0bd4e40fd 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -555,12 +555,25 @@ private Map match(String path, boolean forceHostName) { } values.put(HOSTNAME_VAR, hostName); } + if (withHostName && segments.get(0).kind() == SegmentKind.LITERAL) { + inPos = alignInputPositionToLiteralSegment(input, inPos, segments.get(0).value()); + } if (!match(input, inPos, segments, 0, values)) { return null; } return ImmutableMap.copyOf(values); } + private int alignInputPositionToLiteralSegment(List input, int inPos, + String literalSegmentValue) { + for (; inPos < input.size(); inPos++) { + if (literalSegmentValue.equals(input.get(inPos))) { + return inPos; + } + } + return inPos; + } + // Tries to match the input based on the segments at given positions. Returns a boolean // indicating whether the match was successful. private boolean match( diff --git a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java index 563f0338a..323979b14 100644 --- a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java +++ b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java @@ -85,12 +85,13 @@ public void matchWithHostName() { @Test public void matchWithHostNameAndProtocol() { - PathTemplate template = PathTemplate.create("buckets/*/objects/*"); - Map match = template.match("http://somewhere.io/buckets/b/objects/o"); + PathTemplate template = PathTemplate.create("projects/{project}/zones/{zone}"); + Map match = template + .match("https://www.googleapis.com/compute/v1/projects/project-123/zones/europe-west3-c"); Truth.assertThat(match).isNotNull(); - Truth.assertThat(match.get(PathTemplate.HOSTNAME_VAR)).isEqualTo("http://somewhere.io"); - Truth.assertThat(match.get("$0")).isEqualTo("b"); - Truth.assertThat(match.get("$1")).isEqualTo("o"); + Truth.assertThat(match.get(PathTemplate.HOSTNAME_VAR)).isEqualTo("https://www.googleapis.com"); + Truth.assertThat(match.get("project")).isEqualTo("project-123"); + Truth.assertThat(match.get("zone")).isEqualTo("europe-west3-c"); } @Test From 1875829e0376f6ce372f041c17460469a403b49a Mon Sep 17 00:00:00 2001 From: Ajay Date: Fri, 7 Dec 2018 23:41:16 -0500 Subject: [PATCH 4/7] fix formatting --- src/main/java/com/google/api/pathtemplate/PathTemplate.java | 5 +++-- .../java/com/google/api/pathtemplate/PathTemplateTest.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index 0bd4e40fd..3afede0ca 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -564,8 +564,9 @@ private Map match(String path, boolean forceHostName) { return ImmutableMap.copyOf(values); } - private int alignInputPositionToLiteralSegment(List input, int inPos, - String literalSegmentValue) { + // Aligns input to start of literal segment if input contains hostname. + private int alignInputPositionToLiteralSegment( + List input, int inPos, String literalSegmentValue) { for (; inPos < input.size(); inPos++) { if (literalSegmentValue.equals(input.get(inPos))) { return inPos; diff --git a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java index 323979b14..4fc6d3610 100644 --- a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java +++ b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java @@ -86,8 +86,9 @@ public void matchWithHostName() { @Test public void matchWithHostNameAndProtocol() { PathTemplate template = PathTemplate.create("projects/{project}/zones/{zone}"); - Map match = template - .match("https://www.googleapis.com/compute/v1/projects/project-123/zones/europe-west3-c"); + Map match = + template.match( + "https://www.googleapis.com/compute/v1/projects/project-123/zones/europe-west3-c"); Truth.assertThat(match).isNotNull(); Truth.assertThat(match.get(PathTemplate.HOSTNAME_VAR)).isEqualTo("https://www.googleapis.com"); Truth.assertThat(match.get("project")).isEqualTo("project-123"); From e513bfabaa6b25c1d0a25b9fa4fe4c093e3d566d Mon Sep 17 00:00:00 2001 From: Ajay Date: Mon, 10 Dec 2018 14:03:48 -0500 Subject: [PATCH 5/7] add comment for HOSTNAME_VAR --- src/main/java/com/google/api/pathtemplate/PathTemplate.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index 3afede0ca..e86ccfd1f 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -125,7 +125,8 @@ public class PathTemplate { /** * A constant identifying the special variable used for endpoint bindings in the result of - * {@link #matchFromFullName(String)}. + * {@link #matchFromFullName(String)}. It may also contain protocol string, if its provided + * in the input. */ public static final String HOSTNAME_VAR = "$hostname"; From 08868bdf42ac4254650480929e73b69e06df7eb9 Mon Sep 17 00:00:00 2001 From: Ajay Date: Mon, 10 Dec 2018 14:31:19 -0500 Subject: [PATCH 6/7] fix format --- src/main/java/com/google/api/pathtemplate/PathTemplate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index e86ccfd1f..aed552c75 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -125,8 +125,8 @@ public class PathTemplate { /** * A constant identifying the special variable used for endpoint bindings in the result of - * {@link #matchFromFullName(String)}. It may also contain protocol string, if its provided - * in the input. + * {@link #matchFromFullName(String)}. It may also contain protocol string, if its provided in the + * input. */ public static final String HOSTNAME_VAR = "$hostname"; From 8d75255d264f5a25e0a63fc3b075f7789d9132ce Mon Sep 17 00:00:00 2001 From: Ajay Date: Tue, 11 Dec 2018 10:26:03 -0500 Subject: [PATCH 7/7] fix when template starts with binding segment --- .../google/api/pathtemplate/PathTemplate.java | 20 +++++++++++++++---- .../api/pathtemplate/PathTemplateTest.java | 12 +++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index aed552c75..6edcddcca 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -556,8 +556,8 @@ private Map match(String path, boolean forceHostName) { } values.put(HOSTNAME_VAR, hostName); } - if (withHostName && segments.get(0).kind() == SegmentKind.LITERAL) { - inPos = alignInputPositionToLiteralSegment(input, inPos, segments.get(0).value()); + if (withHostName) { + inPos = alignInputToAlignableSegment(input, inPos, segments.get(0)); } if (!match(input, inPos, segments, 0, values)) { return null; @@ -565,8 +565,20 @@ private Map match(String path, boolean forceHostName) { return ImmutableMap.copyOf(values); } - // Aligns input to start of literal segment if input contains hostname. - private int alignInputPositionToLiteralSegment( + // Aligns input to start of literal value of literal or binding segment if input contains hostname. + private int alignInputToAlignableSegment(List input, int inPos, Segment segment) { + switch (segment.kind()) { + case BINDING: + inPos = alignInputPositionToLiteral(input, inPos, segment.value() + "s"); + return inPos + 1; + case LITERAL: + return alignInputPositionToLiteral(input, inPos, segment.value()); + } + return inPos; + } + + // Aligns input to start of literal value if input contains hostname. + private int alignInputPositionToLiteral( List input, int inPos, String literalSegmentValue) { for (; inPos < input.size(); inPos++) { if (literalSegmentValue.equals(input.get(inPos))) { diff --git a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java index 4fc6d3610..69d935fc1 100644 --- a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java +++ b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java @@ -95,6 +95,18 @@ public void matchWithHostNameAndProtocol() { Truth.assertThat(match.get("zone")).isEqualTo("europe-west3-c"); } + @Test + public void matchWithHostNameAndProtocolWithTemplateStartWithBinding() { + PathTemplate template = PathTemplate.create("{project}/zones/{zone}"); + Map match = + template.match( + "https://www.googleapis.com/compute/v1/projects/project-123/zones/europe-west3-c"); + Truth.assertThat(match).isNotNull(); + Truth.assertThat(match.get(PathTemplate.HOSTNAME_VAR)).isEqualTo("https://www.googleapis.com"); + Truth.assertThat(match.get("project")).isEqualTo("project-123"); + Truth.assertThat(match.get("zone")).isEqualTo("europe-west3-c"); + } + @Test public void matchWithCustomMethod() { PathTemplate template = PathTemplate.create("buckets/*/objects/*:custom");