Vendor all dependencies (Warning: Huge changeset.)

The vendor/ folder was created with the help of @FiloSottile's gvt and
vendorcheck.

Any dependencies of Caddy plugins outside this repo are not vendored.

We do not remove any unused, vendored packages because vendorcheck -u
only checks using the current build configuration; i.e. packages that
may be imported by files toggled by build tags of other systems.

CI tests have been updated to ignore the vendor/ folder. When Go 1.9 is
released, a few of the go commands should be revised to again use ./...
as it will ignore the vendor folder by default.
This commit is contained in:
Matthew Holt
2017-05-27 13:30:11 -06:00
parent 90efff68e5
commit 6fde3632ef
889 changed files with 395382 additions and 326 deletions

View File

@ -45,14 +45,16 @@ func SetupIfMatcher(controller *caddy.Controller) (RequestMatcher, error) {
// operators
const (
isOp = "is"
notOp = "not"
hasOp = "has"
notHasOp = "not_has"
startsWithOp = "starts_with"
endsWithOp = "ends_with"
matchOp = "match"
notMatchOp = "not_match"
isOp = "is"
notOp = "not"
hasOp = "has"
notHasOp = "not_has"
startsWithOp = "starts_with"
notStartsWithOp = "not_starts_with"
endsWithOp = "ends_with"
notEndsWithOp = "not_ends_with"
matchOp = "match"
notMatchOp = "not_match"
)
func operatorError(operator string) error {
@ -63,14 +65,16 @@ func operatorError(operator string) error {
type ifCondition func(string, string) bool
var ifConditions = map[string]ifCondition{
isOp: isFunc,
notOp: notFunc,
hasOp: hasFunc,
notHasOp: notHasFunc,
startsWithOp: startsWithFunc,
endsWithOp: endsWithFunc,
matchOp: matchFunc,
notMatchOp: notMatchFunc,
isOp: isFunc,
notOp: notFunc,
hasOp: hasFunc,
notHasOp: notHasFunc,
startsWithOp: startsWithFunc,
notStartsWithOp: notStartsWithFunc,
endsWithOp: endsWithFunc,
notEndsWithOp: notEndsWithFunc,
matchOp: matchFunc,
notMatchOp: notMatchFunc,
}
// isFunc is condition for Is operator.
@ -82,7 +86,7 @@ func isFunc(a, b string) bool {
// notFunc is condition for Not operator.
// It checks for inequality.
func notFunc(a, b string) bool {
return a != b
return !isFunc(a, b)
}
// hasFunc is condition for Has operator.
@ -94,7 +98,7 @@ func hasFunc(a, b string) bool {
// notHasFunc is condition for NotHas operator.
// It checks if b is not a substring of a.
func notHasFunc(a, b string) bool {
return !strings.Contains(a, b)
return !hasFunc(a, b)
}
// startsWithFunc is condition for StartsWith operator.
@ -103,12 +107,24 @@ func startsWithFunc(a, b string) bool {
return strings.HasPrefix(a, b)
}
// notStartsWithFunc is condition for NotStartsWith operator.
// It checks if b is not a prefix of a.
func notStartsWithFunc(a, b string) bool {
return !startsWithFunc(a, b)
}
// endsWithFunc is condition for EndsWith operator.
// It checks if b is a suffix of a.
func endsWithFunc(a, b string) bool {
return strings.HasSuffix(a, b)
}
// notEndsWithFunc is condition for NotEndsWith operator.
// It checks if b is not a suffix of a.
func notEndsWithFunc(a, b string) bool {
return !endsWithFunc(a, b)
}
// matchFunc is condition for Match operator.
// It does regexp matching of a against pattern in b
// and returns if they match.
@ -121,8 +137,7 @@ func matchFunc(a, b string) bool {
// It does regexp matching of a against pattern in b
// and returns if they do not match.
func notMatchFunc(a, b string) bool {
matched, _ := regexp.MatchString(b, a)
return !matched
return !matchFunc(a, b)
}
// ifCond is statement for a IfMatcher condition.

View File

@ -32,9 +32,15 @@ func TestConditions(t *testing.T) {
{"bab starts_with bb", false},
{"bab starts_with ba", true},
{"bab starts_with bab", true},
{"bab not_starts_with bb", true},
{"bab not_starts_with ba", false},
{"bab not_starts_with bab", false},
{"bab ends_with bb", false},
{"bab ends_with bab", true},
{"bab ends_with ab", true},
{"bab not_ends_with bb", true},
{"bab not_ends_with ab", false},
{"bab not_ends_with bab", false},
{"a match *", false},
{"a match a", true},
{"a match .*", true},
@ -221,7 +227,7 @@ func TestSetupIfMatcher(t *testing.T) {
},
{`test {
if goal has go
if cook not_has go
if cook not_has go
}`, false, IfMatcher{
ifs: []ifCond{
{a: "goal", op: "has", b: "go"},
@ -230,7 +236,7 @@ func TestSetupIfMatcher(t *testing.T) {
}},
{`test {
if goal has go
if cook not_has go
if cook not_has go
if_op and
}`, false, IfMatcher{
ifs: []ifCond{
@ -240,7 +246,7 @@ func TestSetupIfMatcher(t *testing.T) {
}},
{`test {
if goal has go
if cook not_has go
if cook not_has go
if_op not
}`, true, IfMatcher{},
},

View File

@ -12,7 +12,7 @@ import (
"sync"
"testing"
"gopkg.in/mcuadros/go-syslog.v2"
syslog "gopkg.in/mcuadros/go-syslog.v2"
"gopkg.in/mcuadros/go-syslog.v2/format"
)

View File

@ -326,24 +326,34 @@ func (info rawHelloInfo) looksLikeFirefox() bool {
// EC point formats, and handshake compression methods."
// We check for the presence and order of the extensions.
// Note: Sometimes padding (21) is present, sometimes not.
// Note: Sometimes 0x15 (21, padding) is present, sometimes not.
// Note: Firefox 51+ does not advertise 0x3374 (13172, NPN).
// Note: Firefox doesn't advertise 0x0 (0, SNI) when connecting to IP addresses.
requiredExtensionsOrder := []uint16{23, 65281, 10, 11, 35, 16, 5, 65283, 13}
// Note: Firefox 55+ doesn't appear to advertise 0xFF03 (65283, short headers). It used to be between 5 and 13.
requiredExtensionsOrder := []uint16{23, 65281, 10, 11, 35, 16, 5, 13}
if !assertPresenceAndOrdering(requiredExtensionsOrder, info.extensions, true) {
return false
}
// We check for both presence of curves and their ordering.
expectedCurves := []tls.CurveID{29, 23, 24, 25}
if len(info.curves) != len(expectedCurves) {
requiredCurves := []tls.CurveID{29, 23, 24, 25}
if len(info.curves) < len(requiredCurves) {
return false
}
for i := range expectedCurves {
if info.curves[i] != expectedCurves[i] {
for i := range requiredCurves {
if info.curves[i] != requiredCurves[i] {
return false
}
}
if len(info.curves) > len(requiredCurves) {
// newer Firefox (55 Nightly?) may have additional curves at end of list
allowedCurves := []tls.CurveID{256, 257}
for i := range allowedCurves {
if info.curves[len(requiredCurves)+i] != allowedCurves[i] {
return false
}
}
}
if hasGreaseCiphers(info.cipherSuites) {
return false
@ -353,6 +363,9 @@ func (info rawHelloInfo) looksLikeFirefox() bool {
// according to the paper, cipher suites may be not be added
// or reordered by the user, but they may be disabled.
expectedCipherSuiteOrder := []uint16{
TLS_AES_128_GCM_SHA256, // 0x1301
TLS_CHACHA20_POLY1305_SHA256, // 0x1303
TLS_AES_256_GCM_SHA384, // 0x1302
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // 0xc02b
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // 0xc02f
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, // 0xcca9
@ -401,14 +414,14 @@ func (info rawHelloInfo) looksLikeChrome() bool {
// 0xc00a, 0xc014, 0xc009, 0x9c, 0x9d, 0x2f, 0x35, 0xa
chromeCipherExclusions := map[uint16]struct{}{
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: {}, // 0xc024
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: {}, // 0xc023
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: {}, // 0xc028
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: {}, // 0xc027
TLS_RSA_WITH_AES_256_CBC_SHA256: {}, // 0x3d
tls.TLS_RSA_WITH_AES_128_CBC_SHA256: {}, // 0x3c
TLS_DHE_RSA_WITH_AES_128_CBC_SHA: {}, // 0x33
TLS_DHE_RSA_WITH_AES_256_CBC_SHA: {}, // 0x39
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: {}, // 0xc024
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: {}, // 0xc023
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: {}, // 0xc028
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: {}, // 0xc027
TLS_RSA_WITH_AES_256_CBC_SHA256: {}, // 0x3d
tls.TLS_RSA_WITH_AES_128_CBC_SHA256: {}, // 0x3c
TLS_DHE_RSA_WITH_AES_128_CBC_SHA: {}, // 0x33
TLS_DHE_RSA_WITH_AES_256_CBC_SHA: {}, // 0x39
}
for _, ext := range info.cipherSuites {
if _, ok := chromeCipherExclusions[ext]; ok {
@ -511,7 +524,7 @@ func (info rawHelloInfo) looksLikeSafari() bool {
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, // 0xc02c
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // 0xc02b
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, // 0xc024
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // 0xc023
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // 0xc023
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, // 0xc00a
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, // 0xc009
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, // 0xc030
@ -523,7 +536,7 @@ func (info rawHelloInfo) looksLikeSafari() bool {
tls.TLS_RSA_WITH_AES_256_GCM_SHA384, // 0x9d
tls.TLS_RSA_WITH_AES_128_GCM_SHA256, // 0x9c
TLS_RSA_WITH_AES_256_CBC_SHA256, // 0x3d
TLS_RSA_WITH_AES_128_CBC_SHA256, // 0x3c
tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // 0x3c
tls.TLS_RSA_WITH_AES_256_CBC_SHA, // 0x35
tls.TLS_RSA_WITH_AES_128_CBC_SHA, // 0x2f
}
@ -610,11 +623,17 @@ const (
// cipher suites missing from the crypto/tls package,
// in no particular order here
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xc024
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xc023
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xc028
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x3c
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3d
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x33
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x39
TLS_RSA_WITH_RC4_128_MD5 = 0x4
// new PSK ciphers introduced by TLS 1.3, not (yet) in crypto/tls
// https://tlswg.github.io/tls13-spec/#rfc.appendix.A.4)
TLS_AES_128_GCM_SHA256 = 0x1301
TLS_AES_256_GCM_SHA384 = 0x1302
TLS_CHACHA20_POLY1305_SHA256 = 0x1303
TLS_AES_128_CCM_SHA256 = 0x1304
TLS_AES_128_CCM_8_SHA256 = 0x1305
)

View File

@ -139,6 +139,22 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
helloHex: `010000bd030375f9022fc3a6562467f3540d68013b2d0b961979de6129e944efe0b35531323500001ec02bc02fcca9cca8c02cc030c00ac009c013c01400330039002f0035000a010000760000000e000c0000096c6f63616c686f737400170000ff01000100000a000a0008001d001700180019000b00020100002300000010000e000c02683208687474702f312e31000500050100000000ff030000000d0020001e040305030603020308040805080604010501060102010402050206020202`,
interception: false,
},
{
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0",
helloHex: `010001fc0303c99d54ae0628bbb9fea3833a4244c6a712cac9d7738f4930b8b9d8e2f6bd578220f7936cedb48907981c9292fb08ceee6f59bd6fddb3d4271ccd7c12380c5038ab001ec02bc02fcca9cca8c02cc030c00ac009c013c01400330039002f0035000a01000195001500af000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000c0000096c6f63616c686f737400170000ff01000100000a000a0008001d001700180019000b000201000023007886da2d41843ff42131b856982c19a545837b70e604325423a817d925e9d95bd084737682cea6b804dfb7cbe336a3b27b8d520d57520c29cfe5f4f3d3236183b84b05c18f0ca30bf598111e390086fea00d9631f1f78527277eb7838b86e73c4e5d15b55d086b1a4a8aa29f12a55126c6274bcd499bbeb23a0010000e000c02683208687474702f312e31000500050100000000000d0018001604030503060308040805080604010501060102030201`,
interception: false,
},
{
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0",
helloHex: `010000b1030365d899820b999245d571c2f7d6b850f63ad931d3c68ceb9cf5a508421a871dc500001ec02bc02fcca9cca8c02cc030c00ac009c013c01400330039002f0035000a0100006a0000000e000c0000096c6f63616c686f737400170000ff01000100000a000a0008001d001700180019000b00020100002300000010000e000c02683208687474702f312e31000500050100000000000d0018001604030503060308040805080604010501060102030201`,
interception: false,
},
{
// this was a Nightly release at the time
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0",
helloHex: `010001fc030331e380b7d12018e1202ef3327607203df5c5732b4fa5ab5abaf0b60034c2fb662070c836b9b89123e37f4f1074d152df438fa8ee8a0f89b036fd952f4fcc0b994f001c130113031302c02bc02fcca9cca8c02cc030c013c014002f0035000a0100019700000014001200000f63616464797365727665722e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b0002010000230078c97e7716a041e2ea824571bef26a3dff2bf50a883cd15d904ab2d17deb514f6e0a079ee7c212c000178387ffafc2e530b6df6662f570aae134330f13c458a0eaad5a96a9696f572110918740b15db1143d19aaaa706942030b433a7e6150f62b443c0564e5b8f7ee9577bf3bf7faec8c67425b648ab54d880010000e000c02683208687474702f312e310005000501000000000028006b0069001d0020aee6e596155ee6f79f943e81ceabe0979d27fbbb8b9189ccb2ebc75226351f32001700410421875a44e510decac11ef1d7cfddd4dfe105d5cd3a2d42fba03ebde23e51e8ce65bda1b48be82d4848d1db2bfce68e94092e925a9ce0dbf5df35479558108489002b0009087f12030303020301000d0018001604030503060308040805080604010501060102030201002d000201010015002500000000000000000000000000000000000000000000000000000000000000000000000000`,
interception: false,
},
},
"Edge": {
{

View File

@ -436,7 +436,7 @@ var directives = []string{
"root",
"index",
"bind",
"maxrequestbody", // TODO: 'limits'
"limits",
"timeouts",
"tls",
@ -477,6 +477,7 @@ var directives = []string{
"pprof",
"expvar",
"push",
"datadog", // github.com/payintech/caddy-datadog
"prometheus", // github.com/miekg/caddy-prometheus
"proxy",
"fastcgi",

View File

@ -302,7 +302,7 @@ func (r *replacer) getSubstitution(key string) string {
}
_, err := ioutil.ReadAll(r.request.Body)
if err != nil {
if _, ok := err.(MaxBytesExceeded); ok {
if err == ErrMaxBytesExceeded {
return r.emptyValue
}
}

View File

@ -4,8 +4,8 @@ package httpserver
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"log"
"net"
"net/http"
@ -66,6 +66,7 @@ func NewServer(addr string, group []*SiteConfig) (*Server, error) {
sites: group,
connTimeout: GracefulTimeout,
}
s.Server = makeHTTPServerWithHeaderLimit(s.Server, group)
s.Server.Handler = s // this is weird, but whatever
// extract TLS settings from each site config to build
@ -127,6 +128,32 @@ func NewServer(addr string, group []*SiteConfig) (*Server, error) {
return s, nil
}
// makeHTTPServerWithHeaderLimit apply minimum header limit within a group to given http.Server
func makeHTTPServerWithHeaderLimit(s *http.Server, group []*SiteConfig) *http.Server {
var min int64
for _, cfg := range group {
limit := cfg.Limits.MaxRequestHeaderSize
if limit == 0 {
continue
}
// not set yet
if min == 0 {
min = limit
}
// find a better one
if limit < min {
min = limit
}
}
if min > 0 {
s.MaxHeaderBytes = int(min)
}
return s
}
// makeHTTPServerWithTimeouts makes an http.Server from the group of
// configs in a way that configures timeouts (or, if not set, it uses
// the default timeouts) by combining the configuration of each
@ -359,20 +386,6 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
}
}
// Apply the path-based request body size limit
// The error returned by MaxBytesReader is meant to be handled
// by whichever middleware/plugin that receives it when calling
// .Read() or a similar method on the request body
// TODO: Make this middleware instead?
if r.Body != nil {
for _, pathlimit := range vhost.MaxRequestBodySizes {
if Path(r.URL.Path).Matches(pathlimit.Path) {
r.Body = MaxBytesReader(w, r.Body, pathlimit.Limit)
break
}
}
}
return vhost.middlewareChain.ServeHTTP(w, r)
}
@ -465,73 +478,9 @@ func (ln tcpKeepAliveListener) File() (*os.File, error) {
return ln.TCPListener.File()
}
// MaxBytesExceeded is the error type returned by MaxBytesReader
// ErrMaxBytesExceeded is the error returned by MaxBytesReader
// when the request body exceeds the limit imposed
type MaxBytesExceeded struct{}
func (err MaxBytesExceeded) Error() string {
return "http: request body too large"
}
// MaxBytesReader and its associated methods are borrowed from the
// Go Standard library (comments intact). The only difference is that
// it returns a MaxBytesExceeded error instead of a generic error message
// when the request body has exceeded the requested limit
func MaxBytesReader(w http.ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
return &maxBytesReader{w: w, r: r, n: n}
}
type maxBytesReader struct {
w http.ResponseWriter
r io.ReadCloser // underlying reader
n int64 // max bytes remaining
err error // sticky error
}
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
if l.err != nil {
return 0, l.err
}
if len(p) == 0 {
return 0, nil
}
// If they asked for a 32KB byte read but only 5 bytes are
// remaining, no need to read 32KB. 6 bytes will answer the
// question of the whether we hit the limit or go past it.
if int64(len(p)) > l.n+1 {
p = p[:l.n+1]
}
n, err = l.r.Read(p)
if int64(n) <= l.n {
l.n -= int64(n)
l.err = err
return n, err
}
n = int(l.n)
l.n = 0
// The server code and client code both use
// maxBytesReader. This "requestTooLarge" check is
// only used by the server code. To prevent binaries
// which only using the HTTP Client code (such as
// cmd/go) from also linking in the HTTP server, don't
// use a static type assertion to the server
// "*response" type. Check this interface instead:
type requestTooLarger interface {
requestTooLarge()
}
if res, ok := l.w.(requestTooLarger); ok {
res.requestTooLarge()
}
l.err = MaxBytesExceeded{}
return n, l.err
}
func (l *maxBytesReader) Close() error {
return l.r.Close()
}
var ErrMaxBytesExceeded = errors.New("http: request body too large")
// DefaultErrorFunc responds to an HTTP request with a simple description
// of the specified HTTP status code.

View File

@ -15,7 +15,7 @@ func TestAddress(t *testing.T) {
}
}
func TestMakeHTTPServer(t *testing.T) {
func TestMakeHTTPServerWithTimeouts(t *testing.T) {
for i, tc := range []struct {
group []*SiteConfig
expected Timeouts
@ -111,3 +111,36 @@ func TestMakeHTTPServer(t *testing.T) {
}
}
}
func TestMakeHTTPServerWithHeaderLimit(t *testing.T) {
for name, c := range map[string]struct {
group []*SiteConfig
expect int
}{
"disable": {
group: []*SiteConfig{{}},
expect: 0,
},
"oneSite": {
group: []*SiteConfig{{Limits: Limits{
MaxRequestHeaderSize: 100,
}}},
expect: 100,
},
"multiSites": {
group: []*SiteConfig{
{Limits: Limits{MaxRequestHeaderSize: 100}},
{Limits: Limits{MaxRequestHeaderSize: 50}},
},
expect: 50,
},
} {
c := c
t.Run(name, func(t *testing.T) {
actual := makeHTTPServerWithHeaderLimit(&http.Server{}, c.group)
if got := actual.MaxHeaderBytes; got != c.expect {
t.Errorf("Expect %d, but got %d", c.expect, got)
}
})
}
}

View File

@ -38,8 +38,8 @@ type SiteConfig struct {
// for a request.
HiddenFiles []string
// Max amount of bytes a request can send on a given path
MaxRequestBodySizes []PathLimit
// Max request's header/body size
Limits Limits
// The path to the Caddyfile used to generate this site config
originCaddyfile string
@ -71,6 +71,12 @@ type Timeouts struct {
IdleTimeoutSet bool
}
// Limits specify size limit of request's header and body.
type Limits struct {
MaxRequestHeaderSize int64
MaxRequestBodySizes []PathLimit
}
// PathLimit is a mapping from a site's path to its corresponding
// maximum request body size (in bytes)
type PathLimit struct {