From c188bc9be4888558829b330a08da6e88a7e8d663 Mon Sep 17 00:00:00 2001
From: Jessica Yuen <im.jessicayuen@gmail.com>
Date: Wed, 15 Nov 2017 12:35:08 -0800
Subject: [PATCH] Normalize environment server URL

As part of the environments feature, we want to be able to deploy to a
specific cluster given the environment's URI. We cross-check against
kubecfg for this URI's location. For fail-safe comparison, we probably
want to normalize these URIs.
---
 cmd/root.go             | 16 +++++++++++++---
 metadata/environment.go |  6 ++++++
 utils/strings.go        | 10 ++++++++++
 utils/strings_test.go   | 28 ++++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/cmd/root.go b/cmd/root.go
index 52e777ff..3bedfd69 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -347,7 +347,12 @@ func overrideCluster(envName string, clientConfig clientcmd.ClientConfig, overri
 
 	var servers = make(map[string]string)
 	for name, cluster := range rawConfig.Clusters {
-		servers[cluster.Server] = name
+		server, err := utils.NormalizeURL(cluster.Server)
+		if err != nil {
+			return err
+		}
+
+		servers[server] = name
 	}
 
 	//
@@ -361,8 +366,13 @@ func overrideCluster(envName string, clientConfig clientcmd.ClientConfig, overri
 		return err
 	}
 
-	if _, ok := servers[env.Server]; ok {
-		clusterName := servers[env.Server]
+	server, err := utils.NormalizeURL(env.Server)
+	if err != nil {
+		return err
+	}
+
+	if _, ok := servers[server]; ok {
+		clusterName := servers[server]
 		log.Debugf("Overwriting --cluster flag with '%s'", clusterName)
 		overrides.Context.Cluster = clusterName
 		log.Debugf("Overwriting --namespace flag with '%s'", env.Namespace)
diff --git a/metadata/environment.go b/metadata/environment.go
index 18b1b019..efcb9035 100644
--- a/metadata/environment.go
+++ b/metadata/environment.go
@@ -30,6 +30,7 @@ import (
 	"github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet"
 	"github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubespec"
 	param "github.com/ksonnet/ksonnet/metadata/params"
+	"github.com/ksonnet/ksonnet/utils"
 )
 
 const (
@@ -492,6 +493,11 @@ params + {
 }
 
 func generateSpecData(server, namespace string) ([]byte, error) {
+	server, err := utils.NormalizeURL(server)
+	if err != nil {
+		return nil, err
+	}
+
 	// Format the spec json and return; preface keys with 2 space idents.
 	return json.MarshalIndent(EnvironmentSpec{Server: server, Namespace: namespace}, "", "  ")
 }
diff --git a/utils/strings.go b/utils/strings.go
index c15dd077..fdd28a96 100644
--- a/utils/strings.go
+++ b/utils/strings.go
@@ -18,6 +18,8 @@ package utils
 import (
 	"bytes"
 	"strings"
+
+	"github.com/PuerkitoBio/purell"
 )
 
 // IsASCIIIdentifier takes a string and returns true if the string does not
@@ -32,6 +34,14 @@ func IsASCIIIdentifier(s string) bool {
 	return true
 }
 
+// NormalizeURL uses purell's "usually safe normalization" algorithm to
+// normalize URLs. This includes removing dot segments, removing trailing
+// slashes, removing unnecessary escapes, removing default ports, and setting
+// the URL to lowercase.
+func NormalizeURL(s string) (string, error) {
+	return purell.NormalizeURLString(s, purell.FlagsUsuallySafeGreedy)
+}
+
 func PadRows(rows [][]string) (string, error) {
 	maxRowLen := 0
 	for _, row := range rows {
diff --git a/utils/strings_test.go b/utils/strings_test.go
index 821608ab..3886e28c 100644
--- a/utils/strings_test.go
+++ b/utils/strings_test.go
@@ -53,6 +53,34 @@ func TestIsASCIIIdentifier(t *testing.T) {
 	}
 }
 
+func TestNormalizeURL(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{
+			input:    "host/path/./a/b/../c",
+			expected: "host/path/a/c",
+		},
+		{
+			input:    "HTTP://host",
+			expected: "http://host",
+		},
+		{
+			input:    "http://host:80",
+			expected: "http://host",
+		},
+	}
+	for _, test := range tests {
+		normalized, err := NormalizeURL(test.input)
+		if err != nil {
+			t.Error(err)
+		}
+
+		require.EqualValues(t, test.expected, normalized)
+	}
+}
+
 func TestPadRows(t *testing.T) {
 	tests := []struct {
 		input    [][]string
-- 
GitLab