forked from Ivasoft/traefik
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9e9e11035 | ||
|
|
772c9ca4d5 | ||
|
|
208d0fa471 | ||
|
|
9f72b6d1d5 | ||
|
|
29ef007917 | ||
|
|
590a0d67bb |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# Change Log
|
||||
|
||||
## [v1.7.19](https://github.com/containous/traefik/tree/v1.7.19) (2019-10-25)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.18...v1.7.19)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[k8s,k8s/ingress]** Add functions to support precise float compute of weight ([#5663](https://github.com/containous/traefik/pull/5663) by [rmrfself](https://github.com/rmrfself))
|
||||
- **[middleware]** Fix Location response header http to https when SSL ([#5574](https://github.com/containous/traefik/pull/5574) by [elielgoncalves](https://github.com/elielgoncalves))
|
||||
- **[tls]** Allow Default Certificate to work on macOS 10.15 ([#5662](https://github.com/containous/traefik/pull/5662) by [dtomcej](https://github.com/dtomcej))
|
||||
|
||||
**Documentation:**
|
||||
- **[k8s]** Update DaemonSet apiVersion ([#5682](https://github.com/containous/traefik/pull/5682) by [ialidzhikov](https://github.com/ialidzhikov))
|
||||
|
||||
## [v1.7.18](https://github.com/containous/traefik/tree/v1.7.18) (2019-09-23)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.17...v1.7.18)
|
||||
|
||||
|
||||
12
Gopkg.lock
generated
12
Gopkg.lock
generated
@@ -1770,6 +1770,13 @@
|
||||
pruneopts = "NUT"
|
||||
revision = "1d7be4effb13d2d908342d349d71a284a7542693"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9ca27be3cfd8a452f9814926a5842c6917289da8c21174ee0f9c79d84850b2ed"
|
||||
name = "github.com/shopspring/decimal"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "f1972eb1d1f519e2e5f4b51f2dea765e8c93a130"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:01252cd79aac70f16cac02a72a1067dd136e0ad6d5b597d0129cf74c739fd8d1"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
@@ -1909,11 +1916,11 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "v1"
|
||||
digest = "1:60888cead16f066c948c078258b27f2885dce91cb6aadacf545b62a1ae1d08cb"
|
||||
digest = "1:819d4566276aed820b412b7e72683edfe99f53d2ac54e5b13eda197b523a369b"
|
||||
name = "github.com/unrolled/secure"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "a1cf62cc2159fff407728f118c41aece76c397fa"
|
||||
revision = "232c938a6a69cfd83e26e2bfe100a20486d3a9a0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e84e99d5f369afaa9a5c41f55b57fa03047ecd3bac2a65861607882693ceea81"
|
||||
@@ -2612,6 +2619,7 @@
|
||||
"github.com/rancher/go-rancher-metadata/metadata",
|
||||
"github.com/rancher/go-rancher/v2",
|
||||
"github.com/ryanuber/go-glob",
|
||||
"github.com/shopspring/decimal",
|
||||
"github.com/sirupsen/logrus",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/mock",
|
||||
|
||||
@@ -264,3 +264,11 @@
|
||||
[[constraint]]
|
||||
name = "github.com/google/uuid"
|
||||
version = "0.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/shopspring/decimal"
|
||||
revision = "f1972eb1d1f519e2e5f4b51f2dea765e8c93a130"
|
||||
|
||||
[[override]]
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
version = "0.4.12"
|
||||
|
||||
@@ -6,13 +6,17 @@ metadata:
|
||||
namespace: kube-system
|
||||
---
|
||||
kind: DaemonSet
|
||||
apiVersion: extensions/v1beta1
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: traefik-ingress-controller
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: traefik-ingress-lb
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: traefik-ingress-lb
|
||||
name: traefik-ingress-lb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
|
||||
@@ -341,24 +341,32 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAs(c *check.
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = "snitest.com"
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "snitest.com",
|
||||
Certificates: []tls.Certificate{},
|
||||
}
|
||||
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: tlsConfig},
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
// Connection without client certificate should fail
|
||||
_, err = tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("should not be allowed to connect to server"))
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
// Connect with client signed by ca1
|
||||
cert, err := tls.LoadX509KeyPair("fixtures/https/clientca/client1.crt", "fixtures/https/clientca/client1.key")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to load client certificate and key"))
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server"))
|
||||
|
||||
conn.Close()
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Connect with client signed by ca2
|
||||
tlsConfig = &tls.Config{
|
||||
@@ -370,10 +378,13 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAs(c *check.
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to load client certificate and key"))
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
|
||||
conn, err = tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server"))
|
||||
client = http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: tlsConfig},
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Connect with client signed by ca3 should fail
|
||||
tlsConfig = &tls.Config{
|
||||
@@ -385,8 +396,13 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAs(c *check.
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to load client certificate and key"))
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
|
||||
_, err = tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("should not be allowed to connect to server"))
|
||||
client = http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: tlsConfig},
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.NotNil)
|
||||
}
|
||||
|
||||
// TestWithClientCertificateAuthentication
|
||||
@@ -402,24 +418,32 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAsMultipleFi
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1000*time.Millisecond, try.BodyContains("Host:snitest.org"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = "snitest.com"
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "snitest.com",
|
||||
Certificates: []tls.Certificate{},
|
||||
}
|
||||
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: tlsConfig},
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
// Connection without client certificate should fail
|
||||
_, err = tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("should not be allowed to connect to server"))
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
// Connect with client signed by ca1
|
||||
cert, err := tls.LoadX509KeyPair("fixtures/https/clientca/client1.crt", "fixtures/https/clientca/client1.key")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to load client certificate and key"))
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server"))
|
||||
|
||||
conn.Close()
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Connect with client signed by ca2
|
||||
tlsConfig = &tls.Config{
|
||||
@@ -431,9 +455,13 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAsMultipleFi
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to load client certificate and key"))
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
|
||||
conn, err = tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server"))
|
||||
conn.Close()
|
||||
client = http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: tlsConfig},
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Connect with client signed by ca3 should fail
|
||||
tlsConfig = &tls.Config{
|
||||
@@ -445,8 +473,13 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAsMultipleFi
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to load client certificate and key"))
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
|
||||
_, err = tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("should not be allowed to connect to server"))
|
||||
client = http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: tlsConfig},
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
_, err = client.Do(req)
|
||||
c.Assert(err, checker.NotNil)
|
||||
}
|
||||
|
||||
func (s *HTTPSSuite) TestWithRootCAsContentForHTTPSOnBackend(c *check.C) {
|
||||
|
||||
@@ -25,11 +25,6 @@ var host = flag.Bool("host", false, "run host integration tests")
|
||||
var showLog = flag.Bool("tlog", false, "always show Traefik logs")
|
||||
|
||||
func Test(t *testing.T) {
|
||||
check.TestingT(t)
|
||||
}
|
||||
|
||||
func init() {
|
||||
flag.Parse()
|
||||
if !*integration {
|
||||
log.Info("Integration tests disabled.")
|
||||
return
|
||||
@@ -70,6 +65,8 @@ func init() {
|
||||
check.Suite(&ProxyProtocolSuite{})
|
||||
check.Suite(&Etcd3Suite{})
|
||||
}
|
||||
|
||||
check.TestingT(t)
|
||||
}
|
||||
|
||||
var traefikBinary = "../dist/traefik"
|
||||
|
||||
@@ -3,6 +3,8 @@ package kubernetes
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
const defaultPercentageValuePrecision = 3
|
||||
@@ -43,5 +45,6 @@ func newPercentageValueFromString(rawValue string) (percentageValue, error) {
|
||||
|
||||
// newPercentageValueFromFloat64 reads percentage value from float64
|
||||
func newPercentageValueFromFloat64(f float64) percentageValue {
|
||||
return percentageValue(f * (1000 * 100))
|
||||
value := decimal.NewFromFloat(f).Mul(decimal.NewFromFloat(1000 * 100))
|
||||
return percentageValue(value.IntPart())
|
||||
}
|
||||
|
||||
@@ -74,46 +74,54 @@ func TestNewPercentageValueFromString(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
value: "1%",
|
||||
expectError: false,
|
||||
expectedString: "1.000%",
|
||||
expectedFloat64: 0.01,
|
||||
},
|
||||
{
|
||||
value: "0.5",
|
||||
expectError: false,
|
||||
expectedString: "0.500%",
|
||||
expectedFloat64: 0.005,
|
||||
},
|
||||
{
|
||||
value: "99%",
|
||||
expectError: false,
|
||||
expectedString: "99.000%",
|
||||
expectedFloat64: 0.99,
|
||||
},
|
||||
{
|
||||
value: "99.9%",
|
||||
expectError: false,
|
||||
expectedString: "99.900%",
|
||||
expectedFloat64: 0.999,
|
||||
},
|
||||
{
|
||||
value: "-99.9%",
|
||||
expectError: false,
|
||||
expectedString: "-99.900%",
|
||||
expectedFloat64: -0.999,
|
||||
},
|
||||
{
|
||||
value: "-99.99999%",
|
||||
expectError: false,
|
||||
expectedString: "-99.999%",
|
||||
expectedFloat64: -0.99999,
|
||||
},
|
||||
{
|
||||
value: "0%",
|
||||
expectError: false,
|
||||
expectedString: "0.000%",
|
||||
expectedFloat64: 0,
|
||||
},
|
||||
{
|
||||
value: "2.3%",
|
||||
expectedString: "2.300%",
|
||||
expectedFloat64: 0.023,
|
||||
},
|
||||
{
|
||||
value: "5.1%",
|
||||
expectedString: "5.100%",
|
||||
expectedFloat64: 0.051,
|
||||
},
|
||||
{
|
||||
value: "83.85%",
|
||||
expectedString: "83.850%",
|
||||
expectedFloat64: 0.83850,
|
||||
},
|
||||
{
|
||||
value: "%",
|
||||
expectError: true,
|
||||
|
||||
@@ -86,6 +86,7 @@ func derCert(privKey *rsa.PrivateKey, expiration time.Time, domain string) ([]by
|
||||
NotAfter: expiration,
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageDataEncipherment,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
DNSNames: []string{domain},
|
||||
}
|
||||
|
||||
45
vendor/github.com/shopspring/decimal/LICENSE
generated
vendored
Normal file
45
vendor/github.com/shopspring/decimal/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Spring, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
- Based on https://github.com/oguzbilgic/fpd, which has the following license:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Oguz Bilgic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
414
vendor/github.com/shopspring/decimal/decimal-go.go
generated
vendored
Normal file
414
vendor/github.com/shopspring/decimal/decimal-go.go
generated
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Multiprecision decimal numbers.
|
||||
// For floating-point formatting only; not general purpose.
|
||||
// Only operations are assign and (binary) left/right shift.
|
||||
// Can do binary floating point in multiprecision decimal precisely
|
||||
// because 2 divides 10; cannot do decimal floating point
|
||||
// in multiprecision binary precisely.
|
||||
package decimal
|
||||
|
||||
type decimal struct {
|
||||
d [800]byte // digits, big-endian representation
|
||||
nd int // number of digits used
|
||||
dp int // decimal point
|
||||
neg bool // negative flag
|
||||
trunc bool // discarded nonzero digits beyond d[:nd]
|
||||
}
|
||||
|
||||
func (a *decimal) String() string {
|
||||
n := 10 + a.nd
|
||||
if a.dp > 0 {
|
||||
n += a.dp
|
||||
}
|
||||
if a.dp < 0 {
|
||||
n += -a.dp
|
||||
}
|
||||
|
||||
buf := make([]byte, n)
|
||||
w := 0
|
||||
switch {
|
||||
case a.nd == 0:
|
||||
return "0"
|
||||
|
||||
case a.dp <= 0:
|
||||
// zeros fill space between decimal point and digits
|
||||
buf[w] = '0'
|
||||
w++
|
||||
buf[w] = '.'
|
||||
w++
|
||||
w += digitZero(buf[w : w+-a.dp])
|
||||
w += copy(buf[w:], a.d[0:a.nd])
|
||||
|
||||
case a.dp < a.nd:
|
||||
// decimal point in middle of digits
|
||||
w += copy(buf[w:], a.d[0:a.dp])
|
||||
buf[w] = '.'
|
||||
w++
|
||||
w += copy(buf[w:], a.d[a.dp:a.nd])
|
||||
|
||||
default:
|
||||
// zeros fill space between digits and decimal point
|
||||
w += copy(buf[w:], a.d[0:a.nd])
|
||||
w += digitZero(buf[w : w+a.dp-a.nd])
|
||||
}
|
||||
return string(buf[0:w])
|
||||
}
|
||||
|
||||
func digitZero(dst []byte) int {
|
||||
for i := range dst {
|
||||
dst[i] = '0'
|
||||
}
|
||||
return len(dst)
|
||||
}
|
||||
|
||||
// trim trailing zeros from number.
|
||||
// (They are meaningless; the decimal point is tracked
|
||||
// independent of the number of digits.)
|
||||
func trim(a *decimal) {
|
||||
for a.nd > 0 && a.d[a.nd-1] == '0' {
|
||||
a.nd--
|
||||
}
|
||||
if a.nd == 0 {
|
||||
a.dp = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Assign v to a.
|
||||
func (a *decimal) Assign(v uint64) {
|
||||
var buf [24]byte
|
||||
|
||||
// Write reversed decimal in buf.
|
||||
n := 0
|
||||
for v > 0 {
|
||||
v1 := v / 10
|
||||
v -= 10 * v1
|
||||
buf[n] = byte(v + '0')
|
||||
n++
|
||||
v = v1
|
||||
}
|
||||
|
||||
// Reverse again to produce forward decimal in a.d.
|
||||
a.nd = 0
|
||||
for n--; n >= 0; n-- {
|
||||
a.d[a.nd] = buf[n]
|
||||
a.nd++
|
||||
}
|
||||
a.dp = a.nd
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Maximum shift that we can do in one pass without overflow.
|
||||
// A uint has 32 or 64 bits, and we have to be able to accommodate 9<<k.
|
||||
const uintSize = 32 << (^uint(0) >> 63)
|
||||
const maxShift = uintSize - 4
|
||||
|
||||
// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow.
|
||||
func rightShift(a *decimal, k uint) {
|
||||
r := 0 // read pointer
|
||||
w := 0 // write pointer
|
||||
|
||||
// Pick up enough leading digits to cover first shift.
|
||||
var n uint
|
||||
for ; n>>k == 0; r++ {
|
||||
if r >= a.nd {
|
||||
if n == 0 {
|
||||
// a == 0; shouldn't get here, but handle anyway.
|
||||
a.nd = 0
|
||||
return
|
||||
}
|
||||
for n>>k == 0 {
|
||||
n = n * 10
|
||||
r++
|
||||
}
|
||||
break
|
||||
}
|
||||
c := uint(a.d[r])
|
||||
n = n*10 + c - '0'
|
||||
}
|
||||
a.dp -= r - 1
|
||||
|
||||
var mask uint = (1 << k) - 1
|
||||
|
||||
// Pick up a digit, put down a digit.
|
||||
for ; r < a.nd; r++ {
|
||||
c := uint(a.d[r])
|
||||
dig := n >> k
|
||||
n &= mask
|
||||
a.d[w] = byte(dig + '0')
|
||||
w++
|
||||
n = n*10 + c - '0'
|
||||
}
|
||||
|
||||
// Put down extra digits.
|
||||
for n > 0 {
|
||||
dig := n >> k
|
||||
n &= mask
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(dig + '0')
|
||||
w++
|
||||
} else if dig > 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = n * 10
|
||||
}
|
||||
|
||||
a.nd = w
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Cheat sheet for left shift: table indexed by shift count giving
|
||||
// number of new digits that will be introduced by that shift.
|
||||
//
|
||||
// For example, leftcheats[4] = {2, "625"}. That means that
|
||||
// if we are shifting by 4 (multiplying by 16), it will add 2 digits
|
||||
// when the string prefix is "625" through "999", and one fewer digit
|
||||
// if the string prefix is "000" through "624".
|
||||
//
|
||||
// Credit for this trick goes to Ken.
|
||||
|
||||
type leftCheat struct {
|
||||
delta int // number of new digits
|
||||
cutoff string // minus one digit if original < a.
|
||||
}
|
||||
|
||||
var leftcheats = []leftCheat{
|
||||
// Leading digits of 1/2^i = 5^i.
|
||||
// 5^23 is not an exact 64-bit floating point number,
|
||||
// so have to use bc for the math.
|
||||
// Go up to 60 to be large enough for 32bit and 64bit platforms.
|
||||
/*
|
||||
seq 60 | sed 's/^/5^/' | bc |
|
||||
awk 'BEGIN{ print "\t{ 0, \"\" }," }
|
||||
{
|
||||
log2 = log(2)/log(10)
|
||||
printf("\t{ %d, \"%s\" },\t// * %d\n",
|
||||
int(log2*NR+1), $0, 2**NR)
|
||||
}'
|
||||
*/
|
||||
{0, ""},
|
||||
{1, "5"}, // * 2
|
||||
{1, "25"}, // * 4
|
||||
{1, "125"}, // * 8
|
||||
{2, "625"}, // * 16
|
||||
{2, "3125"}, // * 32
|
||||
{2, "15625"}, // * 64
|
||||
{3, "78125"}, // * 128
|
||||
{3, "390625"}, // * 256
|
||||
{3, "1953125"}, // * 512
|
||||
{4, "9765625"}, // * 1024
|
||||
{4, "48828125"}, // * 2048
|
||||
{4, "244140625"}, // * 4096
|
||||
{4, "1220703125"}, // * 8192
|
||||
{5, "6103515625"}, // * 16384
|
||||
{5, "30517578125"}, // * 32768
|
||||
{5, "152587890625"}, // * 65536
|
||||
{6, "762939453125"}, // * 131072
|
||||
{6, "3814697265625"}, // * 262144
|
||||
{6, "19073486328125"}, // * 524288
|
||||
{7, "95367431640625"}, // * 1048576
|
||||
{7, "476837158203125"}, // * 2097152
|
||||
{7, "2384185791015625"}, // * 4194304
|
||||
{7, "11920928955078125"}, // * 8388608
|
||||
{8, "59604644775390625"}, // * 16777216
|
||||
{8, "298023223876953125"}, // * 33554432
|
||||
{8, "1490116119384765625"}, // * 67108864
|
||||
{9, "7450580596923828125"}, // * 134217728
|
||||
{9, "37252902984619140625"}, // * 268435456
|
||||
{9, "186264514923095703125"}, // * 536870912
|
||||
{10, "931322574615478515625"}, // * 1073741824
|
||||
{10, "4656612873077392578125"}, // * 2147483648
|
||||
{10, "23283064365386962890625"}, // * 4294967296
|
||||
{10, "116415321826934814453125"}, // * 8589934592
|
||||
{11, "582076609134674072265625"}, // * 17179869184
|
||||
{11, "2910383045673370361328125"}, // * 34359738368
|
||||
{11, "14551915228366851806640625"}, // * 68719476736
|
||||
{12, "72759576141834259033203125"}, // * 137438953472
|
||||
{12, "363797880709171295166015625"}, // * 274877906944
|
||||
{12, "1818989403545856475830078125"}, // * 549755813888
|
||||
{13, "9094947017729282379150390625"}, // * 1099511627776
|
||||
{13, "45474735088646411895751953125"}, // * 2199023255552
|
||||
{13, "227373675443232059478759765625"}, // * 4398046511104
|
||||
{13, "1136868377216160297393798828125"}, // * 8796093022208
|
||||
{14, "5684341886080801486968994140625"}, // * 17592186044416
|
||||
{14, "28421709430404007434844970703125"}, // * 35184372088832
|
||||
{14, "142108547152020037174224853515625"}, // * 70368744177664
|
||||
{15, "710542735760100185871124267578125"}, // * 140737488355328
|
||||
{15, "3552713678800500929355621337890625"}, // * 281474976710656
|
||||
{15, "17763568394002504646778106689453125"}, // * 562949953421312
|
||||
{16, "88817841970012523233890533447265625"}, // * 1125899906842624
|
||||
{16, "444089209850062616169452667236328125"}, // * 2251799813685248
|
||||
{16, "2220446049250313080847263336181640625"}, // * 4503599627370496
|
||||
{16, "11102230246251565404236316680908203125"}, // * 9007199254740992
|
||||
{17, "55511151231257827021181583404541015625"}, // * 18014398509481984
|
||||
{17, "277555756156289135105907917022705078125"}, // * 36028797018963968
|
||||
{17, "1387778780781445675529539585113525390625"}, // * 72057594037927936
|
||||
{18, "6938893903907228377647697925567626953125"}, // * 144115188075855872
|
||||
{18, "34694469519536141888238489627838134765625"}, // * 288230376151711744
|
||||
{18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
|
||||
{19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
|
||||
}
|
||||
|
||||
// Is the leading prefix of b lexicographically less than s?
|
||||
func prefixIsLessThan(b []byte, s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if i >= len(b) {
|
||||
return true
|
||||
}
|
||||
if b[i] != s[i] {
|
||||
return b[i] < s[i]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow.
|
||||
func leftShift(a *decimal, k uint) {
|
||||
delta := leftcheats[k].delta
|
||||
if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
|
||||
delta--
|
||||
}
|
||||
|
||||
r := a.nd // read index
|
||||
w := a.nd + delta // write index
|
||||
|
||||
// Pick up a digit, put down a digit.
|
||||
var n uint
|
||||
for r--; r >= 0; r-- {
|
||||
n += (uint(a.d[r]) - '0') << k
|
||||
quo := n / 10
|
||||
rem := n - 10*quo
|
||||
w--
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(rem + '0')
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
// Put down extra digits.
|
||||
for n > 0 {
|
||||
quo := n / 10
|
||||
rem := n - 10*quo
|
||||
w--
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(rem + '0')
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
a.nd += delta
|
||||
if a.nd >= len(a.d) {
|
||||
a.nd = len(a.d)
|
||||
}
|
||||
a.dp += delta
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Binary shift left (k > 0) or right (k < 0).
|
||||
func (a *decimal) Shift(k int) {
|
||||
switch {
|
||||
case a.nd == 0:
|
||||
// nothing to do: a == 0
|
||||
case k > 0:
|
||||
for k > maxShift {
|
||||
leftShift(a, maxShift)
|
||||
k -= maxShift
|
||||
}
|
||||
leftShift(a, uint(k))
|
||||
case k < 0:
|
||||
for k < -maxShift {
|
||||
rightShift(a, maxShift)
|
||||
k += maxShift
|
||||
}
|
||||
rightShift(a, uint(-k))
|
||||
}
|
||||
}
|
||||
|
||||
// If we chop a at nd digits, should we round up?
|
||||
func shouldRoundUp(a *decimal, nd int) bool {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return false
|
||||
}
|
||||
if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
|
||||
// if we truncated, a little higher than what's recorded - always round up
|
||||
if a.trunc {
|
||||
return true
|
||||
}
|
||||
return nd > 0 && (a.d[nd-1]-'0')%2 != 0
|
||||
}
|
||||
// not halfway - digit tells all
|
||||
return a.d[nd] >= '5'
|
||||
}
|
||||
|
||||
// Round a to nd digits (or fewer).
|
||||
// If nd is zero, it means we're rounding
|
||||
// just to the left of the digits, as in
|
||||
// 0.09 -> 0.1.
|
||||
func (a *decimal) Round(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
if shouldRoundUp(a, nd) {
|
||||
a.RoundUp(nd)
|
||||
} else {
|
||||
a.RoundDown(nd)
|
||||
}
|
||||
}
|
||||
|
||||
// Round a down to nd digits (or fewer).
|
||||
func (a *decimal) RoundDown(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
a.nd = nd
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Round a up to nd digits (or fewer).
|
||||
func (a *decimal) RoundUp(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
|
||||
// round up
|
||||
for i := nd - 1; i >= 0; i-- {
|
||||
c := a.d[i]
|
||||
if c < '9' { // can stop after this digit
|
||||
a.d[i]++
|
||||
a.nd = i + 1
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Number is all 9s.
|
||||
// Change to single 1 with adjusted decimal point.
|
||||
a.d[0] = '1'
|
||||
a.nd = 1
|
||||
a.dp++
|
||||
}
|
||||
|
||||
// Extract integer part, rounded appropriately.
|
||||
// No guarantees about overflow.
|
||||
func (a *decimal) RoundedInteger() uint64 {
|
||||
if a.dp > 20 {
|
||||
return 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
var i int
|
||||
n := uint64(0)
|
||||
for i = 0; i < a.dp && i < a.nd; i++ {
|
||||
n = n*10 + uint64(a.d[i]-'0')
|
||||
}
|
||||
for ; i < a.dp; i++ {
|
||||
n *= 10
|
||||
}
|
||||
if shouldRoundUp(a, a.dp) {
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
1438
vendor/github.com/shopspring/decimal/decimal.go
generated
vendored
Normal file
1438
vendor/github.com/shopspring/decimal/decimal.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
47
vendor/github.com/shopspring/decimal/decomposer.go
generated
vendored
Normal file
47
vendor/github.com/shopspring/decimal/decomposer.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package decimal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Decompose returns the internal decimal state into parts.
|
||||
// If the provided buf has sufficient capacity, buf may be returned as the coefficient with
|
||||
// the value set and length set as appropriate.
|
||||
func (d Decimal) Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) {
|
||||
negative = d.value.Sign() < 0
|
||||
exponent = d.exp
|
||||
coefficient = d.value.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
decomposeFinite = 0
|
||||
decomposeInfinite = 1
|
||||
decomposeNaN = 2
|
||||
)
|
||||
|
||||
// Compose sets the internal decimal value from parts. If the value cannot be
|
||||
// represented then an error should be returned.
|
||||
func (d *Decimal) Compose(form byte, negative bool, coefficient []byte, exponent int32) error {
|
||||
switch form {
|
||||
default:
|
||||
return fmt.Errorf("unknown form: %v", form)
|
||||
case decomposeFinite:
|
||||
// Set rest of finite form below.
|
||||
case decomposeInfinite:
|
||||
return fmt.Errorf("Infinite form not supported")
|
||||
case decomposeNaN:
|
||||
return fmt.Errorf("NaN form not supported")
|
||||
}
|
||||
// Finite form.
|
||||
if d.value == nil {
|
||||
d.value = &big.Int{}
|
||||
}
|
||||
d.value.SetBytes(coefficient)
|
||||
if negative && d.value.Sign() >= 0 {
|
||||
d.value.Neg(d.value)
|
||||
}
|
||||
d.exp = exponent
|
||||
return nil
|
||||
}
|
||||
118
vendor/github.com/shopspring/decimal/rounding.go
generated
vendored
Normal file
118
vendor/github.com/shopspring/decimal/rounding.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Multiprecision decimal numbers.
|
||||
// For floating-point formatting only; not general purpose.
|
||||
// Only operations are assign and (binary) left/right shift.
|
||||
// Can do binary floating point in multiprecision decimal precisely
|
||||
// because 2 divides 10; cannot do decimal floating point
|
||||
// in multiprecision binary precisely.
|
||||
package decimal
|
||||
|
||||
type floatInfo struct {
|
||||
mantbits uint
|
||||
expbits uint
|
||||
bias int
|
||||
}
|
||||
|
||||
var float32info = floatInfo{23, 8, -127}
|
||||
var float64info = floatInfo{52, 11, -1023}
|
||||
|
||||
// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
|
||||
// that will let the original floating point value be precisely reconstructed.
|
||||
func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
|
||||
// If mantissa is zero, the number is zero; stop now.
|
||||
if mant == 0 {
|
||||
d.nd = 0
|
||||
return
|
||||
}
|
||||
|
||||
// Compute upper and lower such that any decimal number
|
||||
// between upper and lower (possibly inclusive)
|
||||
// will round to the original floating point number.
|
||||
|
||||
// We may see at once that the number is already shortest.
|
||||
//
|
||||
// Suppose d is not denormal, so that 2^exp <= d < 10^dp.
|
||||
// The closest shorter number is at least 10^(dp-nd) away.
|
||||
// The lower/upper bounds computed below are at distance
|
||||
// at most 2^(exp-mantbits).
|
||||
//
|
||||
// So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
|
||||
// or equivalently log2(10)*(dp-nd) > exp-mantbits.
|
||||
// It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
|
||||
minexp := flt.bias + 1 // minimum possible exponent
|
||||
if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
|
||||
// The number is already shortest.
|
||||
return
|
||||
}
|
||||
|
||||
// d = mant << (exp - mantbits)
|
||||
// Next highest floating point number is mant+1 << exp-mantbits.
|
||||
// Our upper bound is halfway between, mant*2+1 << exp-mantbits-1.
|
||||
upper := new(decimal)
|
||||
upper.Assign(mant*2 + 1)
|
||||
upper.Shift(exp - int(flt.mantbits) - 1)
|
||||
|
||||
// d = mant << (exp - mantbits)
|
||||
// Next lowest floating point number is mant-1 << exp-mantbits,
|
||||
// unless mant-1 drops the significant bit and exp is not the minimum exp,
|
||||
// in which case the next lowest is mant*2-1 << exp-mantbits-1.
|
||||
// Either way, call it mantlo << explo-mantbits.
|
||||
// Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1.
|
||||
var mantlo uint64
|
||||
var explo int
|
||||
if mant > 1<<flt.mantbits || exp == minexp {
|
||||
mantlo = mant - 1
|
||||
explo = exp
|
||||
} else {
|
||||
mantlo = mant*2 - 1
|
||||
explo = exp - 1
|
||||
}
|
||||
lower := new(decimal)
|
||||
lower.Assign(mantlo*2 + 1)
|
||||
lower.Shift(explo - int(flt.mantbits) - 1)
|
||||
|
||||
// The upper and lower bounds are possible outputs only if
|
||||
// the original mantissa is even, so that IEEE round-to-even
|
||||
// would round to the original mantissa and not the neighbors.
|
||||
inclusive := mant%2 == 0
|
||||
|
||||
// Now we can figure out the minimum number of digits required.
|
||||
// Walk along until d has distinguished itself from upper and lower.
|
||||
for i := 0; i < d.nd; i++ {
|
||||
l := byte('0') // lower digit
|
||||
if i < lower.nd {
|
||||
l = lower.d[i]
|
||||
}
|
||||
m := d.d[i] // middle digit
|
||||
u := byte('0') // upper digit
|
||||
if i < upper.nd {
|
||||
u = upper.d[i]
|
||||
}
|
||||
|
||||
// Okay to round down (truncate) if lower has a different digit
|
||||
// or if lower is inclusive and is exactly the result of rounding
|
||||
// down (i.e., and we have reached the final digit of lower).
|
||||
okdown := l != m || inclusive && i+1 == lower.nd
|
||||
|
||||
// Okay to round up if upper has a different digit and either upper
|
||||
// is inclusive or upper is bigger than the result of rounding up.
|
||||
okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
|
||||
|
||||
// If it's okay to do either, then round to the nearest one.
|
||||
// If it's okay to do only one, do it.
|
||||
switch {
|
||||
case okdown && okup:
|
||||
d.Round(i + 1)
|
||||
return
|
||||
case okdown:
|
||||
d.RoundDown(i + 1)
|
||||
return
|
||||
case okup:
|
||||
d.RoundUp(i + 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
157
vendor/github.com/unrolled/secure/secure.go
generated
vendored
157
vendor/github.com/unrolled/secure/secure.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -11,7 +12,7 @@ type secureCtxKey string
|
||||
|
||||
const (
|
||||
stsHeader = "Strict-Transport-Security"
|
||||
stsSubdomainString = "; includeSubdomains"
|
||||
stsSubdomainString = "; includeSubDomains"
|
||||
stsPreloadString = "; preload"
|
||||
frameOptionsHeader = "X-Frame-Options"
|
||||
frameOptionsValue = "DENY"
|
||||
@@ -20,8 +21,11 @@ const (
|
||||
xssProtectionHeader = "X-XSS-Protection"
|
||||
xssProtectionValue = "1; mode=block"
|
||||
cspHeader = "Content-Security-Policy"
|
||||
cspReportOnlyHeader = "Content-Security-Policy-Report-Only"
|
||||
hpkpHeader = "Public-Key-Pins"
|
||||
referrerPolicyHeader = "Referrer-Policy"
|
||||
featurePolicyHeader = "Feature-Policy"
|
||||
expectCTHeader = "Expect-CT"
|
||||
|
||||
ctxSecureHeaderKey = secureCtxKey("SecureResponseHeader")
|
||||
cspNonceSize = 16
|
||||
@@ -61,6 +65,8 @@ type Options struct {
|
||||
STSPreload bool
|
||||
// ContentSecurityPolicy allows the Content-Security-Policy header value to be set with a custom value. Default is "".
|
||||
ContentSecurityPolicy string
|
||||
// ContentSecurityPolicyReportOnly allows the Content-Security-Policy-Report-Only header value to be set with a custom value. Default is "".
|
||||
ContentSecurityPolicyReportOnly string
|
||||
// CustomBrowserXssValue allows the X-XSS-Protection header value to be set with a custom value. This overrides the BrowserXssFilter option. Default is "".
|
||||
CustomBrowserXssValue string // nolint: golint
|
||||
// Passing a template string will replace `$NONCE` with a dynamic nonce value of 16 bytes for each request which can be later retrieved using the Nonce function.
|
||||
@@ -71,10 +77,15 @@ type Options struct {
|
||||
PublicKey string
|
||||
// ReferrerPolicy allows sites to control when browsers will pass the Referer header to other sites. Default is "".
|
||||
ReferrerPolicy string
|
||||
// FeaturePolicy allows to selectively enable and disable use of various browser features and APIs. Default is "".
|
||||
FeaturePolicy string
|
||||
// SSLHost is the host name that is used to redirect http requests to https. Default is "", which indicates to use the same host.
|
||||
SSLHost string
|
||||
// AllowedHosts is a list of fully qualified domain names that are allowed. Default is empty list, which allows any and all host names.
|
||||
AllowedHosts []string
|
||||
// AllowedHostsAreRegex determines, if the provided slice contains valid regular expressions. If this flag is set to true, every request's
|
||||
// host will be checked against these expressions. Default is false for backwards compatibility.
|
||||
AllowedHostsAreRegex bool
|
||||
// HostsProxyHeaders is a set of header keys that may hold a proxied hostname value for the request.
|
||||
HostsProxyHeaders []string
|
||||
// SSLHostFunc is a function pointer, the return value of the function is the host name that has same functionality as `SSHost`. Default is nil.
|
||||
@@ -84,6 +95,8 @@ type Options struct {
|
||||
SSLProxyHeaders map[string]string
|
||||
// STSSeconds is the max-age of the Strict-Transport-Security header. Default is 0, which would NOT include the header.
|
||||
STSSeconds int64
|
||||
// ExpectCTHeader allows the Expect-CT header value to be set with a custom value. Default is "".
|
||||
ExpectCTHeader string
|
||||
}
|
||||
|
||||
// Secure is a middleware that helps setup a few basic security features. A single secure.Options struct can be
|
||||
@@ -94,6 +107,10 @@ type Secure struct {
|
||||
|
||||
// badHostHandler is the handler used when an incorrect host is passed in.
|
||||
badHostHandler http.Handler
|
||||
|
||||
// cRegexAllowedHosts saves the compiled regular expressions of the AllowedHosts
|
||||
// option for subsequent use in processRequest
|
||||
cRegexAllowedHosts []*regexp.Regexp
|
||||
}
|
||||
|
||||
// New constructs a new Secure instance with the supplied options.
|
||||
@@ -106,13 +123,27 @@ func New(options ...Options) *Secure {
|
||||
}
|
||||
|
||||
o.ContentSecurityPolicy = strings.Replace(o.ContentSecurityPolicy, "$NONCE", "'nonce-%[1]s'", -1)
|
||||
o.ContentSecurityPolicyReportOnly = strings.Replace(o.ContentSecurityPolicyReportOnly, "$NONCE", "'nonce-%[1]s'", -1)
|
||||
|
||||
o.nonceEnabled = strings.Contains(o.ContentSecurityPolicy, "%[1]s")
|
||||
o.nonceEnabled = strings.Contains(o.ContentSecurityPolicy, "%[1]s") || strings.Contains(o.ContentSecurityPolicyReportOnly, "%[1]s")
|
||||
|
||||
return &Secure{
|
||||
s := &Secure{
|
||||
opt: o,
|
||||
badHostHandler: http.HandlerFunc(defaultBadHostHandler),
|
||||
}
|
||||
|
||||
if s.opt.AllowedHostsAreRegex {
|
||||
// Test for invalid regular expressions in AllowedHosts
|
||||
for _, allowedHost := range o.AllowedHosts {
|
||||
regex, err := regexp.Compile(fmt.Sprintf("^%s$", allowedHost))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error parsing AllowedHost: %s", err))
|
||||
}
|
||||
s.cRegexAllowedHosts = append(s.cRegexAllowedHosts, regex)
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// SetBadHostHandler sets the handler to call when secure rejects the host name.
|
||||
@@ -123,13 +154,10 @@ func (s *Secure) SetBadHostHandler(handler http.Handler) {
|
||||
// Handler implements the http.HandlerFunc for integration with the standard net/http lib.
|
||||
func (s *Secure) Handler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if s.opt.nonceEnabled {
|
||||
r = withCSPNonce(r, cspRandNonce())
|
||||
}
|
||||
|
||||
// Let secure process the request. If it returns an error,
|
||||
// that indicates the request should not continue.
|
||||
err := s.Process(w, r)
|
||||
responseHeader, r, err := s.processRequest(w, r)
|
||||
addResponseHeaders(responseHeader, w)
|
||||
|
||||
// If there was an error, do not continue.
|
||||
if err != nil {
|
||||
@@ -144,13 +172,9 @@ func (s *Secure) Handler(h http.Handler) http.Handler {
|
||||
// Note that this is for requests only and will not write any headers.
|
||||
func (s *Secure) HandlerForRequestOnly(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if s.opt.nonceEnabled {
|
||||
r = withCSPNonce(r, cspRandNonce())
|
||||
}
|
||||
|
||||
// Let secure process the request. If it returns an error,
|
||||
// that indicates the request should not continue.
|
||||
responseHeader, err := s.processRequest(w, r)
|
||||
responseHeader, r, err := s.processRequest(w, r)
|
||||
|
||||
// If there was an error, do not continue.
|
||||
if err != nil {
|
||||
@@ -167,13 +191,10 @@ func (s *Secure) HandlerForRequestOnly(h http.Handler) http.Handler {
|
||||
|
||||
// HandlerFuncWithNext is a special implementation for Negroni, but could be used elsewhere.
|
||||
func (s *Secure) HandlerFuncWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
if s.opt.nonceEnabled {
|
||||
r = withCSPNonce(r, cspRandNonce())
|
||||
}
|
||||
|
||||
// Let secure process the request. If it returns an error,
|
||||
// that indicates the request should not continue.
|
||||
err := s.Process(w, r)
|
||||
responseHeader, r, err := s.processRequest(w, r)
|
||||
addResponseHeaders(responseHeader, w)
|
||||
|
||||
// If there was an error, do not call next.
|
||||
if err == nil && next != nil {
|
||||
@@ -184,13 +205,9 @@ func (s *Secure) HandlerFuncWithNext(w http.ResponseWriter, r *http.Request, nex
|
||||
// HandlerFuncWithNextForRequestOnly is a special implementation for Negroni, but could be used elsewhere.
|
||||
// Note that this is for requests only and will not write any headers.
|
||||
func (s *Secure) HandlerFuncWithNextForRequestOnly(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
if s.opt.nonceEnabled {
|
||||
r = withCSPNonce(r, cspRandNonce())
|
||||
}
|
||||
|
||||
// Let secure process the request. If it returns an error,
|
||||
// that indicates the request should not continue.
|
||||
responseHeader, err := s.processRequest(w, r)
|
||||
responseHeader, r, err := s.processRequest(w, r)
|
||||
|
||||
// If there was an error, do not call next.
|
||||
if err == nil && next != nil {
|
||||
@@ -202,21 +219,44 @@ func (s *Secure) HandlerFuncWithNextForRequestOnly(w http.ResponseWriter, r *htt
|
||||
}
|
||||
}
|
||||
|
||||
// Process runs the actual checks and writes the headers in the ResponseWriter.
|
||||
func (s *Secure) Process(w http.ResponseWriter, r *http.Request) error {
|
||||
responseHeader, err := s.processRequest(w, r)
|
||||
if responseHeader != nil {
|
||||
for key, values := range responseHeader {
|
||||
for _, value := range values {
|
||||
w.Header().Add(key, value)
|
||||
}
|
||||
// addResponseHeaders Adds the headers from 'responseHeader' to the response.
|
||||
func addResponseHeaders(responseHeader http.Header, w http.ResponseWriter) {
|
||||
for key, values := range responseHeader {
|
||||
for _, value := range values {
|
||||
w.Header().Set(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process runs the actual checks and writes the headers in the ResponseWriter.
|
||||
func (s *Secure) Process(w http.ResponseWriter, r *http.Request) error {
|
||||
responseHeader, _, err := s.processRequest(w, r)
|
||||
addResponseHeaders(responseHeader, w)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ProcessAndReturnNonce runs the actual checks and writes the headers in the ResponseWriter.
|
||||
// In addition, the generated nonce for the request is returned as well as the error value.
|
||||
func (s *Secure) ProcessAndReturnNonce(w http.ResponseWriter, r *http.Request) (string, error) {
|
||||
responseHeader, newR, err := s.processRequest(w, r)
|
||||
addResponseHeaders(responseHeader, w)
|
||||
|
||||
return CSPNonce(newR.Context()), err
|
||||
}
|
||||
|
||||
// ProcessNoModifyRequest runs the actual checks but does not write the headers in the ResponseWriter.
|
||||
func (s *Secure) ProcessNoModifyRequest(w http.ResponseWriter, r *http.Request) (http.Header, *http.Request, error) {
|
||||
return s.processRequest(w, r)
|
||||
}
|
||||
|
||||
// processRequest runs the actual checks on the request and returns an error if the middleware chain should stop.
|
||||
func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.Header, error) {
|
||||
func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.Header, *http.Request, error) {
|
||||
// Setup nonce if required.
|
||||
if s.opt.nonceEnabled {
|
||||
r = withCSPNonce(r, cspRandNonce())
|
||||
}
|
||||
|
||||
// Resolve the host for the request, using proxy headers if present.
|
||||
host := r.Host
|
||||
for _, header := range s.opt.HostsProxyHeaders {
|
||||
@@ -229,16 +269,25 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He
|
||||
// Allowed hosts check.
|
||||
if len(s.opt.AllowedHosts) > 0 && !s.opt.IsDevelopment {
|
||||
isGoodHost := false
|
||||
for _, allowedHost := range s.opt.AllowedHosts {
|
||||
if strings.EqualFold(allowedHost, host) {
|
||||
isGoodHost = true
|
||||
break
|
||||
if s.opt.AllowedHostsAreRegex {
|
||||
for _, allowedHost := range s.cRegexAllowedHosts {
|
||||
if match := allowedHost.MatchString(host); match {
|
||||
isGoodHost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, allowedHost := range s.opt.AllowedHosts {
|
||||
if strings.EqualFold(allowedHost, host) {
|
||||
isGoodHost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !isGoodHost {
|
||||
s.badHostHandler.ServeHTTP(w, r)
|
||||
return nil, fmt.Errorf("bad host name: %s", host)
|
||||
return nil, nil, fmt.Errorf("bad host name: %s", host)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,11 +314,11 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He
|
||||
}
|
||||
|
||||
http.Redirect(w, r, url.String(), status)
|
||||
return nil, fmt.Errorf("redirecting to HTTPS")
|
||||
return nil, nil, fmt.Errorf("redirecting to HTTPS")
|
||||
}
|
||||
|
||||
if s.opt.SSLForceHost {
|
||||
var SSLHost = host;
|
||||
var SSLHost = host
|
||||
if s.opt.SSLHostFunc != nil {
|
||||
if h := (*s.opt.SSLHostFunc)(host); len(h) > 0 {
|
||||
SSLHost = h
|
||||
@@ -288,7 +337,7 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He
|
||||
}
|
||||
|
||||
http.Redirect(w, r, url.String(), status)
|
||||
return nil, fmt.Errorf("redirecting to HTTPS")
|
||||
return nil, nil, fmt.Errorf("redirecting to HTTPS")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,12 +392,31 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He
|
||||
}
|
||||
}
|
||||
|
||||
// Content Security Policy Report Only header.
|
||||
if len(s.opt.ContentSecurityPolicyReportOnly) > 0 {
|
||||
if s.opt.nonceEnabled {
|
||||
responseHeader.Set(cspReportOnlyHeader, fmt.Sprintf(s.opt.ContentSecurityPolicyReportOnly, CSPNonce(r.Context())))
|
||||
} else {
|
||||
responseHeader.Set(cspReportOnlyHeader, s.opt.ContentSecurityPolicyReportOnly)
|
||||
}
|
||||
}
|
||||
|
||||
// Referrer Policy header.
|
||||
if len(s.opt.ReferrerPolicy) > 0 {
|
||||
responseHeader.Set(referrerPolicyHeader, s.opt.ReferrerPolicy)
|
||||
}
|
||||
|
||||
return responseHeader, nil
|
||||
// Feature Policy header.
|
||||
if len(s.opt.FeaturePolicy) > 0 {
|
||||
responseHeader.Set(featurePolicyHeader, s.opt.FeaturePolicy)
|
||||
}
|
||||
|
||||
// Expect-CT header.
|
||||
if len(s.opt.ExpectCTHeader) > 0 {
|
||||
responseHeader.Set(expectCTHeader, s.opt.ExpectCTHeader)
|
||||
}
|
||||
|
||||
return responseHeader, r, nil
|
||||
}
|
||||
|
||||
// isSSL determine if we are on HTTPS.
|
||||
@@ -369,6 +437,13 @@ func (s *Secure) isSSL(r *http.Request) bool {
|
||||
// Used by http.ReverseProxy.
|
||||
func (s *Secure) ModifyResponseHeaders(res *http.Response) error {
|
||||
if res != nil && res.Request != nil {
|
||||
// Fix Location response header http to https when SSL is enabled.
|
||||
location := res.Header.Get("Location")
|
||||
if s.isSSL(res.Request) && strings.Contains(location, "http:") {
|
||||
location = strings.Replace(location, "http:", "https:", 1)
|
||||
res.Header.Set("Location", location)
|
||||
}
|
||||
|
||||
responseHeader := res.Request.Context().Value(ctxSecureHeaderKey)
|
||||
if responseHeader != nil {
|
||||
for header, values := range responseHeader.(http.Header) {
|
||||
|
||||
Reference in New Issue
Block a user