Skip to content
This repository has been archived by the owner on Dec 22, 2022. It is now read-only.

Commit

Permalink
Validate External Cache Host (prebid#1422)
Browse files Browse the repository at this point in the history
* first draft

* Little tweaks

* Scott's review part 1

* Scott's review corrections part 2

* Scotts refactor

* correction in config_test.go

* Correction and refactor

* Multiple return statements

* Test case refactor

Co-authored-by: Gus Carreon <gcarreongutierrez@vpn-10-75-12-170.nym2.appnexus.com>
Co-authored-by: Gus Carreon <gcarreongutierrez@vpn-10-75-12-23.nym2.appnexus.com>
Co-authored-by: Gus Carreon <gcarreongutierrez@Guss-MacBook-Pro.local>
  • Loading branch information
4 people authored Aug 20, 2020
1 parent 88252d4 commit 3df7dea
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 2 deletions.
36 changes: 36 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"bytes"
"errors"
"fmt"
"net/url"
"reflect"
Expand Down Expand Up @@ -111,6 +112,7 @@ func (cfg *Configuration) validate() configErrors {
errs = cfg.CurrencyConverter.validate(errs)
errs = validateAdapters(cfg.Adapters, errs)
errs = cfg.Debug.validate(errs)
errs = cfg.ExtCacheURL.validate(errs)
return errs
}

Expand All @@ -128,6 +130,40 @@ func (cfg *AuctionTimeouts) validate(errs configErrors) configErrors {
return errs
}

func (data *ExternalCache) validate(errs configErrors) configErrors {
if data.Host == "" && data.Path == "" {
// Both host and path can be blank. No further validation needed
return errs
}

// Either host or path or both not empty, validate.
if data.Host == "" && data.Path != "" || data.Host != "" && data.Path == "" {
return append(errs, errors.New("External cache Host and Path must both be specified"))
}
if strings.HasSuffix(data.Host, "/") {
return append(errs, errors.New(fmt.Sprintf("External cache Host '%s' must not end with a path separator", data.Host)))
}
if strings.ContainsAny(data.Host, "://") {
return append(errs, errors.New(fmt.Sprintf("External cache Host must not specify a protocol. '%s'", data.Host)))
}
if !strings.HasPrefix(data.Path, "/") {
return append(errs, errors.New(fmt.Sprintf("External cache Path '%s' must begin with a path separator", data.Path)))
}

urlObj, err := url.Parse("https://" + data.Host + data.Path)
if err != nil {
return append(errs, errors.New(fmt.Sprintf("External cache Path validation error: %s ", err.Error())))
}
if urlObj.Host != data.Host {
return append(errs, errors.New(fmt.Sprintf("External cache Host '%s' is invalid", data.Host)))
}
if urlObj.Path != data.Path {
return append(errs, errors.New("External cache Path is invalid"))
}

return errs
}

// LimitAuctionTimeout returns the min of requested or cfg.MaxAuctionTimeout.
// Both values treat "0" as "infinite".
func (cfg *AuctionTimeouts) LimitAuctionTimeout(requested time.Duration) time.Duration {
Expand Down
89 changes: 87 additions & 2 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,91 @@ import (
"github.com/stretchr/testify/assert"
)

func TestExternalCacheURLValidate(t *testing.T) {
testCases := []struct {
desc string
data ExternalCache
expErrors int
}{
{
desc: "With http://",
data: ExternalCache{Host: "http://www.google.com", Path: "/path/v1"},
expErrors: 1,
},
{
desc: "Without http://",
data: ExternalCache{Host: "www.google.com", Path: "/path/v1"},
expErrors: 0,
},
{
desc: "No scheme but '//' prefix",
data: ExternalCache{Host: "//www.google.com", Path: "/path/v1"},
expErrors: 1,
},
{
desc: "// appears twice",
data: ExternalCache{Host: "//www.google.com//", Path: "path/v1"},
expErrors: 1,
},
{
desc: "Host has an only // value",
data: ExternalCache{Host: "//", Path: "path/v1"},
expErrors: 1,
},
{
desc: "only scheme host, valid path",
data: ExternalCache{Host: "http://", Path: "/path/v1"},
expErrors: 1,
},
{
desc: "No host, path only",
data: ExternalCache{Host: "", Path: "path/v1"},
expErrors: 1,
},
{
desc: "No host, nor path",
data: ExternalCache{Host: "", Path: ""},
expErrors: 0,
},
{
desc: "Invalid http at the end",
data: ExternalCache{Host: "www.google.com", Path: "http://"},
expErrors: 1,
},
{
desc: "Host has an unknown scheme",
data: ExternalCache{Host: "unknownscheme://host", Path: "/path/v1"},
expErrors: 1,
},
{
desc: "Wrong colon side in scheme",
data: ExternalCache{Host: "http//:www.appnexus.com", Path: "/path/v1"},
expErrors: 1,
},
{
desc: "Missing '/' in scheme",
data: ExternalCache{Host: "http:/www.appnexus.com", Path: "/path/v1"},
expErrors: 1,
},
{
desc: "host with scheme, no path",
data: ExternalCache{Host: "http://www.appnexus.com", Path: ""},
expErrors: 1,
},
{
desc: "scheme, no host nor path",
data: ExternalCache{Host: "http://", Path: ""},
expErrors: 1,
},
}
for _, test := range testCases {
var errs configErrors
errs = test.data.validate(errs)

assert.Equal(t, test.expErrors, len(errs), "Test case threw unexpected number of errors. Desc: %s errMsg = %v \n", test.desc, errs)
}
}

func TestDefaults(t *testing.T) {
v := viper.New()
SetupViper(v, "")
Expand Down Expand Up @@ -66,7 +151,7 @@ cache:
query: uuid=%PBS_CACHE_UUID%
external_cache:
host: www.externalprebidcache.net
path: endpoints/cache
path: /endpoints/cache
http_client:
max_connections_per_host: 10
max_idle_connections: 500
Expand Down Expand Up @@ -223,7 +308,7 @@ func TestFullConfig(t *testing.T) {
cmpStrings(t, "cache.host", cfg.CacheURL.Host, "prebidcache.net")
cmpStrings(t, "cache.query", cfg.CacheURL.Query, "uuid=%PBS_CACHE_UUID%")
cmpStrings(t, "external_cache.host", cfg.ExtCacheURL.Host, "www.externalprebidcache.net")
cmpStrings(t, "external_cache.path", cfg.ExtCacheURL.Path, "endpoints/cache")
cmpStrings(t, "external_cache.path", cfg.ExtCacheURL.Path, "/endpoints/cache")
cmpInts(t, "http_client.max_connections_per_host", cfg.Client.MaxConnsPerHost, 10)
cmpInts(t, "http_client.max_idle_connections", cfg.Client.MaxIdleConns, 500)
cmpInts(t, "http_client.max_idle_connections_per_host", cfg.Client.MaxIdleConnsPerHost, 20)
Expand Down

0 comments on commit 3df7dea

Please sign in to comment.