diff --git a/hack/vendor.sh b/hack/vendor.sh index 1119c37b25..7f01a236c8 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -39,11 +39,11 @@ clone() { echo done } -clone git github.com/kr/pty 98c7b80083 +clone git github.com/kr/pty 67e2db24c8 -clone git github.com/gorilla/context 708054d61e5 +clone git github.com/gorilla/context b06ed15e1c -clone git github.com/gorilla/mux 9b36453141c +clone git github.com/gorilla/mux 136d54f81f clone git github.com/syndtr/gocapability 3c85049eae diff --git a/vendor/src/github.com/gorilla/context/.travis.yml b/vendor/src/github.com/gorilla/context/.travis.yml new file mode 100644 index 0000000000..d87d465768 --- /dev/null +++ b/vendor/src/github.com/gorilla/context/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - 1.0 + - 1.1 + - 1.2 + - tip diff --git a/vendor/src/github.com/gorilla/context/README.md b/vendor/src/github.com/gorilla/context/README.md index 8ee62b4263..c60a31b053 100644 --- a/vendor/src/github.com/gorilla/context/README.md +++ b/vendor/src/github.com/gorilla/context/README.md @@ -1,5 +1,6 @@ context ======= +[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) gorilla/context is a general purpose registry for global request variables. diff --git a/vendor/src/github.com/gorilla/context/context.go b/vendor/src/github.com/gorilla/context/context.go index 35d65561f3..a7f7d85bb4 100644 --- a/vendor/src/github.com/gorilla/context/context.go +++ b/vendor/src/github.com/gorilla/context/context.go @@ -11,7 +11,7 @@ import ( ) var ( - mutex sync.Mutex + mutex sync.RWMutex data = make(map[*http.Request]map[interface{}]interface{}) datat = make(map[*http.Request]int64) ) @@ -19,42 +19,64 @@ var ( // Set stores a value for a given key in a given request. func Set(r *http.Request, key, val interface{}) { mutex.Lock() - defer mutex.Unlock() if data[r] == nil { data[r] = make(map[interface{}]interface{}) datat[r] = time.Now().Unix() } data[r][key] = val + mutex.Unlock() } // Get returns a value stored for a given key in a given request. func Get(r *http.Request, key interface{}) interface{} { - mutex.Lock() - defer mutex.Unlock() + mutex.RLock() if data[r] != nil { + mutex.RUnlock() return data[r][key] } + mutex.RUnlock() return nil } // GetOk returns stored value and presence state like multi-value return of map access. func GetOk(r *http.Request, key interface{}) (interface{}, bool) { - mutex.Lock() - defer mutex.Unlock() + mutex.RLock() if _, ok := data[r]; ok { value, ok := data[r][key] + mutex.RUnlock() return value, ok } + mutex.RUnlock() return nil, false } +// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. +func GetAll(r *http.Request) map[interface{}]interface{} { + mutex.RLock() + if context, ok := data[r]; ok { + mutex.RUnlock() + return context + } + mutex.RUnlock() + return nil +} + +// GetAllOk returns all stored values for the request as a map. It returns not +// ok if the request was never registered. +func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { + mutex.RLock() + context, ok := data[r] + mutex.RUnlock() + return context, ok +} + // Delete removes a value stored for a given key in a given request. func Delete(r *http.Request, key interface{}) { mutex.Lock() - defer mutex.Unlock() if data[r] != nil { delete(data[r], key) } + mutex.Unlock() } // Clear removes all values stored for a given request. @@ -63,8 +85,8 @@ func Delete(r *http.Request, key interface{}) { // variables at the end of a request lifetime. See ClearHandler(). func Clear(r *http.Request) { mutex.Lock() - defer mutex.Unlock() clear(r) + mutex.Unlock() } // clear is Clear without the lock. @@ -84,7 +106,6 @@ func clear(r *http.Request) { // periodically until the problem is fixed. func Purge(maxAge int) int { mutex.Lock() - defer mutex.Unlock() count := 0 if maxAge <= 0 { count = len(data) @@ -92,13 +113,14 @@ func Purge(maxAge int) int { datat = make(map[*http.Request]int64) } else { min := time.Now().Unix() - int64(maxAge) - for r, _ := range data { + for r := range data { if datat[r] < min { clear(r) count++ } } } + mutex.Unlock() return count } diff --git a/vendor/src/github.com/gorilla/context/context_test.go b/vendor/src/github.com/gorilla/context/context_test.go index ff9e2ad5fc..6ada8ec31f 100644 --- a/vendor/src/github.com/gorilla/context/context_test.go +++ b/vendor/src/github.com/gorilla/context/context_test.go @@ -24,6 +24,7 @@ func TestContext(t *testing.T) { } r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) + emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil) // Get() assertEqual(Get(r, key1), nil) @@ -51,6 +52,26 @@ func TestContext(t *testing.T) { assertEqual(value, nil) assertEqual(ok, true) + // GetAll() + values := GetAll(r) + assertEqual(len(values), 3) + + // GetAll() for empty request + values = GetAll(emptyR) + if values != nil { + t.Error("GetAll didn't return nil value for invalid request") + } + + // GetAllOk() + values, ok = GetAllOk(r) + assertEqual(len(values), 3) + assertEqual(ok, true) + + // GetAllOk() for empty request + values, ok = GetAllOk(emptyR) + assertEqual(value, nil) + assertEqual(ok, false) + // Delete() Delete(r, key1) assertEqual(Get(r, key1), nil) @@ -64,3 +85,77 @@ func TestContext(t *testing.T) { Clear(r) assertEqual(len(data), 0) } + +func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) { + <-wait + for i := 0; i < iterations; i++ { + Get(r, key) + } + done <- struct{}{} + +} + +func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) { + <-wait + for i := 0; i < iterations; i++ { + Get(r, key) + } + done <- struct{}{} + +} + +func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) { + + b.StopTimer() + r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) + done := make(chan struct{}) + b.StartTimer() + + for i := 0; i < b.N; i++ { + wait := make(chan struct{}) + + for i := 0; i < numReaders; i++ { + go parallelReader(r, "test", iterations, wait, done) + } + + for i := 0; i < numWriters; i++ { + go parallelWriter(r, "test", "123", iterations, wait, done) + } + + close(wait) + + for i := 0; i < numReaders+numWriters; i++ { + <-done + } + + } + +} + +func BenchmarkMutexSameReadWrite1(b *testing.B) { + benchmarkMutex(b, 1, 1, 32) +} +func BenchmarkMutexSameReadWrite2(b *testing.B) { + benchmarkMutex(b, 2, 2, 32) +} +func BenchmarkMutexSameReadWrite4(b *testing.B) { + benchmarkMutex(b, 4, 4, 32) +} +func BenchmarkMutex1(b *testing.B) { + benchmarkMutex(b, 2, 8, 32) +} +func BenchmarkMutex2(b *testing.B) { + benchmarkMutex(b, 16, 4, 64) +} +func BenchmarkMutex3(b *testing.B) { + benchmarkMutex(b, 1, 2, 128) +} +func BenchmarkMutex4(b *testing.B) { + benchmarkMutex(b, 128, 32, 256) +} +func BenchmarkMutex5(b *testing.B) { + benchmarkMutex(b, 1024, 2048, 64) +} +func BenchmarkMutex6(b *testing.B) { + benchmarkMutex(b, 2048, 1024, 512) +} diff --git a/vendor/src/github.com/gorilla/context/doc.go b/vendor/src/github.com/gorilla/context/doc.go index 297606455c..73c7400311 100644 --- a/vendor/src/github.com/gorilla/context/doc.go +++ b/vendor/src/github.com/gorilla/context/doc.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. /* -Package gorilla/context stores values shared during a request lifetime. +Package context stores values shared during a request lifetime. For example, a router can set variables extracted from the URL and later application handlers can access those values, or it can be used to store diff --git a/vendor/src/github.com/gorilla/mux/.travis.yml b/vendor/src/github.com/gorilla/mux/.travis.yml new file mode 100644 index 0000000000..d87d465768 --- /dev/null +++ b/vendor/src/github.com/gorilla/mux/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - 1.0 + - 1.1 + - 1.2 + - tip diff --git a/vendor/src/github.com/gorilla/mux/README.md b/vendor/src/github.com/gorilla/mux/README.md index f6db41ad81..e60301b033 100644 --- a/vendor/src/github.com/gorilla/mux/README.md +++ b/vendor/src/github.com/gorilla/mux/README.md @@ -1,5 +1,6 @@ mux === +[![Build Status](https://travis-ci.org/gorilla/mux.png?branch=master)](https://travis-ci.org/gorilla/mux) gorilla/mux is a powerful URL router and dispatcher. diff --git a/vendor/src/github.com/gorilla/mux/doc.go b/vendor/src/github.com/gorilla/mux/doc.go index 8ee5540a4f..b2deed34c4 100644 --- a/vendor/src/github.com/gorilla/mux/doc.go +++ b/vendor/src/github.com/gorilla/mux/doc.go @@ -134,7 +134,7 @@ the inner routes use it as base for their paths: // "/products/{key}/" s.HandleFunc("/{key}/", ProductHandler) // "/products/{key}/details" - s.HandleFunc("/{key}/details"), ProductDetailsHandler) + s.HandleFunc("/{key}/details", ProductDetailsHandler) Now let's see how to build registered URLs. diff --git a/vendor/src/github.com/gorilla/mux/mux.go b/vendor/src/github.com/gorilla/mux/mux.go index 385717394c..8b23c39d39 100644 --- a/vendor/src/github.com/gorilla/mux/mux.go +++ b/vendor/src/github.com/gorilla/mux/mux.go @@ -14,7 +14,7 @@ import ( // NewRouter returns a new router instance. func NewRouter() *Router { - return &Router{namedRoutes: make(map[string]*Route)} + return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} } // Router registers routes to be matched and dispatches a handler. @@ -46,6 +46,8 @@ type Router struct { namedRoutes map[string]*Route // See Router.StrictSlash(). This defines the flag for new routes. strictSlash bool + // If true, do not clear the request context after handling the request + KeepContext bool } // Match matches registered routes against the request. @@ -65,6 +67,14 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool { func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Clean path to canonical form and redirect. if p := cleanPath(req.URL.Path); p != req.URL.Path { + + // Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query. + // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: + // http://code.google.com/p/go/issues/detail?id=5252 + url := *req.URL + url.Path = p + p = url.String() + w.Header().Set("Location", p) w.WriteHeader(http.StatusMovedPermanently) return @@ -82,7 +92,9 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { } handler = r.NotFoundHandler } - defer context.Clear(req) + if !r.KeepContext { + defer context.Clear(req) + } handler.ServeHTTP(w, req) } @@ -97,14 +109,20 @@ func (r *Router) GetRoute(name string) *Route { return r.getNamedRoutes()[name] } -// StrictSlash defines the slash behavior for new routes. +// StrictSlash defines the trailing slash behavior for new routes. The initial +// value is false. // // When true, if the route path is "/path/", accessing "/path" will redirect -// to the former and vice versa. +// to the former and vice versa. In other words, your application will always +// see the path as specified in the route. // -// Special case: when a route sets a path prefix, strict slash is -// automatically set to false for that route because the redirect behavior -// can't be determined for prefixes. +// When false, if the route path is "/path", accessing "/path/" will not match +// this route and vice versa. +// +// Special case: when a route sets a path prefix using the PathPrefix() method, +// strict slash is ignored for that route because the redirect behavior can't +// be determined from a prefix alone. However, any subrouters created from that +// route inherit the original StrictSlash setting. func (r *Router) StrictSlash(value bool) *Router { r.strictSlash = value return r diff --git a/vendor/src/github.com/gorilla/mux/mux_test.go b/vendor/src/github.com/gorilla/mux/mux_test.go index 55159bd10d..0e2e48067a 100644 --- a/vendor/src/github.com/gorilla/mux/mux_test.go +++ b/vendor/src/github.com/gorilla/mux/mux_test.go @@ -8,16 +8,19 @@ import ( "fmt" "net/http" "testing" + + "github.com/gorilla/context" ) type routeTest struct { - title string // title of the test - route *Route // the route being tested - request *http.Request // a request to test the route - vars map[string]string // the expected vars of the match - host string // the expected host of the match - path string // the expected path of the match - shouldMatch bool // whether the request is expected to match the route at all + title string // title of the test + route *Route // the route being tested + request *http.Request // a request to test the route + vars map[string]string // the expected vars of the match + host string // the expected host of the match + path string // the expected path of the match + shouldMatch bool // whether the request is expected to match the route at all + shouldRedirect bool // whether the request should result in a redirect } func TestHost(t *testing.T) { @@ -149,6 +152,33 @@ func TestPath(t *testing.T) { path: "/111/222/333", shouldMatch: true, }, + { + title: "Path route, match with trailing slash in request and path", + route: new(Route).Path("/111/"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: true, + }, + { + title: "Path route, do not match with trailing slash in path", + route: new(Route).Path("/111/"), + request: newRequest("GET", "http://localhost/111"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: false, + }, + { + title: "Path route, do not match with trailing slash in request", + route: new(Route).Path("/111"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: false, + }, { title: "Path route, wrong path in request in request URL", route: new(Route).Path("/111/222/333"), @@ -212,6 +242,15 @@ func TestPathPrefix(t *testing.T) { path: "/111", shouldMatch: true, }, + { + title: "PathPrefix route, match substring", + route: new(Route).PathPrefix("/1"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{}, + host: "", + path: "/1", + shouldMatch: true, + }, { title: "PathPrefix route, URL prefix in request does not match", route: new(Route).PathPrefix("/111"), @@ -414,6 +453,15 @@ func TestQueries(t *testing.T) { path: "", shouldMatch: true, }, + { + title: "Queries route, match with a query string", + route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"), + request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, { title: "Queries route, bad query", route: new(Route).Queries("foo", "bar", "baz", "ding"), @@ -568,26 +616,74 @@ func TestNamedRoutes(t *testing.T) { } func TestStrictSlash(t *testing.T) { - var r *Router - var req *http.Request - var route *Route - var match *RouteMatch - var matched bool - - // StrictSlash should be ignored for path prefix. - // So we register a route ending in slash but it doesn't attempt to add - // the slash for a path not ending in slash. - r = NewRouter() + r := NewRouter() r.StrictSlash(true) - route = r.NewRoute().PathPrefix("/static/") - req, _ = http.NewRequest("GET", "http://localhost/static/logo.png", nil) - match = new(RouteMatch) - matched = r.Match(req, match) - if !matched { - t.Errorf("Should match request %q -- %v", req.URL.Path, getRouteTemplate(route)) + + tests := []routeTest{ + { + title: "Redirect path without slash", + route: r.NewRoute().Path("/111/"), + request: newRequest("GET", "http://localhost/111"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: true, + shouldRedirect: true, + }, + { + title: "Do not redirect path with slash", + route: r.NewRoute().Path("/111/"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: true, + shouldRedirect: false, + }, + { + title: "Redirect path with slash", + route: r.NewRoute().Path("/111"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: true, + shouldRedirect: true, + }, + { + title: "Do not redirect path without slash", + route: r.NewRoute().Path("/111"), + request: newRequest("GET", "http://localhost/111"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: true, + shouldRedirect: false, + }, + { + title: "Propagate StrictSlash to subrouters", + route: r.NewRoute().PathPrefix("/static/").Subrouter().Path("/images/"), + request: newRequest("GET", "http://localhost/static/images"), + vars: map[string]string{}, + host: "", + path: "/static/images/", + shouldMatch: true, + shouldRedirect: true, + }, + { + title: "Ignore StrictSlash for path prefix", + route: r.NewRoute().PathPrefix("/static/"), + request: newRequest("GET", "http://localhost/static/logo.png"), + vars: map[string]string{}, + host: "", + path: "/static/", + shouldMatch: true, + shouldRedirect: false, + }, } - if match.Handler != nil { - t.Errorf("Should not redirect") + + for _, test := range tests { + testRoute(t, test) } } @@ -616,6 +712,7 @@ func testRoute(t *testing.T, test routeTest) { host := test.host path := test.path url := test.host + test.path + shouldRedirect := test.shouldRedirect var match RouteMatch ok := route.Match(request, &match) @@ -653,6 +750,84 @@ func testRoute(t *testing.T, test routeTest) { return } } + if shouldRedirect && match.Handler == nil { + t.Errorf("(%v) Did not redirect", test.title) + return + } + if !shouldRedirect && match.Handler != nil { + t.Errorf("(%v) Unexpected redirect", test.title) + return + } + } +} + +// Tests that the context is cleared or not cleared properly depending on +// the configuration of the router +func TestKeepContext(t *testing.T) { + func1 := func(w http.ResponseWriter, r *http.Request) {} + + r := NewRouter() + r.HandleFunc("/", func1).Name("func1") + + req, _ := http.NewRequest("GET", "http://localhost/", nil) + context.Set(req, "t", 1) + + res := new(http.ResponseWriter) + r.ServeHTTP(*res, req) + + if _, ok := context.GetOk(req, "t"); ok { + t.Error("Context should have been cleared at end of request") + } + + r.KeepContext = true + + req, _ = http.NewRequest("GET", "http://localhost/", nil) + context.Set(req, "t", 1) + + r.ServeHTTP(*res, req) + if _, ok := context.GetOk(req, "t"); !ok { + t.Error("Context should NOT have been cleared at end of request") + } + +} + +type TestA301ResponseWriter struct { + hh http.Header + status int +} + +func (ho TestA301ResponseWriter) Header() http.Header { + return http.Header(ho.hh) +} + +func (ho TestA301ResponseWriter) Write(b []byte) (int, error) { + return 0, nil +} + +func (ho TestA301ResponseWriter) WriteHeader(code int) { + ho.status = code +} + +func Test301Redirect(t *testing.T) { + m := make(http.Header) + + func1 := func(w http.ResponseWriter, r *http.Request) {} + func2 := func(w http.ResponseWriter, r *http.Request) {} + + r := NewRouter() + r.HandleFunc("/api/", func2).Name("func2") + r.HandleFunc("/", func1).Name("func1") + + req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil) + + res := TestA301ResponseWriter{ + hh: m, + status: 0, + } + r.ServeHTTP(&res, req) + + if "http://localhost/api/?abc=def" != res.hh["Location"][0] { + t.Errorf("Should have complete URL with query string") } } diff --git a/vendor/src/github.com/gorilla/mux/old_test.go b/vendor/src/github.com/gorilla/mux/old_test.go index 7e266bb695..42530590e7 100644 --- a/vendor/src/github.com/gorilla/mux/old_test.go +++ b/vendor/src/github.com/gorilla/mux/old_test.go @@ -96,8 +96,8 @@ func TestRouteMatchers(t *testing.T) { method = "GET" headers = map[string]string{"X-Requested-With": "XMLHttpRequest"} resultVars = map[bool]map[string]string{ - true: map[string]string{"var1": "www", "var2": "product", "var3": "42"}, - false: map[string]string{}, + true: {"var1": "www", "var2": "product", "var3": "42"}, + false: {}, } } @@ -110,8 +110,8 @@ func TestRouteMatchers(t *testing.T) { method = "POST" headers = map[string]string{"Content-Type": "application/json"} resultVars = map[bool]map[string]string{ - true: map[string]string{"var4": "google", "var5": "product", "var6": "42"}, - false: map[string]string{}, + true: {"var4": "google", "var5": "product", "var6": "42"}, + false: {}, } } diff --git a/vendor/src/github.com/gorilla/mux/regexp.go b/vendor/src/github.com/gorilla/mux/regexp.go index 4c3482bfbd..925f268abe 100644 --- a/vendor/src/github.com/gorilla/mux/regexp.go +++ b/vendor/src/github.com/gorilla/mux/regexp.go @@ -98,12 +98,13 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, strictSlash bool) (*rout } // Done! return &routeRegexp{ - template: template, - matchHost: matchHost, - regexp: reg, - reverse: reverse.String(), - varsN: varsN, - varsR: varsR, + template: template, + matchHost: matchHost, + strictSlash: strictSlash, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, }, nil } @@ -114,6 +115,8 @@ type routeRegexp struct { template string // True for host match, false for path match. matchHost bool + // The strictSlash value defined on the route, but disabled if PathPrefix was used. + strictSlash bool // Expanded regexp. regexp *regexp.Regexp // Reverse template. @@ -216,7 +219,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) m.Vars[v] = pathVars[k+1] } // Check if we should redirect. - if r.strictSlash { + if v.path.strictSlash { p1 := strings.HasSuffix(req.URL.Path, "/") p2 := strings.HasSuffix(v.path.template, "/") if p1 != p2 { diff --git a/vendor/src/github.com/gorilla/mux/route.go b/vendor/src/github.com/gorilla/mux/route.go index cb538ea4ec..5cb2526d61 100644 --- a/vendor/src/github.com/gorilla/mux/route.go +++ b/vendor/src/github.com/gorilla/mux/route.go @@ -259,7 +259,8 @@ func (r *Route) Methods(methods ...string) *Route { // Path ----------------------------------------------------------------------- // Path adds a matcher for the URL path. -// It accepts a template with zero or more URL variables enclosed by {}. +// It accepts a template with zero or more URL variables enclosed by {}. The +// template must start with a "/". // Variables can define an optional regexp pattern to me matched: // // - {name} matches anything until the next slash. @@ -283,9 +284,16 @@ func (r *Route) Path(tpl string) *Route { // PathPrefix ----------------------------------------------------------------- -// PathPrefix adds a matcher for the URL path prefix. +// PathPrefix adds a matcher for the URL path prefix. This matches if the given +// template is a prefix of the full URL path. See Route.Path() for details on +// the tpl argument. +// +// Note that it does not treat slashes specially ("/foobar/" will be matched by +// the prefix "/foo") so you may want to use a trailing slash here. +// +// Also note that the setting of Router.StrictSlash() has no effect on routes +// with a PathPrefix matcher. func (r *Route) PathPrefix(tpl string) *Route { - r.strictSlash = false r.err = r.addRegexpMatcher(tpl, false, true) return r } @@ -328,7 +336,7 @@ func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool { } // Schemes adds a matcher for URL schemes. -// It accepts a sequence schemes to be matched, e.g.: "http", "https". +// It accepts a sequence of schemes to be matched, e.g.: "http", "https". func (r *Route) Schemes(schemes ...string) *Route { for k, v := range schemes { schemes[k] = strings.ToLower(v) diff --git a/vendor/src/github.com/kr/pty/ioctl.go b/vendor/src/github.com/kr/pty/ioctl.go new file mode 100644 index 0000000000..5b856e8711 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ioctl.go @@ -0,0 +1,11 @@ +package pty + +import "syscall" + +func ioctl(fd, cmd, ptr uintptr) error { + _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr) + if e != 0 { + return e + } + return nil +} diff --git a/vendor/src/github.com/kr/pty/ioctl_bsd.go b/vendor/src/github.com/kr/pty/ioctl_bsd.go new file mode 100644 index 0000000000..73b12c53cf --- /dev/null +++ b/vendor/src/github.com/kr/pty/ioctl_bsd.go @@ -0,0 +1,39 @@ +// +build darwin dragonfly freebsd netbsd openbsd + +package pty + +// from +const ( + _IOC_VOID uintptr = 0x20000000 + _IOC_OUT uintptr = 0x40000000 + _IOC_IN uintptr = 0x80000000 + _IOC_IN_OUT uintptr = _IOC_OUT | _IOC_IN + _IOC_DIRMASK = _IOC_VOID | _IOC_OUT | _IOC_IN + + _IOC_PARAM_SHIFT = 13 + _IOC_PARAM_MASK = (1 << _IOC_PARAM_SHIFT) - 1 +) + +func _IOC_PARM_LEN(ioctl uintptr) uintptr { + return (ioctl >> 16) & _IOC_PARAM_MASK +} + +func _IOC(inout uintptr, group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return inout | (param_len&_IOC_PARAM_MASK)<<16 | uintptr(group)<<8 | ioctl_num +} + +func _IO(group byte, ioctl_num uintptr) uintptr { + return _IOC(_IOC_VOID, group, ioctl_num, 0) +} + +func _IOR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return _IOC(_IOC_OUT, group, ioctl_num, param_len) +} + +func _IOW(group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return _IOC(_IOC_IN, group, ioctl_num, param_len) +} + +func _IOWR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return _IOC(_IOC_IN_OUT, group, ioctl_num, param_len) +} diff --git a/vendor/src/github.com/kr/pty/ioctl_linux.go b/vendor/src/github.com/kr/pty/ioctl_linux.go new file mode 100644 index 0000000000..9fe7b0b0f9 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ioctl_linux.go @@ -0,0 +1,42 @@ +package pty + +// from +const ( + _IOC_NRBITS = 8 + _IOC_TYPEBITS = 8 + + _IOC_SIZEBITS = 14 + _IOC_DIRBITS = 2 + + _IOC_NRSHIFT = 0 + _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS + _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS + _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS + + _IOC_NONE uint = 0 + _IOC_WRITE uint = 1 + _IOC_READ uint = 2 +) + +func _IOC(dir uint, ioctl_type byte, nr byte, size uintptr) uintptr { + return (uintptr(dir)<<_IOC_DIRSHIFT | + uintptr(ioctl_type)<<_IOC_TYPESHIFT | + uintptr(nr)<<_IOC_NRSHIFT | + size<<_IOC_SIZESHIFT) +} + +func _IO(ioctl_type byte, nr byte) uintptr { + return _IOC(_IOC_NONE, ioctl_type, nr, 0) +} + +func _IOR(ioctl_type byte, nr byte, size uintptr) uintptr { + return _IOC(_IOC_READ, ioctl_type, nr, size) +} + +func _IOW(ioctl_type byte, nr byte, size uintptr) uintptr { + return _IOC(_IOC_WRITE, ioctl_type, nr, size) +} + +func _IOWR(ioctl_type byte, nr byte, size uintptr) uintptr { + return _IOC(_IOC_READ|_IOC_WRITE, ioctl_type, nr, size) +} diff --git a/vendor/src/github.com/kr/pty/mktypes.bash b/vendor/src/github.com/kr/pty/mktypes.bash new file mode 100755 index 0000000000..9952c88838 --- /dev/null +++ b/vendor/src/github.com/kr/pty/mktypes.bash @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +GOOSARCH="${GOOS}_${GOARCH}" +case "$GOOSARCH" in +_* | *_ | _) + echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 + exit 1 + ;; +esac + +GODEFS="go tool cgo -godefs" + +$GODEFS types.go |gofmt > ztypes_$GOARCH.go + +case $GOOS in +freebsd) + $GODEFS types_$GOOS.go |gofmt > ztypes_$GOOSARCH.go + ;; +esac diff --git a/vendor/src/github.com/kr/pty/pty_darwin.go b/vendor/src/github.com/kr/pty/pty_darwin.go index 597bb03e57..4f4d5ca26e 100644 --- a/vendor/src/github.com/kr/pty/pty_darwin.go +++ b/vendor/src/github.com/kr/pty/pty_darwin.go @@ -7,9 +7,6 @@ import ( "unsafe" ) -// see ioccom.h -const sys_IOCPARM_MASK = 0x1fff - func open() (pty, tty *os.File, err error) { p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) if err != nil { @@ -39,9 +36,13 @@ func open() (pty, tty *os.File, err error) { } func ptsname(f *os.File) (string, error) { - var n [(syscall.TIOCPTYGNAME >> 16) & sys_IOCPARM_MASK]byte + n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME)) + + err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0]))) + if err != nil { + return "", err + } - ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n))) for i, c := range n { if c == 0 { return string(n[:i]), nil @@ -51,19 +52,9 @@ func ptsname(f *os.File) (string, error) { } func grantpt(f *os.File) error { - var u int - return ioctl(f.Fd(), syscall.TIOCPTYGRANT, uintptr(unsafe.Pointer(&u))) + return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0) } func unlockpt(f *os.File) error { - var u int - return ioctl(f.Fd(), syscall.TIOCPTYUNLK, uintptr(unsafe.Pointer(&u))) -} - -func ioctl(fd, cmd, ptr uintptr) error { - _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr) - if e != 0 { - return syscall.ENOTTY - } - return nil + return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0) } diff --git a/vendor/src/github.com/kr/pty/pty_freebsd.go b/vendor/src/github.com/kr/pty/pty_freebsd.go index 13b64d722e..b341babd05 100644 --- a/vendor/src/github.com/kr/pty/pty_freebsd.go +++ b/vendor/src/github.com/kr/pty/pty_freebsd.go @@ -1,53 +1,73 @@ package pty import ( + "errors" "os" - "strconv" "syscall" "unsafe" ) -const ( - sys_TIOCGPTN = 0x4004740F - sys_TIOCSPTLCK = 0x40045431 -) +func posix_openpt(oflag int) (fd int, err error) { + r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0) + fd = int(r0) + if e1 != 0 { + err = e1 + } + return +} func open() (pty, tty *os.File, err error) { - p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) + fd, err := posix_openpt(syscall.O_RDWR | syscall.O_CLOEXEC) if err != nil { return nil, nil, err } + p := os.NewFile(uintptr(fd), "/dev/pts") sname, err := ptsname(p) if err != nil { return nil, nil, err } - t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) + t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0) if err != nil { return nil, nil, err } return p, t, nil } +func isptmaster(fd uintptr) (bool, error) { + err := ioctl(fd, syscall.TIOCPTMASTER, 0) + return err == nil, err +} + +var ( + emptyFiodgnameArg fiodgnameArg + ioctl_FIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) +) + func ptsname(f *os.File) (string, error) { - var n int - err := ioctl(f.Fd(), sys_TIOCGPTN, &n) + master, err := isptmaster(f.Fd()) if err != nil { return "", err } - return "/dev/pts/" + strconv.Itoa(n), nil -} - -func ioctl(fd uintptr, cmd uintptr, data *int) error { - _, _, e := syscall.Syscall( - syscall.SYS_IOCTL, - fd, - cmd, - uintptr(unsafe.Pointer(data)), - ) - if e != 0 { - return syscall.ENOTTY + if !master { + return "", syscall.EINVAL } - return nil + + const n = _C_SPECNAMELEN + 1 + var ( + buf = make([]byte, n) + arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))} + ) + err = ioctl(f.Fd(), ioctl_FIODGNAME, uintptr(unsafe.Pointer(&arg))) + if err != nil { + return "", err + } + + for i, c := range buf { + if c == 0 { + return string(buf[:i]), nil + } + } + return "", errors.New("FIODGNAME string not NUL-terminated") } diff --git a/vendor/src/github.com/kr/pty/pty_linux.go b/vendor/src/github.com/kr/pty/pty_linux.go index a5edfbb394..6e5a04241c 100644 --- a/vendor/src/github.com/kr/pty/pty_linux.go +++ b/vendor/src/github.com/kr/pty/pty_linux.go @@ -7,9 +7,9 @@ import ( "unsafe" ) -const ( - sys_TIOCGPTN = 0x80045430 - sys_TIOCSPTLCK = 0x40045431 +var ( + ioctl_TIOCGPTN = _IOR('T', 0x30, unsafe.Sizeof(_C_uint(0))) /* Get Pty Number (of pty-mux device) */ + ioctl_TIOCSPTLCK = _IOW('T', 0x31, unsafe.Sizeof(_C_int(0))) /* Lock/unlock Pty */ ) func open() (pty, tty *os.File, err error) { @@ -36,28 +36,16 @@ func open() (pty, tty *os.File, err error) { } func ptsname(f *os.File) (string, error) { - var n int - err := ioctl(f.Fd(), sys_TIOCGPTN, &n) + var n _C_uint + err := ioctl(f.Fd(), ioctl_TIOCGPTN, uintptr(unsafe.Pointer(&n))) if err != nil { return "", err } - return "/dev/pts/" + strconv.Itoa(n), nil + return "/dev/pts/" + strconv.Itoa(int(n)), nil } func unlockpt(f *os.File) error { - var u int - return ioctl(f.Fd(), sys_TIOCSPTLCK, &u) -} - -func ioctl(fd uintptr, cmd uintptr, data *int) error { - _, _, e := syscall.Syscall( - syscall.SYS_IOCTL, - fd, - cmd, - uintptr(unsafe.Pointer(data)), - ) - if e != 0 { - return syscall.ENOTTY - } - return nil + var u _C_int + // use TIOCSPTLCK with a zero valued arg to clear the slave pty lock + return ioctl(f.Fd(), ioctl_TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) } diff --git a/vendor/src/github.com/kr/pty/pty_unsupported.go b/vendor/src/github.com/kr/pty/pty_unsupported.go index d4958b3583..898c7303c4 100644 --- a/vendor/src/github.com/kr/pty/pty_unsupported.go +++ b/vendor/src/github.com/kr/pty/pty_unsupported.go @@ -9,19 +9,3 @@ import ( func open() (pty, tty *os.File, err error) { return nil, nil, ErrUnsupported } - -func ptsname(f *os.File) (string, error) { - return "", ErrUnsupported -} - -func grantpt(f *os.File) error { - return ErrUnsupported -} - -func unlockpt(f *os.File) error { - return ErrUnsupported -} - -func ioctl(fd, cmd, ptr uintptr) error { - return ErrUnsupported -} diff --git a/vendor/src/github.com/kr/pty/types.go b/vendor/src/github.com/kr/pty/types.go new file mode 100644 index 0000000000..5aecb6bcdc --- /dev/null +++ b/vendor/src/github.com/kr/pty/types.go @@ -0,0 +1,10 @@ +// +build ignore + +package pty + +import "C" + +type ( + _C_int C.int + _C_uint C.uint +) diff --git a/vendor/src/github.com/kr/pty/types_freebsd.go b/vendor/src/github.com/kr/pty/types_freebsd.go new file mode 100644 index 0000000000..ce3eb95181 --- /dev/null +++ b/vendor/src/github.com/kr/pty/types_freebsd.go @@ -0,0 +1,15 @@ +// +build ignore + +package pty + +/* +#include +#include +*/ +import "C" + +const ( + _C_SPECNAMELEN = C.SPECNAMELEN /* max length of devicename */ +) + +type fiodgnameArg C.struct_fiodgname_arg diff --git a/vendor/src/github.com/kr/pty/ztypes_386.go b/vendor/src/github.com/kr/pty/ztypes_386.go new file mode 100644 index 0000000000..ff0b8fd838 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ztypes_386.go @@ -0,0 +1,9 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/vendor/src/github.com/kr/pty/ztypes_amd64.go b/vendor/src/github.com/kr/pty/ztypes_amd64.go new file mode 100644 index 0000000000..ff0b8fd838 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ztypes_amd64.go @@ -0,0 +1,9 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/vendor/src/github.com/kr/pty/ztypes_arm.go b/vendor/src/github.com/kr/pty/ztypes_arm.go new file mode 100644 index 0000000000..ff0b8fd838 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ztypes_arm.go @@ -0,0 +1,9 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/vendor/src/github.com/kr/pty/ztypes_freebsd_386.go b/vendor/src/github.com/kr/pty/ztypes_freebsd_386.go new file mode 100644 index 0000000000..d9975374e3 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ztypes_freebsd_386.go @@ -0,0 +1,13 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Buf *byte +} diff --git a/vendor/src/github.com/kr/pty/ztypes_freebsd_amd64.go b/vendor/src/github.com/kr/pty/ztypes_freebsd_amd64.go new file mode 100644 index 0000000000..5fa102fcdf --- /dev/null +++ b/vendor/src/github.com/kr/pty/ztypes_freebsd_amd64.go @@ -0,0 +1,14 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Pad_cgo_0 [4]byte + Buf *byte +} diff --git a/vendor/src/github.com/kr/pty/ztypes_freebsd_arm.go b/vendor/src/github.com/kr/pty/ztypes_freebsd_arm.go new file mode 100644 index 0000000000..d9975374e3 --- /dev/null +++ b/vendor/src/github.com/kr/pty/ztypes_freebsd_arm.go @@ -0,0 +1,13 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Buf *byte +}