Skip to content

Commit 11bca65

Browse files
Allow URLs with paths in NormalizeURL (#474)
This change also makes it an error to specify a URL scheme that is not "https" or "http" instead of silently changing an invalid scheme to "http". Signed-off-by: Mark S. Lewis <Mark.S.Lewis@outlook.com>
1 parent 1c0e3f8 commit 11bca65

File tree

10 files changed

+4088
-54
lines changed

10 files changed

+4088
-54
lines changed

lib/client.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"os"
2020
"path"
2121
"path/filepath"
22-
"strconv"
2322
"strings"
2423

2524
idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto"
@@ -971,38 +970,44 @@ func newCfsslKeyRequest(bkr *api.KeyRequest) *csr.KeyRequest {
971970
return &csr.KeyRequest{A: bkr.Algo, S: bkr.Size}
972971
}
973972

974-
// NormalizeURL normalizes a URL (from cfssl)
973+
// NormalizeURL normalizes a full or partial URL to a full URL, using
974+
// configuration for missing elements.
975975
func NormalizeURL(addr string) (*url.URL, error) {
976976
addr = strings.TrimSpace(addr)
977+
if addr == "" {
978+
addr = util.GetServerURL()
979+
}
980+
977981
u, err := url.Parse(addr)
978982
if err != nil {
979983
return nil, err
980984
}
985+
981986
if u.Opaque != "" {
982-
u.Host = net.JoinHostPort(u.Scheme, u.Opaque)
987+
port, path, found := strings.Cut(u.Opaque, "/")
988+
if found {
989+
u = u.JoinPath(path)
990+
}
991+
u.Host = net.JoinHostPort(u.Scheme, port)
992+
u.Scheme = ""
983993
u.Opaque = ""
984-
} else if u.Path != "" && !strings.Contains(u.Path, ":") {
994+
} else if u.Host == "" {
985995
u.Host = net.JoinHostPort(u.Path, util.GetServerPort())
986996
u.Path = ""
987-
} else if u.Scheme == "" {
988-
u.Host = u.Path
989-
u.Path = ""
997+
} else if u.Port() == "" {
998+
u.Host = net.JoinHostPort(u.Host, util.GetServerPort())
990999
}
991-
if u.Scheme != "https" {
1000+
1001+
if u.Scheme == "" {
9921002
u.Scheme = "http"
1003+
} else if !isValidScheme(u.Scheme) {
1004+
return nil, errors.Errorf("invalid scheme: %s", u.Scheme)
9931005
}
994-
_, port, err := net.SplitHostPort(u.Host)
995-
if err != nil {
996-
_, port, err = net.SplitHostPort(u.Host + ":" + util.GetServerPort())
997-
if err != nil {
998-
return nil, err
999-
}
1000-
}
1001-
if port != "" {
1002-
_, err = strconv.Atoi(port)
1003-
if err != nil {
1004-
return nil, err
1005-
}
1006-
}
1007-
return u, nil
1006+
1007+
// Parse again to ensure URL contains no invalid characters
1008+
return url.Parse(u.String())
1009+
}
1010+
1011+
func isValidScheme(scheme string) bool {
1012+
return scheme == "http" || scheme == "https"
10081013
}

lib/client_test.go

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/hyperledger/fabric-lib-go/bccsp"
2828
"github.com/pkg/errors"
2929
"github.com/stretchr/testify/assert"
30+
"github.com/stretchr/testify/require"
3031
)
3132

3233
var (
@@ -1320,39 +1321,75 @@ func setupGenCRLTest(t *testing.T, serverHome, clientHome string) (*Server, *Ide
13201321
return server, adminID
13211322
}
13221323

1323-
func TestNormalizeUrl(t *testing.T) {
1324-
u, err := NormalizeURL("")
1325-
if err != nil {
1326-
t.Errorf("normalizeURL empty: %s", err)
1327-
} else {
1328-
t.Logf("URL %s, %s, %s", u.Scheme, u.Host, u.Path)
1329-
}
1330-
u, err = NormalizeURL("http://host:7054/path")
1331-
if err != nil {
1332-
t.Errorf("normalizeURL failed: %s", err)
1333-
} else {
1334-
t.Logf("URL %s, %s, %s", u.Scheme, u.Host, u.Path)
1335-
}
1336-
u, err = NormalizeURL("https://localhost:80/a%2Fb%2Fc")
1337-
if err != nil {
1338-
t.Errorf("NormalizeURL failed: %s", err)
1339-
} else {
1340-
t.Logf("URL %s, %s, %s", u.Scheme, u.Host, u.Path)
1341-
}
1342-
_, err = NormalizeURL("[")
1343-
t.Logf("NormalizeURL() error %v", err)
1344-
if err == nil {
1345-
t.Errorf("NormalizeURL '[' should have failed")
1346-
}
1347-
_, err = NormalizeURL("http://[/path")
1348-
t.Logf("NormalizeURL() error %v", err)
1349-
if err == nil {
1350-
t.Errorf("NormalizeURL 'http://[/path]' should have failed")
1324+
func TestNormalizeURL(t *testing.T) {
1325+
for testName, testData := range map[string]struct {
1326+
input string
1327+
expected string
1328+
}{
1329+
"HTTP server URL is accepted": {
1330+
input: "http://host:9876",
1331+
expected: "http://host:9876",
1332+
},
1333+
"HTTPS server URL is accepted": {
1334+
input: "https://host:9876",
1335+
expected: "https://host:9876",
1336+
},
1337+
"HTTP scheme if only host and port specified": {
1338+
input: "host:9876",
1339+
expected: "http://host:9876",
1340+
},
1341+
"HTTP scheme and default port if only host specified": {
1342+
input: "host",
1343+
expected: "http://host:7054",
1344+
},
1345+
"default port if only scheme and host specified": {
1346+
input: "http://host",
1347+
expected: "http://host:7054",
1348+
},
1349+
"URL with path is accepted": {
1350+
input: "http://host:9876/path",
1351+
expected: "http://host:9876/path",
1352+
},
1353+
"HTTP scheme if host, port and path specified": {
1354+
input: "host:9876/path",
1355+
expected: "http://host:9876/path",
1356+
},
1357+
"URL encoded characters in path are unmodified": {
1358+
input: "http://host:9876/a%2Fb%2Fc",
1359+
expected: "http://host:9876/a%2Fb%2Fc",
1360+
},
1361+
"URL encoded characters in path without scheme are unmodified": {
1362+
input: "host:9876/a%2Fb%2Fc",
1363+
expected: "http://host:9876/a%2Fb%2Fc",
1364+
},
1365+
"empty returns default": {
1366+
input: "",
1367+
expected: "http://localhost:7054",
1368+
},
1369+
} {
1370+
t.Run(testName, func(t *testing.T) {
1371+
u, err := NormalizeURL(testData.input)
1372+
require.NoError(t, err)
1373+
1374+
assert.Equal(t, testData.expected, u.String())
1375+
})
13511376
}
1352-
_, err = NormalizeURL("https:rootless/path")
1353-
t.Logf("NormalizeURL() error %v", err)
1354-
if err == nil {
1355-
t.Errorf("NormalizeURL 'https:rootless/path' should have failed")
1377+
1378+
t.Run("invalid scheme fails", func(t *testing.T) {
1379+
u, err := NormalizeURL("ftp://host:9876")
1380+
require.ErrorContains(t, err, "ftp", "URL: %s", u)
1381+
})
1382+
1383+
for testName, input := range map[string]string{
1384+
"invalid URL input fails": "[",
1385+
"invalid characters in hostname fails": "http://[/path",
1386+
"rootless path fails": "https:rootless/path",
1387+
"non-numeric port fails": "host:port",
1388+
} {
1389+
t.Run(testName, func(t *testing.T) {
1390+
u, err := NormalizeURL(input)
1391+
require.Error(t, err, "expected error, got: %s", u)
1392+
})
13561393
}
13571394
}
13581395

vendor/github.com/stretchr/testify/require/doc.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/stretchr/testify/require/forward_requirements.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)