Этот коммит содержится в:
Christopher Speller
2016-11-16 19:28:52 -05:00
коммит произвёл GitHub
родитель 0b296dd8c2
Коммит 0135904f7d
445 изменённых файлов: 38624 добавлений и 14161 удалений

2
vendor/github.com/NYTimes/gziphandler/gzip.go сгенерированный поставляемый
Просмотреть файл

@@ -181,7 +181,7 @@ func GzipHandler(h http.Handler) http.Handler {
}
// acceptsGzip returns true if the given HTTP request indicates that it will
// accept a gzippped response.
// accept a gzipped response.
func acceptsGzip(r *http.Request) bool {
acceptedEncodings, _ := parseEncodings(r.Header.Get(acceptEncoding))
return acceptedEncodings["gzip"] > 0.0

8
vendor/github.com/gorilla/handlers/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -6,13 +6,13 @@ matrix:
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: tip
allow_failures:
- go: tip
install:
- go get golang.org/x/tools/cmd/vet
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go tool vet .
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...

3
vendor/github.com/gorilla/handlers/compress.go сгенерированный поставляемый
Просмотреть файл

@@ -56,6 +56,9 @@ func (w *compressResponseWriter) Flush() {
// CompressHandler gzip compresses HTTP responses for clients that support it
// via the 'Accept-Encoding' header.
//
// Compressing TLS traffic may leak the page contents to an attacker if the
// page contains user input: http://security.stackexchange.com/a/102015/12208
func CompressHandler(h http.Handler) http.Handler {
return CompressHandlerLevel(h, gzip.DefaultCompression)
}

3
vendor/github.com/gorilla/handlers/cors.go сгенерированный поставляемый
Просмотреть файл

@@ -112,6 +112,9 @@ func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set(corsAllowOriginHeader, origin)
if r.Method == corsOptionMethod {
return
}
ch.h.ServeHTTP(w, r)
}

18
vendor/github.com/gorilla/handlers/cors_test.go сгенерированный поставляемый
Просмотреть файл

@@ -104,6 +104,24 @@ func TestCORSHandlerInvalidRequestMethodForPreflightMethodNotAllowed(t *testing.
}
}
func TestCORSHandlerOptionsRequestMustNotBePassedToNextHandler(t *testing.T) {
r := newRequest("OPTIONS", "http://www.example.com/")
r.Header.Set("Origin", r.URL.String())
r.Header.Set(corsRequestMethodHeader, "GET")
rr := httptest.NewRecorder()
testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Fatal("Options request must not be passed to next handler")
})
CORS()(testHandler).ServeHTTP(rr, r)
if status := rr.Code; status != http.StatusOK {
t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
}
}
func TestCORSHandlerAllowedMethodForPreflight(t *testing.T) {
r := newRequest("OPTIONS", "http://www.example.com/")
r.Header.Set("Origin", r.URL.String())

23
vendor/github.com/gorilla/handlers/proxy_headers.go сгенерированный поставляемый
Просмотреть файл

@@ -8,9 +8,11 @@ import (
var (
// De-facto standard header keys.
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Scheme")
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host")
xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Proto")
xForwardedScheme = http.CanonicalHeaderKey("X-Forwarded-Scheme")
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
)
var (
@@ -28,9 +30,9 @@ var (
// ProxyHeaders inspects common reverse proxy headers and sets the corresponding
// fields in the HTTP request struct. These are X-Forwarded-For and X-Real-IP
// for the remote (client) IP address, X-Forwarded-Proto for the scheme
// (http|https) and the RFC7239 Forwarded header, which may include both client
// IPs and schemes.
// for the remote (client) IP address, X-Forwarded-Proto or X-Forwarded-Scheme
// for the scheme (http|https) and the RFC7239 Forwarded header, which may
// include both client IPs and schemes.
//
// NOTE: This middleware should only be used when behind a reverse
// proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are
@@ -49,7 +51,10 @@ func ProxyHeaders(h http.Handler) http.Handler {
if scheme := getScheme(r); scheme != "" {
r.URL.Scheme = scheme
}
// Set the host with the value passed by the proxy
if r.Header.Get(xForwardedHost) != "" {
r.Host = r.Header.Get(xForwardedHost)
}
// Call the next handler in the chain.
h.ServeHTTP(w, r)
}
@@ -99,7 +104,9 @@ func getScheme(r *http.Request) string {
// Retrieve the scheme from X-Forwarded-Proto.
if proto := r.Header.Get(xForwardedProto); proto != "" {
scheme = strings.ToLower(proto)
} else if proto := r.Header.Get(forwarded); proto != "" {
} else if proto = r.Header.Get(xForwardedScheme); proto != "" {
scheme = strings.ToLower(proto)
} else if proto = r.Header.Get(forwarded); proto != "" {
// match should contain at least two elements if the protocol was
// specified in the Forwarded header. The first element will always be
// the 'proto=' capture, which we ignore. In the case of multiple proto

17
vendor/github.com/gorilla/handlers/proxy_headers_test.go сгенерированный поставляемый
Просмотреть файл

@@ -47,6 +47,9 @@ func TestGetScheme(t *testing.T) {
{xForwardedProto, "https", "https"},
{xForwardedProto, "http", "http"},
{xForwardedProto, "HTTP", "http"},
{xForwardedScheme, "https", "https"},
{xForwardedScheme, "http", "http"},
{xForwardedScheme, "HTTP", "http"},
{forwarded, `For="[2001:db8:cafe::17]:4711`, ""}, // No proto
{forwarded, `for=192.0.2.43, for=198.51.100.17;proto=https`, "https"}, // Multiple params before proto
{forwarded, `for=172.32.10.15; proto=https;by=127.0.0.1`, "https"}, // Space before proto
@@ -74,13 +77,17 @@ func TestProxyHeaders(t *testing.T) {
r.Header.Set(xForwardedFor, "8.8.8.8")
r.Header.Set(xForwardedProto, "https")
var addr string
var proto string
r.Header.Set(xForwardedHost, "google.com")
var (
addr string
proto string
host string
)
ProxyHeaders(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
addr = r.RemoteAddr
proto = r.URL.Scheme
host = r.Host
})).ServeHTTP(rr, r)
if rr.Code != http.StatusOK {
@@ -96,5 +103,9 @@ func TestProxyHeaders(t *testing.T) {
t.Fatalf("wrong address: got %s want %s", proto,
r.Header.Get(xForwardedProto))
}
if host != r.Header.Get(xForwardedHost) {
t.Fatalf("wrong address: got %s want %s", host,
r.Header.Get(xForwardedHost))
}
}

3
vendor/github.com/gorilla/mux/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -8,10 +8,11 @@ matrix:
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: tip
install:
- go get golang.org/x/tools/cmd/vet
- # Skip
script:
- go get -t -v ./...

69
vendor/github.com/gorilla/mux/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,19 +1,43 @@
mux
gorilla/mux
===
[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
http://www.gorillatoolkit.org/pkg/mux
Package `gorilla/mux` implements a request router and dispatcher.
Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
their respective handler.
The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
* URL hosts and paths can have variables with an optional regular expression.
* Registered URLs can be built, or "reversed", which helps maintaining references to resources.
* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
---
* [Install](#install)
* [Examples](#examples)
* [Matching Routes](#matching-routes)
* [Static Files](#static-files)
* [Registered URLs](#registered-urls)
* [Full Example](#full-example)
---
## Install
With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:
```sh
go get -u github.com/gorilla/mux
```
## Examples
Let's start registering a couple of URL paths and handlers:
@@ -47,6 +71,8 @@ category := vars["category"]
And this is all you need to know about the basic usage. More advanced options are explained below.
### Matching Routes
Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
```go
@@ -118,7 +144,7 @@ Then register routes in the subrouter:
```go
s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
```
The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
@@ -138,6 +164,37 @@ s.HandleFunc("/{key}/", ProductHandler)
s.HandleFunc("/{key}/details", ProductDetailsHandler)
```
### Static Files
Note that the path provided to `PathPrefix()` represents a "wildcard": calling
`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
request that matches "/static/*". This makes it easy to serve static files with mux:
```go
func main() {
var dir string
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
flag.Parse()
r := mux.NewRouter()
// This will serve files under http://localhost:8000/static/<filename>
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
srv := &http.Server{
Handler: r,
Addr: "127.0.0.1:8000",
// Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}
```
### Registered URLs
Now let's see how to build registered URLs.
Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
@@ -219,7 +276,7 @@ package main
import (
"net/http"
"log"
"github.com/gorilla/mux"
)
@@ -233,7 +290,7 @@ func main() {
r.HandleFunc("/", YourHandler)
// Bind to a port and pass our router in
http.ListenAndServe(":8000", r)
log.Fatal(http.ListenAndServe(":8000", r))
}
```

26
vendor/github.com/gorilla/mux/context_gorilla.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,26 @@
// +build !go1.7
package mux
import (
"net/http"
"github.com/gorilla/context"
)
func contextGet(r *http.Request, key interface{}) interface{} {
return context.Get(r, key)
}
func contextSet(r *http.Request, key, val interface{}) *http.Request {
if val == nil {
return r
}
context.Set(r, key, val)
return r
}
func contextClear(r *http.Request) {
context.Clear(r)
}

40
vendor/github.com/gorilla/mux/context_gorilla_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,40 @@
// +build !go1.7
package mux
import (
"net/http"
"testing"
"github.com/gorilla/context"
)
// 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")
}
}

24
vendor/github.com/gorilla/mux/context_native.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,24 @@
// +build go1.7
package mux
import (
"context"
"net/http"
)
func contextGet(r *http.Request, key interface{}) interface{} {
return r.Context().Value(key)
}
func contextSet(r *http.Request, key, val interface{}) *http.Request {
if val == nil {
return r
}
return r.WithContext(context.WithValue(r.Context(), key, val))
}
func contextClear(r *http.Request) {
return
}

32
vendor/github.com/gorilla/mux/context_native_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,32 @@
// +build go1.7
package mux
import (
"context"
"net/http"
"testing"
"time"
)
func TestNativeContextMiddleware(t *testing.T) {
withTimeout := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
defer cancel()
h.ServeHTTP(w, r.WithContext(ctx))
})
}
r := NewRouter()
r.Handle("/path/{foo}", withTimeout(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := Vars(r)
if vars["foo"] != "bar" {
t.Fatal("Expected foo var to be set")
}
})))
rec := NewRecorder()
req := newRequest("GET", "/path/bar")
r.ServeHTTP(rec, req)
}

29
vendor/github.com/gorilla/mux/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -47,6 +47,10 @@ variable will be anything until the next slash. For example:
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
The names are used to create a map of route variables which can be retrieved
calling mux.Vars():
@@ -136,6 +140,31 @@ the inner routes use it as base for their paths:
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)
Note that the path provided to PathPrefix() represents a "wildcard": calling
PathPrefix("/static/").Handler(...) means that the handler will be passed any
request that matches "/static/*". This makes it easy to serve static files with mux:
func main() {
var dir string
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
flag.Parse()
r := mux.NewRouter()
// This will serve files under http://localhost:8000/static/<filename>
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
srv := &http.Server{
Handler: r,
Addr: "127.0.0.1:8000",
// Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}
Now let's see how to build registered URLs.
Routes can be named. All routes that define a name can have their URLs built,

117
vendor/github.com/gorilla/mux/mux.go сгенерированный поставляемый
Просмотреть файл

@@ -10,8 +10,7 @@ import (
"net/http"
"path"
"regexp"
"github.com/gorilla/context"
"strings"
)
// NewRouter returns a new router instance.
@@ -48,8 +47,14 @@ 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
// See Router.SkipClean(). This defines the flag for new routes.
skipClean bool
// If true, do not clear the request context after handling the request.
// This has no effect when go1.7+ is used, since the context is stored
// on the request itself.
KeepContext bool
// see Router.UseEncodedPath(). This defines a flag for all routes.
useEncodedPath bool
}
// Match matches registered routes against the request.
@@ -73,32 +78,38 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
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 {
if !r.skipClean {
path := req.URL.Path
if r.useEncodedPath {
path = getPath(req)
}
// Clean path to canonical form and redirect.
if p := cleanPath(path); p != path {
// Added 3 lines (Philip Schlump) - It was dropping 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()
// Added 3 lines (Philip Schlump) - It was dropping 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
w.Header().Set("Location", p)
w.WriteHeader(http.StatusMovedPermanently)
return
}
}
var match RouteMatch
var handler http.Handler
if r.Match(req, &match) {
handler = match.Handler
setVars(req, match.Vars)
setCurrentRoute(req, match.Route)
req = setVars(req, match.Vars)
req = setCurrentRoute(req, match.Route)
}
if handler == nil {
handler = http.NotFoundHandler()
}
if !r.KeepContext {
defer context.Clear(req)
defer contextClear(req)
}
handler.ServeHTTP(w, req)
}
@@ -133,6 +144,34 @@ func (r *Router) StrictSlash(value bool) *Router {
return r
}
// SkipClean defines the path cleaning behaviour for new routes. The initial
// value is false. Users should be careful about which routes are not cleaned
//
// When true, if the route path is "/path//to", it will remain with the double
// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
//
// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
// become /fetch/http/xkcd.com/534
func (r *Router) SkipClean(value bool) *Router {
r.skipClean = value
return r
}
// UseEncodedPath tells the router to match the encoded original path
// to the routes.
// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
// This behavior has the drawback of needing to match routes against
// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix)
// to r.URL.Path will not affect routing when this flag is on and thus may
// induce unintended behavior.
//
// If not called, the router will match the unencoded path to the routes.
// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
func (r *Router) UseEncodedPath() *Router {
r.useEncodedPath = true
return r
}
// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------
@@ -170,7 +209,7 @@ func (r *Router) buildVars(m map[string]string) map[string]string {
// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
route := &Route{parent: r, strictSlash: r.strictSlash}
route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
r.routes = append(r.routes, route)
return route
}
@@ -268,6 +307,9 @@ func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
if err == SkipRouter {
continue
}
if err != nil {
return err
}
for _, sr := range t.matchers {
if h, ok := sr.(*Router); ok {
err := h.walk(walkFn, ancestors)
@@ -308,7 +350,7 @@ const (
// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
if rv := context.Get(r, varsKey); rv != nil {
if rv := contextGet(r, varsKey); rv != nil {
return rv.(map[string]string)
}
return nil
@@ -320,28 +362,46 @@ func Vars(r *http.Request) map[string]string {
// after the handler returns, unless the KeepContext option is set on the
// Router.
func CurrentRoute(r *http.Request) *Route {
if rv := context.Get(r, routeKey); rv != nil {
if rv := contextGet(r, routeKey); rv != nil {
return rv.(*Route)
}
return nil
}
func setVars(r *http.Request, val interface{}) {
if val != nil {
context.Set(r, varsKey, val)
}
func setVars(r *http.Request, val interface{}) *http.Request {
return contextSet(r, varsKey, val)
}
func setCurrentRoute(r *http.Request, val interface{}) {
if val != nil {
context.Set(r, routeKey, val)
}
func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
return contextSet(r, routeKey, val)
}
// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------
// getPath returns the escaped path if possible; doing what URL.EscapedPath()
// which was added in go1.5 does
func getPath(req *http.Request) string {
if req.RequestURI != "" {
// Extract the path from RequestURI (which is escaped unlike URL.Path)
// as detailed here as detailed in https://golang.org/pkg/net/url/#URL
// for < 1.5 server side workaround
// http://localhost/path/here?v=1 -> /path/here
path := req.RequestURI
path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
path = strings.TrimPrefix(path, req.URL.Host)
if i := strings.LastIndex(path, "?"); i > -1 {
path = path[:i]
}
if i := strings.LastIndex(path, "#"); i > -1 {
path = path[:i]
}
return path
}
return req.URL.Path
}
// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
@@ -357,6 +417,7 @@ func cleanPath(p string) string {
if p[len(p)-1] == '/' && np != "/" {
np += "/"
}
return np
}

888
vendor/github.com/gorilla/mux/mux_test.go сгенерированный поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

2
vendor/github.com/gorilla/mux/old_test.go сгенерированный поставляемый
Просмотреть файл

@@ -687,7 +687,7 @@ func TestNewRegexp(t *testing.T) {
}
for pattern, paths := range tests {
p, _ = newRouteRegexp(pattern, false, false, false, false)
p, _ = newRouteRegexp(pattern, false, false, false, false, false)
for path, result := range paths {
matches = p.regexp.FindStringSubmatch(path)
if result == nil {

50
vendor/github.com/gorilla/mux/regexp.go сгенерированный поставляемый
Просмотреть файл

@@ -24,7 +24,7 @@ import (
// Previously we accepted only Python-like identifiers for variable
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
// name and pattern can't be empty, and names can't contain a colon.
func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash bool) (*routeRegexp, error) {
func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) {
// Check if it is well-formed.
idxs, errBraces := braceIndices(tpl)
if errBraces != nil {
@@ -111,14 +111,15 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
}
// Done!
return &routeRegexp{
template: template,
matchHost: matchHost,
matchQuery: matchQuery,
strictSlash: strictSlash,
regexp: reg,
reverse: reverse.String(),
varsN: varsN,
varsR: varsR,
template: template,
matchHost: matchHost,
matchQuery: matchQuery,
strictSlash: strictSlash,
useEncodedPath: useEncodedPath,
regexp: reg,
reverse: reverse.String(),
varsN: varsN,
varsR: varsR,
}, nil
}
@@ -133,6 +134,9 @@ type routeRegexp struct {
matchQuery bool
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
strictSlash bool
// Determines whether to use encoded path from getPath function or unencoded
// req.URL.Path for path matching
useEncodedPath bool
// Expanded regexp.
regexp *regexp.Regexp
// Reverse template.
@@ -149,8 +153,11 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
if r.matchQuery {
return r.matchQueryString(req)
}
return r.regexp.MatchString(req.URL.Path)
path := req.URL.Path
if r.useEncodedPath {
path = getPath(req)
}
return r.regexp.MatchString(path)
}
return r.regexp.MatchString(getHost(req))
@@ -253,14 +260,18 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
extractVars(host, matches, v.host.varsN, m.Vars)
}
}
path := req.URL.Path
if r.useEncodedPath {
path = getPath(req)
}
// Store path variables.
if v.path != nil {
matches := v.path.regexp.FindStringSubmatchIndex(req.URL.Path)
matches := v.path.regexp.FindStringSubmatchIndex(path)
if len(matches) > 0 {
extractVars(req.URL.Path, matches, v.path.varsN, m.Vars)
extractVars(path, matches, v.path.varsN, m.Vars)
// Check if we should redirect.
if v.path.strictSlash {
p1 := strings.HasSuffix(req.URL.Path, "/")
p1 := strings.HasSuffix(path, "/")
p2 := strings.HasSuffix(v.path.template, "/")
if p1 != p2 {
u, _ := url.Parse(req.URL.String())
@@ -299,14 +310,7 @@ func getHost(r *http.Request) string {
}
func extractVars(input string, matches []int, names []string, output map[string]string) {
matchesCount := 0
prevEnd := -1
for i := 2; i < len(matches) && matchesCount < len(names); i += 2 {
if prevEnd < matches[i+1] {
value := input[matches[i]:matches[i+1]]
output[names[matchesCount]] = value
prevEnd = matches[i+1]
matchesCount++
}
for i, name := range names {
output[name] = input[matches[2*i+2]:matches[2*i+3]]
}
}

11
vendor/github.com/gorilla/mux/route.go сгенерированный поставляемый
Просмотреть файл

@@ -26,6 +26,11 @@ type Route struct {
// If true, when the path pattern is "/path/", accessing "/path" will
// redirect to the former and vice versa.
strictSlash bool
// If true, when the path pattern is "/path//to", accessing "/path//to"
// will not redirect
skipClean bool
// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
useEncodedPath bool
// If true, this route never matches: it is only used to build URLs.
buildOnly bool
// The name used to build URLs.
@@ -36,6 +41,10 @@ type Route struct {
buildVarsFunc BuildVarsFunc
}
func (r *Route) SkipClean() bool {
return r.skipClean
}
// Match matches the route against the request.
func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
if r.buildOnly || r.err != nil {
@@ -151,7 +160,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
}
}
rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash)
rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath)
if err != nil {
return err
}

3
vendor/github.com/gorilla/websocket/.gitignore сгенерированный поставляемый
Просмотреть файл

@@ -20,3 +20,6 @@ _cgo_export.*
_testmain.go
*.exe
.idea/
*.iml

1
vendor/github.com/gorilla/websocket/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -6,6 +6,7 @@ matrix:
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: tip
allow_failures:
- go: tip

5
vendor/github.com/gorilla/websocket/README.md сгенерированный поставляемый
Просмотреть файл

@@ -3,6 +3,9 @@
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket)
[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
### Documentation
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
@@ -43,7 +46,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
<tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr>
<tr><td colspan="3">Other Features</tr></td>
<tr><td>Limit size of received message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.SetReadLimit">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=5082">No</a></td></tr>
<tr><td><a href="https://tools.ietf.org/html/rfc7692">Compression Extensions</a></td><td>Experimental</td><td>No</td></tr>
<tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr>
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
</table>

19
vendor/github.com/gorilla/websocket/bench_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,19 +0,0 @@
// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"testing"
)
func BenchmarkMaskBytes(b *testing.B) {
var key [4]byte
data := make([]byte, 1024)
pos := 0
for i := 0; i < b.N; i++ {
pos = maskBytes(key, pos, data)
}
b.SetBytes(int64(len(data)))
}

47
vendor/github.com/gorilla/websocket/client.go сгенерированный поставляемый
Просмотреть файл

@@ -23,6 +23,8 @@ import (
// invalid.
var ErrBadHandshake = errors.New("websocket: bad handshake")
var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
// NewClient creates a new client connection using the given net connection.
// The URL u specifies the host and request URI. Use requestHeader to specify
// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
@@ -70,6 +72,17 @@ type Dialer struct {
// Subprotocols specifies the client's requested subprotocols.
Subprotocols []string
// EnableCompression specifies if the client should attempt to negotiate
// per message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
EnableCompression bool
// Jar specifies the cookie jar.
// If Jar is nil, cookies are not sent in requests and ignored
// in responses.
Jar http.CookieJar
}
var errMalformedURL = errors.New("malformed ws or wss URL")
@@ -83,7 +96,6 @@ func parseURL(s string) (*url.URL, error) {
//
// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
var u url.URL
switch {
case strings.HasPrefix(s, "ws://"):
@@ -193,6 +205,13 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
Host: u.Host,
}
// Set the cookies present in the cookie jar of the dialer
if d.Jar != nil {
for _, cookie := range d.Jar.Cookies(u) {
req.AddCookie(cookie)
}
}
// Set the request headers using the capitalization for names and values in
// RFC examples. Although the capitalization shouldn't matter, there are
// servers that depend on it. The Header.Set method is not used because the
@@ -214,6 +233,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
k == "Connection" ||
k == "Sec-Websocket-Key" ||
k == "Sec-Websocket-Version" ||
k == "Sec-Websocket-Extensions" ||
(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
default:
@@ -221,6 +241,10 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
}
}
if d.EnableCompression {
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
}
hostPort, hostNoPort := hostPortNoPort(u)
var proxyURL *url.URL
@@ -324,6 +348,13 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
if err != nil {
return nil, nil, err
}
if d.Jar != nil {
if rc := resp.Cookies(); len(rc) > 0 {
d.Jar.SetCookies(u, rc)
}
}
if resp.StatusCode != 101 ||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
@@ -337,6 +368,20 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
return nil, resp, ErrBadHandshake
}
for _, ext := range parseExtensions(req.Header) {
if ext[""] != "permessage-deflate" {
continue
}
_, snct := ext["server_no_context_takeover"]
_, cnct := ext["client_no_context_takeover"]
if !snct || !cnct {
return nil, resp, errInvalidCompression
}
conn.newCompressionWriter = compressNoContextTakeover
conn.newDecompressionReader = decompressNoContextTakeover
break
}
resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")

77
vendor/github.com/gorilla/websocket/client_server_test.go сгенерированный поставляемый
Просмотреть файл

@@ -10,8 +10,8 @@ import (
"encoding/base64"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/cookiejar"
"net/http/httptest"
"net/url"
"reflect"
@@ -21,9 +21,10 @@ import (
)
var cstUpgrader = Upgrader{
Subprotocols: []string{"p0", "p1"},
ReadBufferSize: 1024,
WriteBufferSize: 1024,
Subprotocols: []string{"p0", "p1"},
ReadBufferSize: 1024,
WriteBufferSize: 1024,
EnableCompression: true,
Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) {
http.Error(w, reason.Error(), status)
},
@@ -228,6 +229,54 @@ func TestDial(t *testing.T) {
sendRecv(t, ws)
}
func TestDialCookieJar(t *testing.T) {
s := newServer(t)
defer s.Close()
jar, _ := cookiejar.New(nil)
d := cstDialer
d.Jar = jar
u, _ := parseURL(s.URL)
switch u.Scheme {
case "ws":
u.Scheme = "http"
case "wss":
u.Scheme = "https"
}
cookies := []*http.Cookie{&http.Cookie{Name: "gorilla", Value: "ws", Path: "/"}}
d.Jar.SetCookies(u, cookies)
ws, _, err := d.Dial(s.URL, nil)
if err != nil {
t.Fatalf("Dial: %v", err)
}
defer ws.Close()
var gorilla string
var sessionID string
for _, c := range d.Jar.Cookies(u) {
if c.Name == "gorilla" {
gorilla = c.Value
}
if c.Name == "sessionID" {
sessionID = c.Value
}
}
if gorilla != "ws" {
t.Error("Cookie not present in jar.")
}
if sessionID != "1234" {
t.Error("Set-Cookie not received from the server.")
}
sendRecv(t, ws)
}
func TestDialTLS(t *testing.T) {
s := newTLSServer(t)
defer s.Close()
@@ -243,11 +292,9 @@ func TestDialTLS(t *testing.T) {
}
}
u, _ := url.Parse(s.URL)
d := cstDialer
d.NetDial = func(network, addr string) (net.Conn, error) { return net.Dial(network, u.Host) }
d.TLSClientConfig = &tls.Config{RootCAs: certs}
ws, _, err := d.Dial("wss://example.com"+cstRequestURI, nil)
ws, _, err := d.Dial(s.URL, nil)
if err != nil {
t.Fatalf("Dial: %v", err)
}
@@ -267,7 +314,7 @@ func xTestDialTLSBadCert(t *testing.T) {
}
}
func xTestDialTLSNoVerify(t *testing.T) {
func TestDialTLSNoVerify(t *testing.T) {
s := newTLSServer(t)
defer s.Close()
@@ -449,3 +496,17 @@ func TestHostHeader(t *testing.T) {
sendRecv(t, ws)
}
func TestDialCompression(t *testing.T) {
s := newServer(t)
defer s.Close()
dialer := cstDialer
dialer.EnableCompression = true
ws, _, err := dialer.Dial(s.URL, nil)
if err != nil {
t.Fatalf("Dial: %v", err)
}
defer ws.Close()
sendRecv(t, ws)
}

85
vendor/github.com/gorilla/websocket/compression.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,85 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"compress/flate"
"errors"
"io"
"strings"
)
func decompressNoContextTakeover(r io.Reader) io.Reader {
const tail =
// Add four bytes as specified in RFC
"\x00\x00\xff\xff" +
// Add final block to squelch unexpected EOF error from flate reader.
"\x01\x00\x00\xff\xff"
return flate.NewReader(io.MultiReader(r, strings.NewReader(tail)))
}
func compressNoContextTakeover(w io.WriteCloser) (io.WriteCloser, error) {
tw := &truncWriter{w: w}
fw, err := flate.NewWriter(tw, 3)
return &flateWrapper{fw: fw, tw: tw}, err
}
// truncWriter is an io.Writer that writes all but the last four bytes of the
// stream to another io.Writer.
type truncWriter struct {
w io.WriteCloser
n int
p [4]byte
}
func (w *truncWriter) Write(p []byte) (int, error) {
n := 0
// fill buffer first for simplicity.
if w.n < len(w.p) {
n = copy(w.p[w.n:], p)
p = p[n:]
w.n += n
if len(p) == 0 {
return n, nil
}
}
m := len(p)
if m > len(w.p) {
m = len(w.p)
}
if nn, err := w.w.Write(w.p[:m]); err != nil {
return n + nn, err
}
copy(w.p[:], w.p[m:])
copy(w.p[len(w.p)-m:], p[len(p)-m:])
nn, err := w.w.Write(p[:len(p)-m])
return n + nn, err
}
type flateWrapper struct {
fw *flate.Writer
tw *truncWriter
}
func (w *flateWrapper) Write(p []byte) (int, error) {
return w.fw.Write(p)
}
func (w *flateWrapper) Close() error {
err1 := w.fw.Flush()
if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
}
err2 := w.tw.w.Close()
if err1 != nil {
return err1
}
return err2
}

31
vendor/github.com/gorilla/websocket/compression_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,31 @@
package websocket
import (
"bytes"
"io"
"testing"
)
type nopCloser struct{ io.Writer }
func (nopCloser) Close() error { return nil }
func TestTruncWriter(t *testing.T) {
const data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijlkmnopqrstuvwxyz987654321"
for n := 1; n <= 10; n++ {
var b bytes.Buffer
w := &truncWriter{w: nopCloser{&b}}
p := []byte(data)
for len(p) > 0 {
m := len(p)
if m > n {
m = n
}
w.Write(p[:m])
p = p[m:]
}
if b.String() != data[:len(data)-len(w.p)] {
t.Errorf("%d: %q", n, b.String())
}
}
}

489
vendor/github.com/gorilla/websocket/conn.go сгенерированный поставляемый
Просмотреть файл

@@ -10,19 +10,27 @@ import (
"errors"
"io"
"io/ioutil"
"math/rand"
"net"
"strconv"
"sync"
"time"
"unicode/utf8"
)
const (
// Frame header byte 0 bits from Section 5.2 of RFC 6455
finalBit = 1 << 7
rsv1Bit = 1 << 6
rsv2Bit = 1 << 5
rsv3Bit = 1 << 4
// Frame header byte 1 bits from Section 5.2 of RFC 6455
maskBit = 1 << 7
maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
maxControlFramePayloadSize = 125
finalBit = 1 << 7
maskBit = 1 << 7
writeWait = time.Second
writeWait = time.Second
defaultReadBufferSize = 4096
defaultWriteBufferSize = 4096
@@ -210,51 +218,41 @@ func isValidReceivedCloseCode(code int) bool {
return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
}
func maskBytes(key [4]byte, pos int, b []byte) int {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
func newMaskKey() [4]byte {
n := rand.Uint32()
return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
}
// Conn represents a WebSocket connection.
type Conn struct {
conn net.Conn
isServer bool
subprotocol string
// Write fields
mu chan bool // used as mutex to protect write to conn and closeSent
closeSent bool // true if close message was sent
mu chan bool // used as mutex to protect write to conn
writeBuf []byte // frame is constructed in this buffer.
writeDeadline time.Time
writer io.WriteCloser // the current writer returned to the application
isWriting bool // for best-effort concurrent write detection
// Message writer fields.
writeErr error
writeBuf []byte // frame is constructed in this buffer.
writePos int // end of data in writeBuf.
writeFrameType int // type of the current frame.
writeSeq int // incremented to invalidate message writers.
writeDeadline time.Time
isWriting bool // for best-effort concurrent write detection
writeErrMu sync.Mutex
writeErr error
enableWriteCompression bool
newCompressionWriter func(io.WriteCloser) (io.WriteCloser, error)
// Read fields
readErr error
br *bufio.Reader
readRemaining int64 // bytes remaining in current frame.
readFinal bool // true the current message has more frames.
readSeq int // incremented to invalidate message readers.
readLength int64 // Message size.
readLimit int64 // Maximum message size.
readMaskPos int
readMaskKey [4]byte
handlePong func(string) error
handlePing func(string) error
handleClose func(int, string) error
readErrCount int
messageReader *messageReader // the current low-level reader
readDecompress bool // whether last read frame had RSV1 set
newDecompressionReader func(io.Reader) io.Reader
}
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
@@ -264,20 +262,23 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int)
if readBufferSize == 0 {
readBufferSize = defaultReadBufferSize
}
if readBufferSize < maxControlFramePayloadSize {
readBufferSize = maxControlFramePayloadSize
}
if writeBufferSize == 0 {
writeBufferSize = defaultWriteBufferSize
}
c := &Conn{
isServer: isServer,
br: bufio.NewReaderSize(conn, readBufferSize),
conn: conn,
mu: mu,
readFinal: true,
writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
writeFrameType: noFrame,
writePos: maxFrameHeaderSize,
isServer: isServer,
br: bufio.NewReaderSize(conn, readBufferSize),
conn: conn,
mu: mu,
readFinal: true,
writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
enableWriteCompression: true,
}
c.SetCloseHandler(nil)
c.SetPingHandler(nil)
c.SetPongHandler(nil)
return c
@@ -305,29 +306,40 @@ func (c *Conn) RemoteAddr() net.Addr {
// Write methods
func (c *Conn) writeFatal(err error) error {
err = hideTempErr(err)
c.writeErrMu.Lock()
if c.writeErr == nil {
c.writeErr = err
}
c.writeErrMu.Unlock()
return err
}
func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error {
<-c.mu
defer func() { c.mu <- true }()
if c.closeSent {
return ErrCloseSent
} else if frameType == CloseMessage {
c.closeSent = true
c.writeErrMu.Lock()
err := c.writeErr
c.writeErrMu.Unlock()
if err != nil {
return err
}
c.conn.SetWriteDeadline(deadline)
for _, buf := range bufs {
if len(buf) > 0 {
n, err := c.conn.Write(buf)
if n != len(buf) {
// Close on partial write.
c.conn.Close()
}
_, err := c.conn.Write(buf)
if err != nil {
return err
return c.writeFatal(err)
}
}
}
if frameType == CloseMessage {
c.writeFatal(ErrCloseSent)
}
return nil
}
@@ -376,60 +388,104 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
}
defer func() { c.mu <- true }()
if c.closeSent {
return ErrCloseSent
} else if messageType == CloseMessage {
c.closeSent = true
c.writeErrMu.Lock()
err := c.writeErr
c.writeErrMu.Unlock()
if err != nil {
return err
}
c.conn.SetWriteDeadline(deadline)
n, err := c.conn.Write(buf)
if n != 0 && n != len(buf) {
c.conn.Close()
_, err = c.conn.Write(buf)
if err != nil {
return c.writeFatal(err)
}
return hideTempErr(err)
if messageType == CloseMessage {
c.writeFatal(ErrCloseSent)
}
return err
}
// NextWriter returns a writer for the next message to send. The writer's
// Close method flushes the complete message to the network.
// NextWriter returns a writer for the next message to send. The writer's Close
// method flushes the complete message to the network.
//
// There can be at most one open writer on a connection. NextWriter closes the
// previous writer if the application has not already done so.
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
if c.writeErr != nil {
return nil, c.writeErr
}
if c.writeFrameType != noFrame {
if err := c.flushFrame(true, nil); err != nil {
return nil, err
}
// Close previous writer if not already closed by the application. It's
// probably better to return an error in this situation, but we cannot
// change this without breaking existing applications.
if c.writer != nil {
c.writer.Close()
c.writer = nil
}
if !isControl(messageType) && !isData(messageType) {
return nil, errBadWriteOpCode
}
c.writeFrameType = messageType
return messageWriter{c, c.writeSeq}, nil
}
func (c *Conn) flushFrame(final bool, extra []byte) error {
length := c.writePos - maxFrameHeaderSize + len(extra)
// Check for invalid control frames.
if isControl(c.writeFrameType) &&
(!final || length > maxControlFramePayloadSize) {
c.writeSeq++
c.writeFrameType = noFrame
c.writePos = maxFrameHeaderSize
return errInvalidControlFrame
c.writeErrMu.Lock()
err := c.writeErr
c.writeErrMu.Unlock()
if err != nil {
return nil, err
}
b0 := byte(c.writeFrameType)
mw := &messageWriter{
c: c,
frameType: messageType,
pos: maxFrameHeaderSize,
}
c.writer = mw
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
w, err := c.newCompressionWriter(c.writer)
if err != nil {
c.writer = nil
return nil, err
}
mw.compress = true
c.writer = w
}
return c.writer, nil
}
type messageWriter struct {
c *Conn
compress bool // whether next call to flushFrame should set RSV1
pos int // end of data in writeBuf.
frameType int // type of the current frame.
err error
}
func (w *messageWriter) fatal(err error) error {
if w.err != nil {
w.err = err
w.c.writer = nil
}
return err
}
// flushFrame writes buffered data and extra as a frame to the network. The
// final argument indicates that this is the last frame in the message.
func (w *messageWriter) flushFrame(final bool, extra []byte) error {
c := w.c
length := w.pos - maxFrameHeaderSize + len(extra)
// Check for invalid control frames.
if isControl(w.frameType) &&
(!final || length > maxControlFramePayloadSize) {
return w.fatal(errInvalidControlFrame)
}
b0 := byte(w.frameType)
if final {
b0 |= finalBit
}
if w.compress {
b0 |= rsv1Bit
}
w.compress = false
b1 := byte(0)
if !c.isServer {
b1 |= maskBit
@@ -461,10 +517,9 @@ func (c *Conn) flushFrame(final bool, extra []byte) error {
if !c.isServer {
key := newMaskKey()
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:c.writePos])
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
if len(extra) > 0 {
c.writeErr = errors.New("websocket: internal error, extra used in client mode")
return c.writeErr
return c.writeFatal(errors.New("websocket: internal error, extra used in client mode"))
}
}
@@ -477,46 +532,35 @@ func (c *Conn) flushFrame(final bool, extra []byte) error {
}
c.isWriting = true
c.writeErr = c.write(c.writeFrameType, c.writeDeadline, c.writeBuf[framePos:c.writePos], extra)
err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra)
if !c.isWriting {
panic("concurrent write to websocket connection")
}
c.isWriting = false
// Setup for next frame.
c.writePos = maxFrameHeaderSize
c.writeFrameType = continuationFrame
if err != nil {
return w.fatal(err)
}
if final {
c.writeSeq++
c.writeFrameType = noFrame
c.writer = nil
return nil
}
return c.writeErr
}
type messageWriter struct {
c *Conn
seq int
}
func (w messageWriter) err() error {
c := w.c
if c.writeSeq != w.seq {
return errWriteClosed
}
if c.writeErr != nil {
return c.writeErr
}
// Setup for next frame.
w.pos = maxFrameHeaderSize
w.frameType = continuationFrame
return nil
}
func (w messageWriter) ncopy(max int) (int, error) {
n := len(w.c.writeBuf) - w.c.writePos
func (w *messageWriter) ncopy(max int) (int, error) {
n := len(w.c.writeBuf) - w.pos
if n <= 0 {
if err := w.c.flushFrame(false, nil); err != nil {
if err := w.flushFrame(false, nil); err != nil {
return 0, err
}
n = len(w.c.writeBuf) - w.c.writePos
n = len(w.c.writeBuf) - w.pos
}
if n > max {
n = max
@@ -524,14 +568,14 @@ func (w messageWriter) ncopy(max int) (int, error) {
return n, nil
}
func (w messageWriter) write(final bool, p []byte) (int, error) {
if err := w.err(); err != nil {
return 0, err
func (w *messageWriter) Write(p []byte) (int, error) {
if w.err != nil {
return 0, w.err
}
if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
// Don't buffer large messages.
err := w.c.flushFrame(final, p)
err := w.flushFrame(false, p)
if err != nil {
return 0, err
}
@@ -544,20 +588,16 @@ func (w messageWriter) write(final bool, p []byte) (int, error) {
if err != nil {
return 0, err
}
copy(w.c.writeBuf[w.c.writePos:], p[:n])
w.c.writePos += n
copy(w.c.writeBuf[w.pos:], p[:n])
w.pos += n
p = p[n:]
}
return nn, nil
}
func (w messageWriter) Write(p []byte) (int, error) {
return w.write(false, p)
}
func (w messageWriter) WriteString(p string) (int, error) {
if err := w.err(); err != nil {
return 0, err
func (w *messageWriter) WriteString(p string) (int, error) {
if w.err != nil {
return 0, w.err
}
nn := len(p)
@@ -566,27 +606,27 @@ func (w messageWriter) WriteString(p string) (int, error) {
if err != nil {
return 0, err
}
copy(w.c.writeBuf[w.c.writePos:], p[:n])
w.c.writePos += n
copy(w.c.writeBuf[w.pos:], p[:n])
w.pos += n
p = p[n:]
}
return nn, nil
}
func (w messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
if err := w.err(); err != nil {
return 0, err
func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
if w.err != nil {
return 0, w.err
}
for {
if w.c.writePos == len(w.c.writeBuf) {
err = w.c.flushFrame(false, nil)
if w.pos == len(w.c.writeBuf) {
err = w.flushFrame(false, nil)
if err != nil {
break
}
}
var n int
n, err = r.Read(w.c.writeBuf[w.c.writePos:])
w.c.writePos += n
n, err = r.Read(w.c.writeBuf[w.pos:])
w.pos += n
nn += int64(n)
if err != nil {
if err == io.EOF {
@@ -598,30 +638,36 @@ func (w messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
return nn, err
}
func (w messageWriter) Close() error {
if err := w.err(); err != nil {
func (w *messageWriter) Close() error {
if w.err != nil {
return w.err
}
if err := w.flushFrame(true, nil); err != nil {
return err
}
return w.c.flushFrame(true, nil)
w.err = errWriteClosed
return nil
}
// WriteMessage is a helper method for getting a writer using NextWriter,
// writing the message and closing the writer.
func (c *Conn) WriteMessage(messageType int, data []byte) error {
wr, err := c.NextWriter(messageType)
w, err := c.NextWriter(messageType)
if err != nil {
return err
}
w := wr.(messageWriter)
if _, err := w.write(true, data); err != nil {
if mw, ok := w.(*messageWriter); ok && c.isServer {
// Optimize write as a single frame.
n := copy(c.writeBuf[mw.pos:], data)
mw.pos += n
data = data[n:]
err = mw.flushFrame(true, data)
return err
}
if c.writeSeq == w.seq {
if err := c.flushFrame(true, nil); err != nil {
return err
}
if _, err = w.Write(data); err != nil {
return err
}
return nil
return w.Close()
}
// SetWriteDeadline sets the write deadline on the underlying network
@@ -635,22 +681,6 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
// Read methods
// readFull is like io.ReadFull except that io.EOF is never returned.
func (c *Conn) readFull(p []byte) (err error) {
var n int
for n < len(p) && err == nil {
var nn int
nn, err = c.br.Read(p[n:])
n += nn
}
if n == len(p) {
err = nil
} else if err == io.EOF {
err = errUnexpectedEOF
}
return
}
func (c *Conn) advanceFrame() (int, error) {
// 1. Skip remainder of previous frame.
@@ -663,19 +693,24 @@ func (c *Conn) advanceFrame() (int, error) {
// 2. Read and parse first two bytes of frame header.
var b [8]byte
if err := c.readFull(b[:2]); err != nil {
p, err := c.read(2)
if err != nil {
return noFrame, err
}
final := b[0]&finalBit != 0
frameType := int(b[0] & 0xf)
reserved := int((b[0] >> 4) & 0x7)
mask := b[1]&maskBit != 0
c.readRemaining = int64(b[1] & 0x7f)
final := p[0]&finalBit != 0
frameType := int(p[0] & 0xf)
mask := p[1]&maskBit != 0
c.readRemaining = int64(p[1] & 0x7f)
if reserved != 0 {
return noFrame, c.handleProtocolError("unexpected reserved bits " + strconv.Itoa(reserved))
c.readDecompress = false
if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
c.readDecompress = true
p[0] &^= rsv1Bit
}
if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 {
return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16))
}
switch frameType {
@@ -704,15 +739,17 @@ func (c *Conn) advanceFrame() (int, error) {
switch c.readRemaining {
case 126:
if err := c.readFull(b[:2]); err != nil {
p, err := c.read(2)
if err != nil {
return noFrame, err
}
c.readRemaining = int64(binary.BigEndian.Uint16(b[:2]))
c.readRemaining = int64(binary.BigEndian.Uint16(p))
case 127:
if err := c.readFull(b[:8]); err != nil {
p, err := c.read(8)
if err != nil {
return noFrame, err
}
c.readRemaining = int64(binary.BigEndian.Uint64(b[:8]))
c.readRemaining = int64(binary.BigEndian.Uint64(p))
}
// 4. Handle frame masking.
@@ -723,9 +760,11 @@ func (c *Conn) advanceFrame() (int, error) {
if mask {
c.readMaskPos = 0
if err := c.readFull(c.readMaskKey[:]); err != nil {
p, err := c.read(len(c.readMaskKey))
if err != nil {
return noFrame, err
}
copy(c.readMaskKey[:], p)
}
// 5. For text and binary messages, enforce read limit and return.
@@ -745,9 +784,9 @@ func (c *Conn) advanceFrame() (int, error) {
var payload []byte
if c.readRemaining > 0 {
payload = make([]byte, c.readRemaining)
payload, err = c.read(int(c.readRemaining))
c.readRemaining = 0
if err := c.readFull(payload); err != nil {
if err != nil {
return noFrame, err
}
if c.isServer {
@@ -767,11 +806,9 @@ func (c *Conn) advanceFrame() (int, error) {
return noFrame, err
}
case CloseMessage:
echoMessage := []byte{}
closeCode := CloseNoStatusReceived
closeText := ""
if len(payload) >= 2 {
echoMessage = payload[:2]
closeCode = int(binary.BigEndian.Uint16(payload))
if !isValidReceivedCloseCode(closeCode) {
return noFrame, c.handleProtocolError("invalid close code")
@@ -781,7 +818,9 @@ func (c *Conn) advanceFrame() (int, error) {
return noFrame, c.handleProtocolError("invalid utf8 payload in close frame")
}
}
c.WriteControl(CloseMessage, echoMessage, time.Now().Add(writeWait))
if err := c.handleClose(closeCode, closeText); err != nil {
return noFrame, err
}
return noFrame, &CloseError{Code: closeCode, Text: closeText}
}
@@ -805,7 +844,7 @@ func (c *Conn) handleProtocolError(message string) error {
// this method return the same error.
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
c.readSeq++
c.messageReader = nil
c.readLength = 0
for c.readErr == nil {
@@ -815,7 +854,12 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
break
}
if frameType == TextMessage || frameType == BinaryMessage {
return frameType, messageReader{c, c.readSeq}, nil
c.messageReader = &messageReader{c}
var r io.Reader = c.messageReader
if c.readDecompress {
r = c.newDecompressionReader(r)
}
return frameType, r, nil
}
}
@@ -830,51 +874,48 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
return noFrame, nil, c.readErr
}
type messageReader struct {
c *Conn
seq int
}
type messageReader struct{ c *Conn }
func (r messageReader) Read(b []byte) (int, error) {
if r.seq != r.c.readSeq {
func (r *messageReader) Read(b []byte) (int, error) {
c := r.c
if c.messageReader != r {
return 0, io.EOF
}
for r.c.readErr == nil {
for c.readErr == nil {
if r.c.readRemaining > 0 {
if int64(len(b)) > r.c.readRemaining {
b = b[:r.c.readRemaining]
if c.readRemaining > 0 {
if int64(len(b)) > c.readRemaining {
b = b[:c.readRemaining]
}
n, err := r.c.br.Read(b)
r.c.readErr = hideTempErr(err)
if r.c.isServer {
r.c.readMaskPos = maskBytes(r.c.readMaskKey, r.c.readMaskPos, b[:n])
n, err := c.br.Read(b)
c.readErr = hideTempErr(err)
if c.isServer {
c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
}
r.c.readRemaining -= int64(n)
if r.c.readRemaining > 0 && r.c.readErr == io.EOF {
r.c.readErr = errUnexpectedEOF
c.readRemaining -= int64(n)
if c.readRemaining > 0 && c.readErr == io.EOF {
c.readErr = errUnexpectedEOF
}
return n, r.c.readErr
return n, c.readErr
}
if r.c.readFinal {
r.c.readSeq++
if c.readFinal {
c.messageReader = nil
return 0, io.EOF
}
frameType, err := r.c.advanceFrame()
frameType, err := c.advanceFrame()
switch {
case err != nil:
r.c.readErr = hideTempErr(err)
c.readErr = hideTempErr(err)
case frameType == TextMessage || frameType == BinaryMessage:
r.c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
}
}
err := r.c.readErr
if err == io.EOF && r.seq == r.c.readSeq {
err := c.readErr
if err == io.EOF && c.messageReader == r {
err = errUnexpectedEOF
}
return 0, err
@@ -907,6 +948,34 @@ func (c *Conn) SetReadLimit(limit int64) {
c.readLimit = limit
}
// CloseHandler returns the current close handler
func (c *Conn) CloseHandler() func(code int, text string) error {
return c.handleClose
}
// SetCloseHandler sets the handler for close messages received from the peer.
// The code argument to h is the received close code or CloseNoStatusReceived
// if the close message is empty. The default close handler sends a close frame
// back to the peer.
func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
if h == nil {
h = func(code int, text string) error {
message := []byte{}
if code != CloseNoStatusReceived {
message = FormatCloseMessage(code, "")
}
c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
return nil
}
}
c.handleClose = h
}
// PingHandler returns the current ping handler
func (c *Conn) PingHandler() func(appData string) error {
return c.handlePing
}
// SetPingHandler sets the handler for ping messages received from the peer.
// The appData argument to h is the PING frame application data. The default
// ping handler sends a pong to the peer.
@@ -925,6 +994,11 @@ func (c *Conn) SetPingHandler(h func(appData string) error) {
c.handlePing = h
}
// PongHandler returns the current pong handler
func (c *Conn) PongHandler() func(appData string) error {
return c.handlePong
}
// SetPongHandler sets the handler for pong messages received from the peer.
// The appData argument to h is the PONG frame application data. The default
// pong handler does nothing.
@@ -941,6 +1015,13 @@ func (c *Conn) UnderlyingConn() net.Conn {
return c.conn
}
// EnableWriteCompression enables and disables write compression of
// subsequent text and binary messages. This function is a noop if
// compression was not negotiated with the peer.
func (c *Conn) EnableWriteCompression(enable bool) {
c.enableWriteCompression = enable
}
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
func FormatCloseMessage(closeCode int, text string) []byte {
buf := make([]byte, 2+len(text))

18
vendor/github.com/gorilla/websocket/conn_read.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,18 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.5
package websocket
import "io"
func (c *Conn) read(n int) ([]byte, error) {
p, err := c.br.Peek(n)
if err == io.EOF {
err = errUnexpectedEOF
}
c.br.Discard(len(p))
return p, err
}

21
vendor/github.com/gorilla/websocket/conn_read_legacy.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,21 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.5
package websocket
import "io"
func (c *Conn) read(n int) ([]byte, error) {
p, err := c.br.Peek(n)
if err == io.EOF {
err = errUnexpectedEOF
}
if len(p) > 0 {
// advance over the bytes just read
io.ReadFull(c.br, p)
}
return p, err
}

169
vendor/github.com/gorilla/websocket/conn_test.go сгенерированный поставляемый
Просмотреть файл

@@ -26,12 +26,27 @@ type fakeNetConn struct {
}
func (c fakeNetConn) Close() error { return nil }
func (c fakeNetConn) LocalAddr() net.Addr { return nil }
func (c fakeNetConn) RemoteAddr() net.Addr { return nil }
func (c fakeNetConn) LocalAddr() net.Addr { return localAddr }
func (c fakeNetConn) RemoteAddr() net.Addr { return remoteAddr }
func (c fakeNetConn) SetDeadline(t time.Time) error { return nil }
func (c fakeNetConn) SetReadDeadline(t time.Time) error { return nil }
func (c fakeNetConn) SetWriteDeadline(t time.Time) error { return nil }
type fakeAddr int
var (
localAddr = fakeAddr(1)
remoteAddr = fakeAddr(2)
)
func (a fakeAddr) Network() string {
return "net"
}
func (a fakeAddr) String() string {
return "str"
}
func TestFraming(t *testing.T) {
frameSizes := []int{0, 1, 2, 124, 125, 126, 127, 128, 129, 65534, 65535, 65536, 65537}
var readChunkers = []struct {
@@ -42,66 +57,78 @@ func TestFraming(t *testing.T) {
{"one", iotest.OneByteReader},
{"asis", func(r io.Reader) io.Reader { return r }},
}
writeBuf := make([]byte, 65537)
for i := range writeBuf {
writeBuf[i] = byte(i)
}
var writers = []struct {
name string
f func(w io.Writer, n int) (int, error)
}{
{"iocopy", func(w io.Writer, n int) (int, error) {
nn, err := io.Copy(w, bytes.NewReader(writeBuf[:n]))
return int(nn), err
}},
{"write", func(w io.Writer, n int) (int, error) {
return w.Write(writeBuf[:n])
}},
{"string", func(w io.Writer, n int) (int, error) {
return io.WriteString(w, string(writeBuf[:n]))
}},
}
for _, isServer := range []bool{true, false} {
for _, chunker := range readChunkers {
for _, compress := range []bool{false, true} {
for _, isServer := range []bool{true, false} {
for _, chunker := range readChunkers {
var connBuf bytes.Buffer
wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024)
rc := newConn(fakeNetConn{Reader: chunker.f(&connBuf), Writer: nil}, !isServer, 1024, 1024)
var connBuf bytes.Buffer
wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024)
rc := newConn(fakeNetConn{Reader: chunker.f(&connBuf), Writer: nil}, !isServer, 1024, 1024)
if compress {
wc.newCompressionWriter = compressNoContextTakeover
rc.newDecompressionReader = decompressNoContextTakeover
}
for _, n := range frameSizes {
for _, writer := range writers {
name := fmt.Sprintf("z:%v, s:%v, r:%s, n:%d w:%s", compress, isServer, chunker.name, n, writer.name)
for _, n := range frameSizes {
for _, iocopy := range []bool{true, false} {
name := fmt.Sprintf("s:%v, r:%s, n:%d c:%v", isServer, chunker.name, n, iocopy)
w, err := wc.NextWriter(TextMessage)
if err != nil {
t.Errorf("%s: wc.NextWriter() returned %v", name, err)
continue
}
nn, err := writer.f(w, n)
if err != nil || nn != n {
t.Errorf("%s: w.Write(writeBuf[:n]) returned %d, %v", name, nn, err)
continue
}
err = w.Close()
if err != nil {
t.Errorf("%s: w.Close() returned %v", name, err)
continue
}
w, err := wc.NextWriter(TextMessage)
if err != nil {
t.Errorf("%s: wc.NextWriter() returned %v", name, err)
continue
}
var nn int
if iocopy {
var n64 int64
n64, err = io.Copy(w, bytes.NewReader(writeBuf[:n]))
nn = int(n64)
} else {
nn, err = w.Write(writeBuf[:n])
}
if err != nil || nn != n {
t.Errorf("%s: w.Write(writeBuf[:n]) returned %d, %v", name, nn, err)
continue
}
err = w.Close()
if err != nil {
t.Errorf("%s: w.Close() returned %v", name, err)
continue
}
opCode, r, err := rc.NextReader()
if err != nil || opCode != TextMessage {
t.Errorf("%s: NextReader() returned %d, r, %v", name, opCode, err)
continue
}
rbuf, err := ioutil.ReadAll(r)
if err != nil {
t.Errorf("%s: ReadFull() returned rbuf, %v", name, err)
continue
}
opCode, r, err := rc.NextReader()
if err != nil || opCode != TextMessage {
t.Errorf("%s: NextReader() returned %d, r, %v", name, opCode, err)
continue
}
rbuf, err := ioutil.ReadAll(r)
if err != nil {
t.Errorf("%s: ReadFull() returned rbuf, %v", name, err)
continue
}
if len(rbuf) != n {
t.Errorf("%s: len(rbuf) is %d, want %d", name, len(rbuf), n)
continue
}
if len(rbuf) != n {
t.Errorf("%s: len(rbuf) is %d, want %d", name, len(rbuf), n)
continue
}
for i, b := range rbuf {
if byte(i) != b {
t.Errorf("%s: bad byte at offset %d", name, i)
break
for i, b := range rbuf {
if byte(i) != b {
t.Errorf("%s: bad byte at offset %d", name, i)
break
}
}
}
}
@@ -146,7 +173,7 @@ func TestControl(t *testing.T) {
}
}
func TestCloseBeforeFinalFrame(t *testing.T) {
func TestCloseFrameBeforeFinalMessageFrame(t *testing.T) {
const bufSize = 512
expectedErr := &CloseError{Code: CloseNormalClosure, Text: "hello"}
@@ -233,6 +260,32 @@ func TestEOFBeforeFinalFrame(t *testing.T) {
}
}
func TestWriteAfterMessageWriterClose(t *testing.T) {
wc := newConn(fakeNetConn{Reader: nil, Writer: &bytes.Buffer{}}, false, 1024, 1024)
w, _ := wc.NextWriter(BinaryMessage)
io.WriteString(w, "hello")
if err := w.Close(); err != nil {
t.Fatalf("unxpected error closing message writer, %v", err)
}
if _, err := io.WriteString(w, "world"); err == nil {
t.Fatalf("no error writing after close")
}
w, _ = wc.NextWriter(BinaryMessage)
io.WriteString(w, "hello")
// close w by getting next writer
_, err := wc.NextWriter(BinaryMessage)
if err != nil {
t.Fatalf("unexpected error getting next writer, %v", err)
}
if _, err := io.WriteString(w, "world"); err == nil {
t.Fatalf("no error writing after close")
}
}
func TestReadLimit(t *testing.T) {
const readLimit = 512
@@ -267,6 +320,16 @@ func TestReadLimit(t *testing.T) {
}
}
func TestAddrs(t *testing.T) {
c := newConn(&fakeNetConn{}, true, 1024, 1024)
if c.LocalAddr() != localAddr {
t.Errorf("LocalAddr = %v, want %v", c.LocalAddr(), localAddr)
}
if c.RemoteAddr() != remoteAddr {
t.Errorf("RemoteAddr = %v, want %v", c.RemoteAddr(), remoteAddr)
}
}
func TestUnderlyingConn(t *testing.T) {
var b1, b2 bytes.Buffer
fc := fakeNetConn{Reader: &b1, Writer: &b2}

21
vendor/github.com/gorilla/websocket/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -149,4 +149,25 @@
// The deprecated Upgrade function does not enforce an origin policy. It's the
// application's responsibility to check the Origin header before calling
// Upgrade.
//
// Compression [Experimental]
//
// Per message compression extensions (RFC 7692) are experimentally supported
// by this package in a limited capacity. Setting the EnableCompression option
// to true in Dialer or Upgrader will attempt to negotiate per message deflate
// support. If compression was successfully negotiated with the connection's
// peer, any message received in compressed form will be automatically
// decompressed. All Read methods will return uncompressed bytes.
//
// Per message compression of messages written to a connection can be enabled
// or disabled by calling the corresponding Conn method:
//
// conn.EnableWriteCompression(true)
//
// Currently this package does not support compression with "context takeover".
// This means that messages must be compressed and decompressed in isolation,
// without retaining sliding window or dictionary state across messages. For
// more details refer to RFC 7692.
//
// Use of compression is experimental and may result in decreased performance.
package websocket

8
vendor/github.com/gorilla/websocket/examples/autobahn/server.go сгенерированный поставляемый
Просмотреть файл

@@ -8,17 +8,19 @@ package main
import (
"errors"
"flag"
"github.com/gorilla/websocket"
"io"
"log"
"net/http"
"time"
"unicode/utf8"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 4096,
WriteBufferSize: 4096,
ReadBufferSize: 4096,
WriteBufferSize: 4096,
EnableCompression: true,
CheckOrigin: func(r *http.Request) bool {
return true
},

86
vendor/github.com/gorilla/websocket/examples/chat/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,8 +1,8 @@
# Chat Example
This application shows how to use use the
[websocket](https://github.com/gorilla/websocket) package and
[jQuery](http://jquery.com) to implement a simple web chat application.
[websocket](https://github.com/gorilla/websocket) package to implement a simple
web chat application.
## Running the example
@@ -18,3 +18,85 @@ using the following commands.
$ go run *.go
To use the chat example, open http://localhost:8080/ in your browser.
## Server
The server application defines two types, `Client` and `Hub`. The server
creates an instance of the `Client` type for each websocket connection. A
`Client` acts as an intermediary between the websocket connection and a single
instance of the `Hub` type. The `Hub` maintains a set of registered clients and
broadcasts messages to the clients.
The application runs one goroutine for the `Hub` and two goroutines for each
`Client`. The goroutines communicate with each other using channels. The `Hub`
has channels for registering clients, unregistering clients and broadcasting
messages. A `Client` has a buffered channel of outbound messages. One of the
client's goroutines reads messages from this channel and writes the messages to
the websocket. The other client goroutine reads messages from the websocket and
sends them to the hub.
### Hub
The code for the `Hub` type is in
[hub.go](https://github.com/gorilla/websocket/blob/master/examples/chat/hub.go).
The application's `main` function starts the hub's `run` method as a goroutine.
Clients send requests to the hub using the `register`, `unregister` and
`broadcast` channels.
The hub registers clients by adding the client pointer as a key in the
`clients` map. The map value is always true.
The unregister code is a little more complicated. In addition to deleting the
client pointer from the `clients` map, the hub closes the clients's `send`
channel to signal the client that no more messages will be sent to the client.
The hub handles messages by looping over the registered clients and sending the
message to the client's `send` channel. If the client's `send` buffer is full,
then the hub assumes that the client is dead or stuck. In this case, the hub
unregisters the client and closes the websocket.
### Client
The code for the `Client` type is in [client.go](https://github.com/gorilla/websocket/blob/master/examples/chat/client.go).
The `serveWs` function is registered by the application's `main` function as
an HTTP handler. The handler upgrades the HTTP connection to the WebSocket
protocol, creates a client, registers the client with the hub and schedules the
client to be unregistered using a defer statement.
Next, the HTTP handler starts the client's `writePump` method as a goroutine.
This method transfers messages from the client's send channel to the websocket
connection. The writer method exits when the channel is closed by the hub or
there's an error writing to the websocket connection.
Finally, the HTTP handler calls the client's `readPump` method. This method
transfers inbound messages from the websocket to the hub.
WebSocket connections [support one concurrent reader and one concurrent
writer](https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency). The
application ensures that these concurrency requirements are met by executing
all reads from the `readPump` goroutine and all writes from the `writePump`
goroutine.
To improve efficiency under high load, the `writePump` function coalesces
pending chat messages in the `send` channel to a single WebSocket message. This
reduces the number of system calls and the amount of data sent over the
network.
## Frontend
The frontend code is in [home.html](https://github.com/gorilla/websocket/blob/master/examples/chat/home.html).
On document load, the script checks for websocket functionality in the browser.
If websocket functionality is available, then the script opens a connection to
the server and registers a callback to handle messages from the server. The
callback appends the message to the chat log using the appendLog function.
To allow the user to manually scroll through the chat log without interruption
from new messages, the `appendLog` function checks the scroll position before
adding new content. If the chat log is scrolled to the bottom, then the
function scrolls new content into view after adding the content. Otherwise, the
scroll position is not changed.
The form handler writes the user input to the websocket and clears the input
field.

134
vendor/github.com/gorilla/websocket/examples/chat/client.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,134 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
const (
// Time allowed to write a message to the peer.
writeWait = 10 * time.Second
// Time allowed to read the next pong message from the peer.
pongWait = 60 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
// Maximum message size allowed from peer.
maxMessageSize = 512
)
var (
newline = []byte{'\n'}
space = []byte{' '}
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
// Client is a middleman between the websocket connection and the hub.
type Client struct {
hub *Hub
// The websocket connection.
conn *websocket.Conn
// Buffered channel of outbound messages.
send chan []byte
}
// readPump pumps messages from the websocket connection to the hub.
//
// The application runs readPump in a per-connection goroutine. The application
// ensures that there is at most one reader on a connection by executing all
// reads from this goroutine.
func (c *Client) readPump() {
defer func() {
c.hub.unregister <- c
c.conn.Close()
}()
c.conn.SetReadLimit(maxMessageSize)
c.conn.SetReadDeadline(time.Now().Add(pongWait))
c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
for {
_, message, err := c.conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
log.Printf("error: %v", err)
}
break
}
message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
c.hub.broadcast <- message
}
}
// writePump pumps messages from the hub to the websocket connection.
//
// A goroutine running writePump is started for each connection. The
// application ensures that there is at most one writer to a connection by
// executing all writes from this goroutine.
func (c *Client) writePump() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
c.conn.Close()
}()
for {
select {
case message, ok := <-c.send:
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if !ok {
// The hub closed the channel.
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
return
}
w, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
return
}
w.Write(message)
// Add queued chat messages to the current websocket message.
n := len(c.send)
for i := 0; i < n; i++ {
w.Write(newline)
w.Write(<-c.send)
}
if err := w.Close(); err != nil {
return
}
case <-ticker.C:
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if err := c.conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
return
}
}
}
}
// serveWs handles websocket requests from the peer.
func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}
client.hub.register <- client
go client.writePump()
client.readPump()
}

105
vendor/github.com/gorilla/websocket/examples/chat/conn.go сгенерированный поставляемый
Просмотреть файл

@@ -1,105 +0,0 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"github.com/gorilla/websocket"
"log"
"net/http"
"time"
)
const (
// Time allowed to write a message to the peer.
writeWait = 10 * time.Second
// Time allowed to read the next pong message from the peer.
pongWait = 60 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
// Maximum message size allowed from peer.
maxMessageSize = 512
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
// connection is an middleman between the websocket connection and the hub.
type connection struct {
// The websocket connection.
ws *websocket.Conn
// Buffered channel of outbound messages.
send chan []byte
}
// readPump pumps messages from the websocket connection to the hub.
func (c *connection) readPump() {
defer func() {
h.unregister <- c
c.ws.Close()
}()
c.ws.SetReadLimit(maxMessageSize)
c.ws.SetReadDeadline(time.Now().Add(pongWait))
c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
for {
_, message, err := c.ws.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
log.Printf("error: %v", err)
}
break
}
h.broadcast <- message
}
}
// write writes a message with the given message type and payload.
func (c *connection) write(mt int, payload []byte) error {
c.ws.SetWriteDeadline(time.Now().Add(writeWait))
return c.ws.WriteMessage(mt, payload)
}
// writePump pumps messages from the hub to the websocket connection.
func (c *connection) writePump() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
c.ws.Close()
}()
for {
select {
case message, ok := <-c.send:
if !ok {
c.write(websocket.CloseMessage, []byte{})
return
}
if err := c.write(websocket.TextMessage, message); err != nil {
return
}
case <-ticker.C:
if err := c.write(websocket.PingMessage, []byte{}); err != nil {
return
}
}
}
}
// serveWs handles websocket requests from the peer.
func serveWs(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
c := &connection{send: make(chan []byte, 256), ws: ws}
h.register <- c
go c.writePump()
c.readPump()
}

54
vendor/github.com/gorilla/websocket/examples/chat/home.html сгенерированный поставляемый
Просмотреть файл

@@ -2,47 +2,53 @@
<html lang="en">
<head>
<title>Chat Example</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
window.onload = function () {
var conn;
var msg = $("#msg");
var log = $("#log");
var msg = document.getElementById("msg");
var log = document.getElementById("log");
function appendLog(msg) {
var d = log[0]
var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
msg.appendTo(log)
function appendLog(item) {
var doScroll = log.scrollTop === log.scrollHeight - log.clientHeight;
log.appendChild(item);
if (doScroll) {
d.scrollTop = d.scrollHeight - d.clientHeight;
log.scrollTop = log.scrollHeight - log.clientHeight;
}
}
$("#form").submit(function() {
document.getElementById("form").onsubmit = function () {
if (!conn) {
return false;
}
if (!msg.val()) {
if (!msg.value) {
return false;
}
conn.send(msg.val());
msg.val("");
return false
});
conn.send(msg.value);
msg.value = "";
return false;
};
if (window["WebSocket"]) {
conn = new WebSocket("ws://{{$}}/ws");
conn.onclose = function(evt) {
appendLog($("<div><b>Connection closed.</b></div>"))
}
conn.onmessage = function(evt) {
appendLog($("<div/>").text(evt.data))
}
conn.onclose = function (evt) {
var item = document.createElement("div");
item.innerHTML = "<b>Connection closed.</b>";
appendLog(item);
};
conn.onmessage = function (evt) {
var messages = evt.data.split('\n');
for (var i = 0; i < messages.length; i++) {
var item = document.createElement("div");
item.innerText = messages[i];
appendLog(item);
}
};
} else {
appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
var item = document.createElement("div");
item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
appendLog(item);
}
});
};
</script>
<style type="text/css">
html {

56
vendor/github.com/gorilla/websocket/examples/chat/hub.go сгенерированный поставляемый
Просмотреть файл

@@ -4,46 +4,48 @@
package main
// hub maintains the set of active connections and broadcasts messages to the
// connections.
type hub struct {
// Registered connections.
connections map[*connection]bool
// hub maintains the set of active clients and broadcasts messages to the
// clients.
type Hub struct {
// Registered clients.
clients map[*Client]bool
// Inbound messages from the connections.
// Inbound messages from the clients.
broadcast chan []byte
// Register requests from the connections.
register chan *connection
// Register requests from the clients.
register chan *Client
// Unregister requests from connections.
unregister chan *connection
// Unregister requests from clients.
unregister chan *Client
}
var h = hub{
broadcast: make(chan []byte),
register: make(chan *connection),
unregister: make(chan *connection),
connections: make(map[*connection]bool),
func newHub() *Hub {
return &Hub{
broadcast: make(chan []byte),
register: make(chan *Client),
unregister: make(chan *Client),
clients: make(map[*Client]bool),
}
}
func (h *hub) run() {
func (h *Hub) run() {
for {
select {
case c := <-h.register:
h.connections[c] = true
case c := <-h.unregister:
if _, ok := h.connections[c]; ok {
delete(h.connections, c)
close(c.send)
case client := <-h.register:
h.clients[client] = true
case client := <-h.unregister:
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
case m := <-h.broadcast:
for c := range h.connections {
case message := <-h.broadcast:
for client := range h.clients {
select {
case c.send <- m:
case client.send <- message:
default:
close(c.send)
delete(h.connections, c)
close(client.send)
delete(h.clients, client)
}
}
}

12
vendor/github.com/gorilla/websocket/examples/chat/main.go сгенерированный поставляемый
Просмотреть файл

@@ -12,9 +12,10 @@ import (
)
var addr = flag.String("addr", ":8080", "http service address")
var homeTempl = template.Must(template.ParseFiles("home.html"))
var homeTemplate = template.Must(template.ParseFiles("home.html"))
func serveHome(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL)
if r.URL.Path != "/" {
http.Error(w, "Not found", 404)
return
@@ -24,14 +25,17 @@ func serveHome(w http.ResponseWriter, r *http.Request) {
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
homeTempl.Execute(w, r.Host)
homeTemplate.Execute(w, r.Host)
}
func main() {
flag.Parse()
go h.run()
hub := newHub()
go hub.run()
http.HandleFunc("/", serveHome)
http.HandleFunc("/ws", serveWs)
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
serveWs(hub, w, r)
})
err := http.ListenAndServe(*addr, nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)

12
vendor/github.com/gorilla/websocket/examples/command/main.go сгенерированный поставляемый
Просмотреть файл

@@ -36,6 +36,9 @@ const (
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
// Time to wait before force close on connection.
closeGracePeriod = 10 * time.Second
)
func pumpStdin(ws *websocket.Conn, w io.Writer) {
@@ -57,19 +60,24 @@ func pumpStdin(ws *websocket.Conn, w io.Writer) {
func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
defer func() {
ws.Close()
close(done)
}()
s := bufio.NewScanner(r)
for s.Scan() {
ws.SetWriteDeadline(time.Now().Add(writeWait))
if err := ws.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
ws.Close()
break
}
}
if s.Err() != nil {
log.Println("scan:", s.Err())
}
close(done)
ws.SetWriteDeadline(time.Now().Add(writeWait))
ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
time.Sleep(closeGracePeriod)
ws.Close()
}
func ping(ws *websocket.Conn, done chan struct{}) {

61
vendor/github.com/gorilla/websocket/mask.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,61 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
package websocket
import (
"math/rand"
"unsafe"
)
const wordSize = int(unsafe.Sizeof(uintptr(0)))
func newMaskKey() [4]byte {
n := rand.Uint32()
return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
}
func maskBytes(key [4]byte, pos int, b []byte) int {
// Mask one byte at a time for small buffers.
if len(b) < 2*wordSize {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
// Mask one byte at a time to word boundary.
if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 {
n = wordSize - n
for i := range b[:n] {
b[i] ^= key[pos&3]
pos++
}
b = b[n:]
}
// Create aligned word size key.
var k [wordSize]byte
for i := range k {
k[i] = key[(pos+i)&3]
}
kw := *(*uintptr)(unsafe.Pointer(&k))
// Mask one word at a time.
n := (len(b) / wordSize) * wordSize
for i := 0; i < n; i += wordSize {
*(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
}
// Mask one byte at a time for remaining bytes.
b = b[n:]
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}

73
vendor/github.com/gorilla/websocket/mask_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,73 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
// Require 1.7 for sub-bencmarks
// +build go1.7
package websocket
import (
"fmt"
"testing"
)
func maskBytesByByte(key [4]byte, pos int, b []byte) int {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
func notzero(b []byte) int {
for i := range b {
if b[i] != 0 {
return i
}
}
return -1
}
func TestMaskBytes(t *testing.T) {
key := [4]byte{1, 2, 3, 4}
for size := 1; size <= 1024; size++ {
for align := 0; align < wordSize; align++ {
for pos := 0; pos < 4; pos++ {
b := make([]byte, size+align)[align:]
maskBytes(key, pos, b)
maskBytesByByte(key, pos, b)
if i := notzero(b); i >= 0 {
t.Errorf("size:%d, align:%d, pos:%d, offset:%d", size, align, pos, i)
}
}
}
}
}
func BenchmarkMaskBytes(b *testing.B) {
for _, size := range []int{2, 4, 8, 16, 32, 512, 1024} {
b.Run(fmt.Sprintf("size-%d", size), func(b *testing.B) {
for _, align := range []int{wordSize / 2} {
b.Run(fmt.Sprintf("align-%d", align), func(b *testing.B) {
for _, fn := range []struct {
name string
fn func(key [4]byte, pos int, b []byte) int
}{
{"byte", maskBytesByByte},
{"word", maskBytes},
} {
b.Run(fn.name, func(b *testing.B) {
key := newMaskKey()
data := make([]byte, size+align)[align:]
for i := 0; i < b.N; i++ {
fn.fn(key, 0, data)
}
b.SetBytes(int64(len(data)))
})
}
})
}
})
}
}

34
vendor/github.com/gorilla/websocket/server.go сгенерированный поставляемый
Просмотреть файл

@@ -46,6 +46,12 @@ type Upgrader struct {
// CheckOrigin is nil, the host in the Origin header must not be set or
// must match the host of the request.
CheckOrigin func(r *http.Request) bool
// EnableCompression specify if the server should attempt to negotiate per
// message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
EnableCompression bool
}
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
@@ -53,6 +59,7 @@ func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status in
if u.Error != nil {
u.Error(w, r, status, err)
} else {
w.Header().Set("Sec-Websocket-Version", "13")
http.Error(w, http.StatusText(status), status)
}
return nil, err
@@ -99,7 +106,12 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
if r.Method != "GET" {
return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET")
}
if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific Sec-Websocket-Extensions headers are unsupported")
}
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
}
@@ -126,6 +138,18 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
subprotocol := u.selectSubprotocol(r, responseHeader)
// Negotiate PMCE
var compress bool
if u.EnableCompression {
for _, ext := range parseExtensions(r.Header) {
if ext[""] != "permessage-deflate" {
continue
}
compress = true
break
}
}
var (
netConn net.Conn
br *bufio.Reader
@@ -151,6 +175,11 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
c.subprotocol = subprotocol
if compress {
c.newCompressionWriter = compressNoContextTakeover
c.newDecompressionReader = decompressNoContextTakeover
}
p := c.writeBuf[:0]
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
p = append(p, computeAcceptKey(challengeKey)...)
@@ -160,6 +189,9 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
p = append(p, c.subprotocol...)
p = append(p, "\r\n"...)
}
if compress {
p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
}
for k, vs := range responseHeader {
if k == "Sec-Websocket-Protocol" {
continue

196
vendor/github.com/gorilla/websocket/util.go сгенерированный поставляемый
Просмотреть файл

@@ -13,19 +13,6 @@ import (
"strings"
)
// tokenListContainsValue returns true if the 1#token header with the given
// name contains token.
func tokenListContainsValue(header http.Header, name string, value string) bool {
for _, v := range header[name] {
for _, s := range strings.Split(v, ",") {
if strings.EqualFold(value, strings.TrimSpace(s)) {
return true
}
}
}
return false
}
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func computeAcceptKey(challengeKey string) string {
@@ -42,3 +29,186 @@ func generateChallengeKey() (string, error) {
}
return base64.StdEncoding.EncodeToString(p), nil
}
// Octet types from RFC 2616.
var octetTypes [256]byte
const (
isTokenOctet = 1 << iota
isSpaceOctet
)
func init() {
// From RFC 2616
//
// OCTET = <any 8-bit sequence of data>
// CHAR = <any US-ASCII character (octets 0 - 127)>
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
// CR = <US-ASCII CR, carriage return (13)>
// LF = <US-ASCII LF, linefeed (10)>
// SP = <US-ASCII SP, space (32)>
// HT = <US-ASCII HT, horizontal-tab (9)>
// <"> = <US-ASCII double-quote mark (34)>
// CRLF = CR LF
// LWS = [CRLF] 1*( SP | HT )
// TEXT = <any OCTET except CTLs, but including LWS>
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
// token = 1*<any CHAR except CTLs or separators>
// qdtext = <any TEXT except <">>
for c := 0; c < 256; c++ {
var t byte
isCtl := c <= 31 || c == 127
isChar := 0 <= c && c <= 127
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
t |= isSpaceOctet
}
if isChar && !isCtl && !isSeparator {
t |= isTokenOctet
}
octetTypes[c] = t
}
}
func skipSpace(s string) (rest string) {
i := 0
for ; i < len(s); i++ {
if octetTypes[s[i]]&isSpaceOctet == 0 {
break
}
}
return s[i:]
}
func nextToken(s string) (token, rest string) {
i := 0
for ; i < len(s); i++ {
if octetTypes[s[i]]&isTokenOctet == 0 {
break
}
}
return s[:i], s[i:]
}
func nextTokenOrQuoted(s string) (value string, rest string) {
if !strings.HasPrefix(s, "\"") {
return nextToken(s)
}
s = s[1:]
for i := 0; i < len(s); i++ {
switch s[i] {
case '"':
return s[:i], s[i+1:]
case '\\':
p := make([]byte, len(s)-1)
j := copy(p, s[:i])
escape := true
for i = i + 1; i < len(s); i++ {
b := s[i]
switch {
case escape:
escape = false
p[j] = b
j += 1
case b == '\\':
escape = true
case b == '"':
return string(p[:j]), s[i+1:]
default:
p[j] = b
j += 1
}
}
return "", ""
}
}
return "", ""
}
// tokenListContainsValue returns true if the 1#token header with the given
// name contains token.
func tokenListContainsValue(header http.Header, name string, value string) bool {
headers:
for _, s := range header[name] {
for {
var t string
t, s = nextToken(skipSpace(s))
if t == "" {
continue headers
}
s = skipSpace(s)
if s != "" && s[0] != ',' {
continue headers
}
if strings.EqualFold(t, value) {
return true
}
if s == "" {
continue headers
}
s = s[1:]
}
}
return false
}
// parseExtensiosn parses WebSocket extensions from a header.
func parseExtensions(header http.Header) []map[string]string {
// From RFC 6455:
//
// Sec-WebSocket-Extensions = extension-list
// extension-list = 1#extension
// extension = extension-token *( ";" extension-param )
// extension-token = registered-token
// registered-token = token
// extension-param = token [ "=" (token | quoted-string) ]
// ;When using the quoted-string syntax variant, the value
// ;after quoted-string unescaping MUST conform to the
// ;'token' ABNF.
var result []map[string]string
headers:
for _, s := range header["Sec-Websocket-Extensions"] {
for {
var t string
t, s = nextToken(skipSpace(s))
if t == "" {
continue headers
}
ext := map[string]string{"": t}
for {
s = skipSpace(s)
if !strings.HasPrefix(s, ";") {
break
}
var k string
k, s = nextToken(skipSpace(s[1:]))
if k == "" {
continue headers
}
s = skipSpace(s)
var v string
if strings.HasPrefix(s, "=") {
v, s = nextTokenOrQuoted(skipSpace(s[1:]))
s = skipSpace(s)
}
if s != "" && s[0] != ',' && s[0] != ';' {
continue headers
}
ext[k] = v
}
if s != "" && s[0] != ',' {
continue headers
}
result = append(result, ext)
if s == "" {
continue headers
}
s = s[1:]
}
}
return result
}

40
vendor/github.com/gorilla/websocket/util_test.go сгенерированный поставляемый
Просмотреть файл

@@ -6,6 +6,7 @@ package websocket
import (
"net/http"
"reflect"
"testing"
)
@@ -32,3 +33,42 @@ func TestTokenListContainsValue(t *testing.T) {
}
}
}
var parseExtensionTests = []struct {
value string
extensions []map[string]string
}{
{`foo`, []map[string]string{map[string]string{"": "foo"}}},
{`foo, bar; baz=2`, []map[string]string{
map[string]string{"": "foo"},
map[string]string{"": "bar", "baz": "2"}}},
{`foo; bar="b,a;z"`, []map[string]string{
map[string]string{"": "foo", "bar": "b,a;z"}}},
{`foo , bar; baz = 2`, []map[string]string{
map[string]string{"": "foo"},
map[string]string{"": "bar", "baz": "2"}}},
{`foo, bar; baz=2 junk`, []map[string]string{
map[string]string{"": "foo"}}},
{`foo junk, bar; baz=2 junk`, nil},
{`mux; max-channels=4; flow-control, deflate-stream`, []map[string]string{
map[string]string{"": "mux", "max-channels": "4", "flow-control": ""},
map[string]string{"": "deflate-stream"}}},
{`permessage-foo; x="10"`, []map[string]string{
map[string]string{"": "permessage-foo", "x": "10"}}},
{`permessage-foo; use_y, permessage-foo`, []map[string]string{
map[string]string{"": "permessage-foo", "use_y": ""},
map[string]string{"": "permessage-foo"}}},
{`permessage-deflate; client_max_window_bits; server_max_window_bits=10 , permessage-deflate; client_max_window_bits`, []map[string]string{
map[string]string{"": "permessage-deflate", "client_max_window_bits": "", "server_max_window_bits": "10"},
map[string]string{"": "permessage-deflate", "client_max_window_bits": ""}}},
}
func TestParseExtensions(t *testing.T) {
for _, tt := range parseExtensionTests {
h := http.Header{http.CanonicalHeaderKey("Sec-WebSocket-Extensions"): {tt.value}}
extensions := parseExtensions(h)
if !reflect.DeepEqual(extensions, tt.extensions) {
t.Errorf("parseExtensions(%q)\n = %v,\nwant %v", tt.value, extensions, tt.extensions)
}
}
}

74
vendor/github.com/lib/pq/conn.go сгенерированный поставляемый
Просмотреть файл

@@ -32,6 +32,10 @@ var (
ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server")
ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less.")
ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly.")
errUnexpectedReady = errors.New("unexpected ReadyForQuery")
errNoRowsAffected = errors.New("no RowsAffected available after the empty statement")
errNoLastInsertId = errors.New("no LastInsertId available after the empty statement")
)
type drv struct{}
@@ -115,6 +119,9 @@ type conn struct {
// Whether to always send []byte parameters over as binary. Enables single
// round-trip mode for non-prepared Query calls.
binaryParameters bool
// If true this connection is in the middle of a COPY
inCopy bool
}
// Handle driver-side settings in parsed connection string.
@@ -598,11 +605,16 @@ func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err
res, commandTag = cn.parseComplete(r.string())
case 'Z':
cn.processReadyForQuery(r)
if res == nil && err == nil {
err = errUnexpectedReady
}
// done
return
case 'E':
err = parseError(r)
case 'T', 'D', 'I':
case 'I':
res = emptyRows
case 'T', 'D':
// ignore any results
default:
cn.bad = true
@@ -666,6 +678,20 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
}
}
type noRows struct{}
var emptyRows noRows
var _ driver.Result = noRows{}
func (noRows) LastInsertId() (int64, error) {
return 0, errNoLastInsertId
}
func (noRows) RowsAffected() (int64, error) {
return 0, errNoRowsAffected
}
// Decides which column formats to use for a prepared statement. The input is
// an array of type oids, one element per result column.
func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, colFmtData []byte) {
@@ -743,25 +769,31 @@ func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) {
defer cn.errRecover(&err)
if len(q) >= 4 && strings.EqualFold(q[:4], "COPY") {
return cn.prepareCopyIn(q)
s, err := cn.prepareCopyIn(q)
if err == nil {
cn.inCopy = true
}
return s, err
}
return cn.prepareTo(q, cn.gname()), nil
}
func (cn *conn) Close() (err error) {
if cn.bad {
return driver.ErrBadConn
}
// Skip cn.bad return here because we always want to close a connection.
defer cn.errRecover(&err)
// Ensure that cn.c.Close is always run. Since error handling is done with
// panics and cn.errRecover, the Close must be in a defer.
defer func() {
cerr := cn.c.Close()
if err == nil {
err = cerr
}
}()
// Don't go through send(); ListenerConn relies on us not scribbling on the
// scratch buffer of this connection.
err = cn.sendSimpleMessage('X')
if err != nil {
return err
}
return cn.c.Close()
return cn.sendSimpleMessage('X')
}
// Implement the "Queryer" interface
@@ -769,6 +801,9 @@ func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err err
if cn.bad {
return nil, driver.ErrBadConn
}
if cn.inCopy {
return nil, errCopyInProgress
}
defer cn.errRecover(&err)
// Check to see if we can use the "simpleQuery" interface, which is
@@ -1472,12 +1507,23 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i], rs.colFmts[i])
}
return
case 'T':
rs.colNames, rs.colFmts, rs.colTyps = parsePortalRowDescribe(&rs.rb)
return io.EOF
default:
errorf("unexpected message after execute: %q", t)
}
}
}
func (rs *rows) HasNextResultSet() bool {
return !rs.done
}
func (rs *rows) NextResultSet() error {
return nil
}
// QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be
// used as part of an SQL statement. For example:
//
@@ -1720,6 +1766,9 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
res, commandTag = cn.parseComplete(r.string())
case 'Z':
cn.processReadyForQuery(r)
if res == nil && err == nil {
err = errUnexpectedReady
}
return res, commandTag, err
case 'E':
err = parseError(r)
@@ -1728,6 +1777,9 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
cn.bad = true
errorf("unexpected %q after error %s", t, err)
}
if t == 'I' {
res = emptyRows
}
// ignore any results
default:
cn.bad = true

51
vendor/github.com/lib/pq/conn_test.go сгенерированный поставляемый
Просмотреть файл

@@ -5,6 +5,7 @@ import (
"database/sql/driver"
"fmt"
"io"
"net"
"os"
"reflect"
"strings"
@@ -385,10 +386,16 @@ func TestEmptyQuery(t *testing.T) {
db := openTestConn(t)
defer db.Close()
_, err := db.Exec("")
res, err := db.Exec("")
if err != nil {
t.Fatal(err)
}
if _, err := res.RowsAffected(); err != errNoRowsAffected {
t.Fatalf("expected %s, got %v", errNoRowsAffected, err)
}
if _, err := res.LastInsertId(); err != errNoLastInsertId {
t.Fatalf("expected %s, got %v", errNoLastInsertId, err)
}
rows, err := db.Query("")
if err != nil {
t.Fatal(err)
@@ -411,10 +418,16 @@ func TestEmptyQuery(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = stmt.Exec()
res, err = stmt.Exec()
if err != nil {
t.Fatal(err)
}
if _, err := res.RowsAffected(); err != errNoRowsAffected {
t.Fatalf("expected %s, got %v", errNoRowsAffected, err)
}
if _, err := res.LastInsertId(); err != errNoLastInsertId {
t.Fatalf("expected %s, got %v", errNoLastInsertId, err)
}
rows, err = stmt.Query()
if err != nil {
t.Fatal(err)
@@ -653,6 +666,40 @@ func TestBadConn(t *testing.T) {
}
}
// TestCloseBadConn tests that the underlying connection can be closed with
// Close after an error.
func TestCloseBadConn(t *testing.T) {
nc, err := net.Dial("tcp", "localhost:5432")
if err != nil {
t.Fatal(err)
}
cn := conn{c: nc}
func() {
defer cn.errRecover(&err)
panic(io.EOF)
}()
// Verify we can write before closing.
if _, err := nc.Write(nil); err != nil {
t.Fatal(err)
}
// First close should close the connection.
if err := cn.Close(); err != nil {
t.Fatal(err)
}
// Verify write after closing fails.
if _, err := nc.Write(nil); err == nil {
t.Fatal("expected error")
} else if !strings.Contains(err.Error(), "use of closed network connection") {
t.Fatalf("expected use of closed network connection error, got %s", err)
}
// Verify second close fails.
if err := cn.Close(); err == nil {
t.Fatal("expected error")
} else if !strings.Contains(err.Error(), "use of closed network connection") {
t.Fatalf("expected use of closed network connection error, got %s", err)
}
}
func TestErrorOnExec(t *testing.T) {
db := openTestConn(t)
defer db.Close()

2
vendor/github.com/lib/pq/copy.go сгенерированный поставляемый
Просмотреть файл

@@ -13,6 +13,7 @@ var (
errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY")
errCopyToNotSupported = errors.New("pq: COPY TO is not supported")
errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction")
errCopyInProgress = errors.New("pq: COPY in progress")
)
// CopyIn creates a COPY FROM statement which can be prepared with
@@ -258,6 +259,7 @@ func (ci *copyin) Close() (err error) {
}
<-ci.done
ci.cn.inCopy = false
if ci.isErrorSet() {
err = ci.err

23
vendor/github.com/lib/pq/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -89,8 +89,10 @@ provided connection parameters.
The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html
is supported, but on Windows PGPASSFILE must be specified explicitly.
Queries
database/sql does not dictate any specific format for parameter
markers in query strings, and pq uses the Postgres-native ordinal markers,
as shown above. The same marker can be reused for the same parameter:
@@ -114,8 +116,29 @@ For more details on RETURNING, see the Postgres documentation:
For additional instructions on querying see the documentation for the database/sql package.
Data Types
Parameters pass through driver.DefaultParameterConverter before they are handled
by this package. When the binary_parameters connection option is enabled,
[]byte values are sent directly to the backend as data in binary format.
This package returns the following types for values from the PostgreSQL backend:
- integer types smallint, integer, and bigint are returned as int64
- floating-point types real and double precision are returned as float64
- character types char, varchar, and text are returned as string
- temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time
- the boolean type is returned as bool
- the bytea type is returned as []byte
All other types are returned directly from the backend as []byte values in text format.
Errors
pq may return errors of type *pq.Error which can be interrogated for error details:
if err, ok := err.(*pq.Error); ok {

68
vendor/github.com/lib/pq/go18_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,68 @@
// +build go1.8
package pq
import "testing"
func TestMultipleSimpleQuery(t *testing.T) {
db := openTestConn(t)
defer db.Close()
rows, err := db.Query("select 1; set time zone default; select 2; select 3")
if err != nil {
t.Fatal(err)
}
defer rows.Close()
var i int
for rows.Next() {
if err := rows.Scan(&i); err != nil {
t.Fatal(err)
}
if i != 1 {
t.Fatalf("expected 1, got %d", i)
}
}
if !rows.NextResultSet() {
t.Fatal("expected more result sets", rows.Err())
}
for rows.Next() {
if err := rows.Scan(&i); err != nil {
t.Fatal(err)
}
if i != 2 {
t.Fatalf("expected 2, got %d", i)
}
}
// Make sure that if we ignore a result we can still query.
rows, err = db.Query("select 4; select 5")
if err != nil {
t.Fatal(err)
}
defer rows.Close()
for rows.Next() {
if err := rows.Scan(&i); err != nil {
t.Fatal(err)
}
if i != 4 {
t.Fatalf("expected 4, got %d", i)
}
}
if !rows.NextResultSet() {
t.Fatal("expected more result sets", rows.Err())
}
for rows.Next() {
if err := rows.Scan(&i); err != nil {
t.Fatal(err)
}
if i != 5 {
t.Fatalf("expected 5, got %d", i)
}
}
if rows.NextResultSet() {
t.Fatal("unexpected result set")
}
}

26
vendor/github.com/lib/pq/issues_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,26 @@
package pq
import "testing"
func TestIssue494(t *testing.T) {
db := openTestConn(t)
defer db.Close()
query := `CREATE TEMP TABLE t (i INT PRIMARY KEY)`
if _, err := db.Exec(query); err != nil {
t.Fatal(err)
}
txn, err := db.Begin()
if err != nil {
t.Fatal(err)
}
if _, err := txn.Prepare(CopyIn("t", "i")); err != nil {
t.Fatal(err)
}
if _, err := txn.Query("SELECT 1"); err == nil {
t.Fatal("expected error")
}
}

5
vendor/github.com/miekg/dns/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns) [![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns)
# Alternative (more granular) approach to a DNS library
@@ -50,6 +50,9 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://dnslookup.org
* https://github.com/looterz/grimd
* https://github.com/phamhongviet/serf-dns
* https://github.com/mehrdadrad/mylg
* https://github.com/bamarni/dockness
* https://github.com/fffaraz/microdns
Send pull request if you want to be listed here.

6
vendor/github.com/miekg/dns/client.go сгенерированный поставляемый
Просмотреть файл

@@ -39,7 +39,7 @@ type Client struct {
}
// Exchange performs a synchronous UDP query. It sends the message m to the address
// contained in a and waits for an reply. Exchange does not retry a failed query, nor
// contained in a and waits for a reply. Exchange does not retry a failed query, nor
// will it fall back to TCP in case of truncation.
// See client.Exchange for more information on setting larger buffer sizes.
func Exchange(m *Msg, a string) (r *Msg, err error) {
@@ -93,8 +93,8 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
return r, err
}
// Exchange performs an synchronous query. It sends the message m to the address
// contained in a and waits for an reply. Basic use pattern with a *dns.Client:
// Exchange performs a synchronous query. It sends the message m to the address
// contained in a and waits for a reply. Basic use pattern with a *dns.Client:
//
// c := new(dns.Client)
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")

44
vendor/github.com/miekg/dns/dane.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,44 @@
package dns
import (
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/hex"
"errors"
"io"
)
// CertificateToDANE converts a certificate to a hex string as used in the TLSA or SMIMEA records.
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
switch matchingType {
case 0:
switch selector {
case 0:
return hex.EncodeToString(cert.Raw), nil
case 1:
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
}
case 1:
h := sha256.New()
switch selector {
case 0:
io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil
}
case 2:
h := sha512.New()
switch selector {
case 0:
io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil
}
}
return "", errors.New("dns: bad MatchingType or Selector")
}

2
vendor/github.com/miekg/dns/dnssec_keyscan.go сгенерированный поставляемый
Просмотреть файл

@@ -14,7 +14,7 @@ import (
// NewPrivateKey returns a PrivateKey by parsing the string s.
// s should be in the same form of the BIND private key files.
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
if s[len(s)-1] != '\n' { // We need a closing newline
if s == "" || s[len(s)-1] != '\n' { // We need a closing newline
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
}
return k.ReadPrivateKey(strings.NewReader(s), "")

2
vendor/github.com/miekg/dns/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -203,7 +203,7 @@ RFC 6895 sets aside a range of type codes for private use. This range
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
can be used, before requesting an official type code from IANA.
see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more
see http://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
information.
EDNS0

14
vendor/github.com/miekg/dns/edns.go сгенерированный поставляемый
Просмотреть файл

@@ -128,8 +128,18 @@ func (rr *OPT) Do() bool {
}
// SetDo sets the DO (DNSSEC OK) bit.
func (rr *OPT) SetDo() {
rr.Hdr.Ttl |= _DO
// If we pass an argument, set the DO bit to that value.
// It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored.
func (rr *OPT) SetDo(do ...bool) {
if len(do) == 1 {
if do[0] {
rr.Hdr.Ttl |= _DO
} else {
rr.Hdr.Ttl &^= _DO
}
} else {
rr.Hdr.Ttl |= _DO
}
}
// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.

36
vendor/github.com/miekg/dns/edns_test.go сгенерированный поставляемый
Просмотреть файл

@@ -7,10 +7,46 @@ func TestOPTTtl(t *testing.T) {
e.Hdr.Name = "."
e.Hdr.Rrtype = TypeOPT
// verify the default setting of DO=0
if e.Do() {
t.Errorf("DO bit should be zero")
}
// There are 6 possible invocations of SetDo():
//
// 1. Starting with DO=0, using SetDo()
// 2. Starting with DO=0, using SetDo(true)
// 3. Starting with DO=0, using SetDo(false)
// 4. Starting with DO=1, using SetDo()
// 5. Starting with DO=1, using SetDo(true)
// 6. Starting with DO=1, using SetDo(false)
// verify that invoking SetDo() sets DO=1 (TEST #1)
e.SetDo()
if !e.Do() {
t.Errorf("DO bit should be non-zero")
}
// verify that using SetDo(true) works when DO=1 (TEST #5)
e.SetDo(true)
if !e.Do() {
t.Errorf("DO bit should still be non-zero")
}
// verify that we can use SetDo(false) to set DO=0 (TEST #6)
e.SetDo(false)
if e.Do() {
t.Errorf("DO bit should be zero")
}
// verify that if we call SetDo(false) when DO=0 that it is unchanged (TEST #3)
e.SetDo(false)
if e.Do() {
t.Errorf("DO bit should still be zero")
}
// verify that using SetDo(true) works for DO=0 (TEST #2)
e.SetDo(true)
if !e.Do() {
t.Errorf("DO bit should be non-zero")
}
// verify that using SetDo() works for DO=1 (TEST #4)
e.SetDo()
if !e.Do() {
t.Errorf("DO bit should be non-zero")

2
vendor/github.com/miekg/dns/msg.go сгенерированный поставляемый
Просмотреть файл

@@ -58,7 +58,7 @@ var (
ErrTruncated error = &Error{err: "failed to unpack truncated message"} // ErrTruncated indicates that we failed to unpack a truncated message. We unpacked as much as we had so Msg can still be used, if desired.
)
// Id, by default, returns a 16 bits random number to be used as a
// Id by default, returns a 16 bits random number to be used as a
// message id. The random provided should be good enough. This being a
// variable the function can be reassigned to a custom function.
// For instance, to make it return a static value:

21
vendor/github.com/miekg/dns/parse_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1375,6 +1375,27 @@ func TestParseTLSA(t *testing.T) {
}
}
func TestParseSMIMEA(t *testing.T) {
lt := map[string]string{
"2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t1 1 2 bd80f334566928fc18f58df7e4928c1886f48f71ca3fd41cd9b1854aca7c2180aaacad2819612ed68e7bd3701cc39be7f2529b017c0bc6a53e8fb3f0c7d48070": "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t1 1 2 bd80f334566928fc18f58df7e4928c1886f48f71ca3fd41cd9b1854aca7c2180aaacad2819612ed68e7bd3701cc39be7f2529b017c0bc6a53e8fb3f0c7d48070",
"2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t0 0 1 cdcf0fc66b182928c5217ddd42c826983f5a4b94160ee6c1c9be62d38199f710": "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t0 0 1 cdcf0fc66b182928c5217ddd42c826983f5a4b94160ee6c1c9be62d38199f710",
"2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8c26b251fa0c887ba4869f011a65f7e79967c2eb729f5b": "2e85e1db3e62be6ea._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8c26b251fa0c887ba4869f011a65f7e79967c2eb729f5b",
"2e85e1db3e62be6eb._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8 c26b251fa0c887ba4869f01 1a65f7e79967c2eb729f5b": "2e85e1db3e62be6eb._smimecert.example.com.\t3600\tIN\tSMIMEA\t3 0 2 499a1eda2af8828b552cdb9d80c3744a25872fddd73f3898d8e4afa3549595d2dd4340126e759566fe8c26b251fa0c887ba4869f011a65f7e79967c2eb729f5b",
}
for i, o := range lt {
rr, err := NewRR(i)
if err != nil {
t.Error("failed to parse RR: ", err)
continue
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", o, o, rr.String())
} else {
t.Logf("RR is OK: `%s'", rr.String())
}
}
}
func TestParseSSHFP(t *testing.T) {
lt := []string{
"test.example.org.\t300\tSSHFP\t1 2 (\n" +

4
vendor/github.com/miekg/dns/privaterr_test.go сгенерированный поставляемый
Просмотреть файл

@@ -7,7 +7,7 @@ import (
"github.com/miekg/dns"
)
const TypeISBN uint16 = 0x0F01
const TypeISBN uint16 = 0xFF00
// A crazy new RR type :)
type ISBN struct {
@@ -101,7 +101,7 @@ func TestPrivateByteSlice(t *testing.T) {
}
}
const TypeVERSION uint16 = 0x0F02
const TypeVERSION uint16 = 0xFF01
type VERSION struct {
x string

7
vendor/github.com/miekg/dns/scan.go сгенерированный поставляемый
Просмотреть файл

@@ -627,6 +627,7 @@ func zlexer(s *scan, c chan lex) {
if stri > 0 {
l.value = zString
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
debug.Printf("[4 %+v]", l.token)
c <- l
@@ -663,6 +664,7 @@ func zlexer(s *scan, c chan lex) {
owner = true
l.value = zNewline
l.token = "\n"
l.tokenUpper = l.token
l.length = 1
l.comment = string(com[:comi])
debug.Printf("[3 %+v %+v]", l.token, l.comment)
@@ -696,6 +698,7 @@ func zlexer(s *scan, c chan lex) {
}
l.value = zNewline
l.token = "\n"
l.tokenUpper = l.token
l.length = 1
debug.Printf("[1 %+v]", l.token)
c <- l
@@ -740,6 +743,7 @@ func zlexer(s *scan, c chan lex) {
if stri != 0 {
l.value = zString
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
debug.Printf("[%+v]", l.token)
@@ -750,6 +754,7 @@ func zlexer(s *scan, c chan lex) {
// send quote itself as separate token
l.value = zQuote
l.token = "\""
l.tokenUpper = l.token
l.length = 1
c <- l
quote = !quote
@@ -775,6 +780,7 @@ func zlexer(s *scan, c chan lex) {
brace--
if brace < 0 {
l.token = "extra closing brace"
l.tokenUpper = l.token
l.err = true
debug.Printf("[%+v]", l.token)
c <- l
@@ -799,6 +805,7 @@ func zlexer(s *scan, c chan lex) {
if stri > 0 {
// Send remainder
l.token = string(str[:stri])
l.tokenUpper = strings.ToUpper(l.token)
l.length = stri
l.value = zString
debug.Printf("[%+v]", l.token)

36
vendor/github.com/miekg/dns/scan_rr.go сгенерированный поставляемый
Просмотреть файл

@@ -1746,6 +1746,41 @@ func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
return rr, nil, c1
}
func setSMIMEA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
rr := new(SMIMEA)
rr.Hdr = h
l := <-c
if l.length == 0 {
return rr, nil, l.comment
}
i, e := strconv.Atoi(l.token)
if e != nil || l.err {
return nil, &ParseError{f, "bad SMIMEA Usage", l}, ""
}
rr.Usage = uint8(i)
<-c // zBlank
l = <-c
i, e = strconv.Atoi(l.token)
if e != nil || l.err {
return nil, &ParseError{f, "bad SMIMEA Selector", l}, ""
}
rr.Selector = uint8(i)
<-c // zBlank
l = <-c
i, e = strconv.Atoi(l.token)
if e != nil || l.err {
return nil, &ParseError{f, "bad SMIMEA MatchingType", l}, ""
}
rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t
s, e2, c1 := endingToString(c, "bad SMIMEA Certificate", f)
if e2 != nil {
return nil, e2, c1
}
rr.Certificate = s
return rr, nil, c1
}
func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
rr := new(RFC3597)
rr.Hdr = h
@@ -2128,6 +2163,7 @@ var typeToparserFunc = map[uint16]parserFunc{
TypeRP: {setRP, false},
TypeRRSIG: {setRRSIG, true},
TypeRT: {setRT, false},
TypeSMIMEA: {setSMIMEA, true},
TypeSOA: {setSOA, false},
TypeSPF: {setSPF, true},
TypeSRV: {setSRV, false},

2
vendor/github.com/miekg/dns/server.go сгенерированный поставляемый
Просмотреть файл

@@ -147,7 +147,7 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
b[i] |= ('a' - 'A')
}
}
if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
if h, ok := mux.z[string(b[:l])]; ok { // causes garbage, might want to change the map key
if t != TypeDS {
return h
}

47
vendor/github.com/miekg/dns/smimea.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,47 @@
package dns
import (
"crypto/sha256"
"crypto/x509"
"encoding/hex"
)
// Sign creates a SMIMEA record from an SSL certificate.
func (r *SMIMEA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
r.Hdr.Rrtype = TypeSMIMEA
r.Usage = uint8(usage)
r.Selector = uint8(selector)
r.MatchingType = uint8(matchingType)
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
if err != nil {
return err
}
return nil
}
// Verify verifies a SMIMEA record against an SSL certificate. If it is OK
// a nil error is returned.
func (r *SMIMEA) Verify(cert *x509.Certificate) error {
c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
if err != nil {
return err // Not also ErrSig?
}
if r.Certificate == c {
return nil
}
return ErrSig // ErrSig, really?
}
// SIMEAName returns the ownername of a SMIMEA resource record as per the
// format specified in RFC 'draft-ietf-dane-smime-12' Section 2 and 3
func SMIMEAName(email_address string, domain_name string) (string, error) {
hasher := sha256.New()
hasher.Write([]byte(email_address))
// RFC Section 3: "The local-part is hashed using the SHA2-256
// algorithm with the hash truncated to 28 octets and
// represented in its hexadecimal representation to become the
// left-most label in the prepared domain name"
return hex.EncodeToString(hasher.Sum(nil)[:28]) + "." + "_smimecert." + domain_name, nil
}

39
vendor/github.com/miekg/dns/tlsa.go сгенерированный поставляемый
Просмотреть файл

@@ -1,50 +1,11 @@
package dns
import (
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/hex"
"errors"
"io"
"net"
"strconv"
)
// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
switch matchingType {
case 0:
switch selector {
case 0:
return hex.EncodeToString(cert.Raw), nil
case 1:
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
}
case 1:
h := sha256.New()
switch selector {
case 0:
io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil
}
case 2:
h := sha512.New()
switch selector {
case 0:
io.WriteString(h, string(cert.Raw))
return hex.EncodeToString(h.Sum(nil)), nil
case 1:
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
return hex.EncodeToString(h.Sum(nil)), nil
}
}
return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
}
// Sign creates a TLSA record from an SSL certificate.
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
r.Hdr.Rrtype = TypeTLSA

45
vendor/github.com/miekg/dns/types.go сгенерированный поставляемый
Просмотреть файл

@@ -70,6 +70,7 @@ const (
TypeNSEC3 uint16 = 50
TypeNSEC3PARAM uint16 = 51
TypeTLSA uint16 = 52
TypeSMIMEA uint16 = 53
TypeHIP uint16 = 55
TypeNINFO uint16 = 56
TypeRKEY uint16 = 57
@@ -1047,6 +1048,28 @@ func (rr *TLSA) String() string {
" " + rr.Certificate
}
type SMIMEA struct {
Hdr RR_Header
Usage uint8
Selector uint8
MatchingType uint8
Certificate string `dns:"hex"`
}
func (rr *SMIMEA) String() string {
s := rr.Hdr.String() +
strconv.Itoa(int(rr.Usage)) +
" " + strconv.Itoa(int(rr.Selector)) +
" " + strconv.Itoa(int(rr.MatchingType))
// Every Nth char needs a space on this output. If we output
// this as one giant line, we can't read it can in because in some cases
// the cert length overflows scan.maxTok (2048).
sx := splitN(rr.Certificate, 1024) // conservative value here
s += " " + strings.Join(sx, " ")
return s
}
type HIP struct {
Hdr RR_Header
HitLength uint8
@@ -1247,3 +1270,25 @@ func copyIP(ip net.IP) net.IP {
copy(p, ip)
return p
}
// SplitN splits a string into N sized string chunks.
// This might become an exported function once.
func splitN(s string, n int) []string {
if len(s) < n {
return []string{s}
}
sx := []string{}
p, i := 0, n
for {
if i <= len(s) {
sx = append(sx, s[p:i])
} else {
sx = append(sx, s[p:])
break
}
p, i = p+n, i+n
}
return sx
}

32
vendor/github.com/miekg/dns/types_test.go сгенерированный поставляемый
Просмотреть файл

@@ -40,3 +40,35 @@ func TestCmToM(t *testing.T) {
t.Error("9, 9")
}
}
func TestSplitN(t *testing.T) {
xs := splitN("abc", 5)
if len(xs) != 1 && xs[0] != "abc" {
t.Errorf("Failure to split abc")
}
s := ""
for i := 0; i < 255; i++ {
s += "a"
}
xs = splitN(s, 255)
if len(xs) != 1 && xs[0] != s {
t.Errorf("failure to split 255 char long string")
}
s += "b"
xs = splitN(s, 255)
if len(xs) != 2 || xs[1] != "b" {
t.Errorf("failure to split 256 char long string: %d", len(xs))
}
// Make s longer
for i := 0; i < 255; i++ {
s += "a"
}
xs = splitN(s, 255)
if len(xs) != 3 || xs[2] != "a" {
t.Errorf("failure to split 510 char long string: %d", len(xs))
}
}

65
vendor/github.com/miekg/dns/zmsg.go сгенерированный поставляемый
Просмотреть файл

@@ -1085,6 +1085,32 @@ func (rr *SIG) pack(msg []byte, off int, compression map[string]int, compress bo
return off, nil
}
func (rr *SMIMEA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
return off, err
}
headerEnd := off
off, err = packUint8(rr.Usage, msg, off)
if err != nil {
return off, err
}
off, err = packUint8(rr.Selector, msg, off)
if err != nil {
return off, err
}
off, err = packUint8(rr.MatchingType, msg, off)
if err != nil {
return off, err
}
off, err = packStringHex(rr.Certificate, msg, off)
if err != nil {
return off, err
}
rr.Header().Rdlength = uint16(off - headerEnd)
return off, nil
}
func (rr *SOA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
@@ -2907,6 +2933,44 @@ func unpackSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
return rr, off, err
}
func unpackSMIMEA(h RR_Header, msg []byte, off int) (RR, int, error) {
rr := new(SMIMEA)
rr.Hdr = h
if noRdata(h) {
return rr, off, nil
}
var err error
rdStart := off
_ = rdStart
rr.Usage, off, err = unpackUint8(msg, off)
if err != nil {
return rr, off, err
}
if off == len(msg) {
return rr, off, nil
}
rr.Selector, off, err = unpackUint8(msg, off)
if err != nil {
return rr, off, err
}
if off == len(msg) {
return rr, off, nil
}
rr.MatchingType, off, err = unpackUint8(msg, off)
if err != nil {
return rr, off, err
}
if off == len(msg) {
return rr, off, nil
}
rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
if err != nil {
return rr, off, err
}
return rr, off, err
}
func unpackSOA(h RR_Header, msg []byte, off int) (RR, int, error) {
rr := new(SOA)
rr.Hdr = h
@@ -3447,6 +3511,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
TypeRRSIG: unpackRRSIG,
TypeRT: unpackRT,
TypeSIG: unpackSIG,
TypeSMIMEA: unpackSMIMEA,
TypeSOA: unpackSOA,
TypeSPF: unpackSPF,
TypeSRV: unpackSRV,

14
vendor/github.com/miekg/dns/ztypes.go сгенерированный поставляемый
Просмотреть файл

@@ -62,6 +62,7 @@ var TypeToRR = map[uint16]func() RR{
TypeRRSIG: func() RR { return new(RRSIG) },
TypeRT: func() RR { return new(RT) },
TypeSIG: func() RR { return new(SIG) },
TypeSMIMEA: func() RR { return new(SMIMEA) },
TypeSOA: func() RR { return new(SOA) },
TypeSPF: func() RR { return new(SPF) },
TypeSRV: func() RR { return new(SRV) },
@@ -141,6 +142,7 @@ var TypeToString = map[uint16]string{
TypeRT: "RT",
TypeReserved: "Reserved",
TypeSIG: "SIG",
TypeSMIMEA: "SMIMEA",
TypeSOA: "SOA",
TypeSPF: "SPF",
TypeSRV: "SRV",
@@ -213,6 +215,7 @@ func (rr *RP) Header() *RR_Header { return &rr.Hdr }
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
func (rr *SMIMEA) Header() *RR_Header { return &rr.Hdr }
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
@@ -514,6 +517,14 @@ func (rr *RT) len() int {
l += len(rr.Host) + 1
return l
}
func (rr *SMIMEA) len() int {
l := rr.Hdr.len()
l += 1 // Usage
l += 1 // Selector
l += 1 // MatchingType
l += len(rr.Certificate)/2 + 1
return l
}
func (rr *SOA) len() int {
l := rr.Hdr.len()
l += len(rr.Ns) + 1
@@ -780,6 +791,9 @@ func (rr *RRSIG) copy() RR {
func (rr *RT) copy() RR {
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
}
func (rr *SMIMEA) copy() RR {
return &SMIMEA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
}
func (rr *SOA) copy() RR {
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
}

2
vendor/github.com/nicksnyder/go-i18n/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -5,4 +5,6 @@ go:
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7
- tip

230
vendor/github.com/nicksnyder/go-i18n/goi18n/constants_command.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,230 @@
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"text/template"
"unicode"
"github.com/nicksnyder/go-i18n/i18n/bundle"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
)
type constantsCommand struct {
translationFiles []string
packageName string
outdir string
}
type templateConstants struct {
ID string
Name string
Comments []string
}
type templateHeader struct {
PackageName string
Constants []templateConstants
}
var constTemplate = template.Must(template.New("").Parse(`// DON'T CHANGE THIS FILE MANUALLY
// This file was generated using the command:
// $ goi18n constants
package {{.PackageName}}
{{range .Constants}}
// {{.Name}} is the identifier for the following localizable string template(s):{{range .Comments}}
// {{.}}{{end}}
const {{.Name}} = "{{.ID}}"
{{end}}`))
func (cc *constantsCommand) execute() error {
if len(cc.translationFiles) != 1 {
return fmt.Errorf("need one translation file")
}
bundle := bundle.New()
if err := bundle.LoadTranslationFile(cc.translationFiles[0]); err != nil {
return fmt.Errorf("failed to load translation file %s because %s\n", cc.translationFiles[0], err)
}
translations := bundle.Translations()
lang := translations[bundle.LanguageTags()[0]]
// create an array of id to organize
keys := make([]string, len(lang))
i := 0
for id := range lang {
keys[i] = id
i++
}
sort.Strings(keys)
tmpl := &templateHeader{
PackageName: cc.packageName,
Constants: make([]templateConstants, len(keys)),
}
for i, id := range keys {
tmpl.Constants[i].ID = id
tmpl.Constants[i].Name = toCamelCase(id)
tmpl.Constants[i].Comments = toComments(lang[id])
}
filename := filepath.Join(cc.outdir, cc.packageName+".go")
f, err := os.Create(filename)
if err != nil {
return fmt.Errorf("failed to create file %s because %s", filename, err)
}
defer f.Close()
if err = constTemplate.Execute(f, tmpl); err != nil {
return fmt.Errorf("failed to write file %s because %s", filename, err)
}
return nil
}
func (cc *constantsCommand) parse(arguments []string) {
flags := flag.NewFlagSet("constants", flag.ExitOnError)
flags.Usage = usageConstants
packageName := flags.String("package", "R", "")
outdir := flags.String("outdir", ".", "")
flags.Parse(arguments)
cc.translationFiles = flags.Args()
cc.packageName = *packageName
cc.outdir = *outdir
}
func (cc *constantsCommand) SetArgs(args []string) {
cc.translationFiles = args
}
func usageConstants() {
fmt.Printf(`Generate constant file from translation file.
Usage:
goi18n constants [options] [file]
Translation files:
A translation file contains the strings and translations for a single language.
Translation file names must have a suffix of a supported format (e.g. .json) and
contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
Options:
-package name
goi18n generates the constant file under the package name.
Default: R
-outdir directory
goi18n writes the constant file to this directory.
Default: .
`)
os.Exit(1)
}
// commonInitialisms is a set of common initialisms.
// Only add entries that are highly unlikely to be non-initialisms.
// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
// https://github.com/golang/lint/blob/master/lint.go
var commonInitialisms = map[string]bool{
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XSRF": true,
"XSS": true,
}
func toCamelCase(id string) string {
var result string
r := regexp.MustCompile(`[\-\.\_\s]`)
words := r.Split(id, -1)
for _, w := range words {
upper := strings.ToUpper(w)
if commonInitialisms[upper] {
result += upper
continue
}
if len(w) > 0 {
u := []rune(w)
u[0] = unicode.ToUpper(u[0])
result += string(u)
}
}
return result
}
func toComments(trans translation.Translation) []string {
var result []string
data := trans.MarshalInterface().(map[string]interface{})
t := data["translation"]
switch v := reflect.ValueOf(t); v.Kind() {
case reflect.Map:
for _, k := range []language.Plural{"zero", "one", "two", "few", "many", "other"} {
vt := v.MapIndex(reflect.ValueOf(k))
if !vt.IsValid() {
continue
}
result = append(result, string(k)+": "+strconv.Quote(fmt.Sprint(vt.Interface())))
}
default:
result = append(result, strconv.Quote(fmt.Sprint(t)))
}
return result
}

42
vendor/github.com/nicksnyder/go-i18n/goi18n/constants_command_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,42 @@
package main
import "testing"
func TestConstantsExecute(t *testing.T) {
resetDir(t, "testdata/output")
cc := &constantsCommand{
translationFiles: []string{"testdata/input/en-us.constants.json"},
packageName: "R",
outdir: "testdata/output",
}
if err := cc.execute(); err != nil {
t.Fatal(err)
}
expectEqualFiles(t, "testdata/output/R.go", "testdata/expected/R.go")
}
func TestToCamelCase(t *testing.T) {
expectEqual := func(test, expected string) {
result := toCamelCase(test)
if result != expected {
t.Fatalf("failed toCamelCase the test %s was expected %s but the result was %s", test, expected, result)
}
}
expectEqual("", "")
expectEqual("a", "A")
expectEqual("_", "")
expectEqual("__code__", "Code")
expectEqual("test", "Test")
expectEqual("test_one", "TestOne")
expectEqual("test.two", "TestTwo")
expectEqual("test_alpha_beta", "TestAlphaBeta")
expectEqual("word word", "WordWord")
expectEqual("test_id", "TestID")
expectEqual("tcp_name", "TCPName")
expectEqual("こんにちは", "こんにちは")
expectEqual("test_a", "TestA")
}

38
vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -5,11 +5,22 @@
//
// Help documentation:
//
// goi18n formats and merges translation files.
// goi18n manages translation files.
//
// Usage:
//
// goi18n [options] [files...]
// goi18n merge Merge translation files
// goi18n constants Generate constant file from translation file
//
// For more details execute:
//
// goi18n [command] -help
//
// Merge translation files.
//
// Usage:
//
// goi18n merge [options] [files...]
//
// Translation files:
//
@@ -56,4 +67,27 @@
// Supported formats: json, yaml
// Default: json
//
// Generate constant file from translation file.
//
// Usage:
//
// goi18n constants [options] [file]
//
// Translation files:
//
// A translation file contains the strings and translations for a single language.
//
// Translation file names must have a suffix of a supported format (e.g. .json) and
// contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
//
// Options:
//
// -package name
// goi18n generates the constant file under the package name.
// Default: R
//
// -outdir directory
// goi18n writes the constant file to this directory.
// Default: .
//
package main

4
vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh сгенерированный поставляемый
Просмотреть файл

@@ -6,5 +6,7 @@ echo "// goi18n -help" >> doc.go
echo "//" >> doc.go
echo "// Help documentation:" >> doc.go
echo "//" >> doc.go
goi18n -help | sed -e 's/^/\/\/ /' >> doc.go
goi18n | sed -e 's/^/\/\/ /' >> doc.go
goi18n merge -help | sed -e 's/^/\/\/ /' >> doc.go
goi18n constants -help | sed -e 's/^/\/\/ /' >> doc.go
echo "package main" >> doc.go

101
vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go сгенерированный поставляемый
Просмотреть файл

@@ -6,77 +6,50 @@ import (
"os"
)
func usage() {
fmt.Printf(`goi18n formats and merges translation files.
Usage:
goi18n [options] [files...]
Translation files:
A translation file contains the strings and translations for a single language.
Translation file names must have a suffix of a supported format (e.g. .json) and
contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
For each language represented by at least one input translation file, goi18n will produce 2 output files:
xx-yy.all.format
This file contains all strings for the language (translated and untranslated).
Use this file when loading strings at runtime.
xx-yy.untranslated.format
This file contains the strings that have not been translated for this language.
The translations for the strings in this file will be extracted from the source language.
After they are translated, merge them back into xx-yy.all.format using goi18n.
Merging:
goi18n will merge multiple translation files for the same language.
Duplicate translations will be merged into the existing translation.
Non-empty fields in the duplicate translation will overwrite those fields in the existing translation.
Empty fields in the duplicate translation are ignored.
Adding a new language:
To produce translation files for a new language, create an empty translation file with the
appropriate name and pass it in to goi18n.
Options:
-sourceLanguage tag
goi18n uses the strings from this language to seed the translations for other languages.
Default: en-us
-outdir directory
goi18n writes the output translation files to this directory.
Default: .
-format format
goi18n encodes the output translation files in this format.
Supported formats: json, yaml
Default: json
`)
os.Exit(1)
type command interface {
execute() error
parse(arguments []string)
}
func main() {
flag.Usage = usage
sourceLanguage := flag.String("sourceLanguage", "en-us", "")
outdir := flag.String("outdir", ".", "")
format := flag.String("format", "json", "")
flag.Parse()
mc := &mergeCommand{
translationFiles: flag.Args(),
sourceLanguageTag: *sourceLanguage,
outdir: *outdir,
format: *format,
if len(os.Args) == 1 {
usage()
}
if err := mc.execute(); err != nil {
var cmd command
switch os.Args[1] {
case "merge":
cmd = &mergeCommand{}
cmd.parse(os.Args[2:])
case "constants":
cmd = &constantsCommand{}
cmd.parse(os.Args[2:])
default:
cmd = &mergeCommand{}
cmd.parse(os.Args[1:])
}
if err := cmd.execute(); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}
func usage() {
fmt.Printf(`goi18n manages translation files.
Usage:
goi18n merge Merge translation files
goi18n constants Generate constant file from translation file
For more details execute:
goi18n [command] -help
`)
os.Exit(1)
}

Просмотреть файл

@@ -2,23 +2,26 @@ package main
import (
"encoding/json"
"flag"
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"gopkg.in/yaml.v2"
"github.com/nicksnyder/go-i18n/i18n/bundle"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
)
type mergeCommand struct {
translationFiles []string
sourceLanguageTag string
outdir string
format string
translationFiles []string
sourceLanguage string
outdir string
format string
}
func (mc *mergeCommand) execute() error {
@@ -26,8 +29,8 @@ func (mc *mergeCommand) execute() error {
return fmt.Errorf("need at least one translation file to parse")
}
if lang := language.Parse(mc.sourceLanguageTag); lang == nil {
return fmt.Errorf("invalid source locale: %s", mc.sourceLanguageTag)
if lang := language.Parse(mc.sourceLanguage); lang == nil {
return fmt.Errorf("invalid source locale: %s", mc.sourceLanguage)
}
marshal, err := newMarshalFunc(mc.format)
@@ -43,7 +46,7 @@ func (mc *mergeCommand) execute() error {
}
translations := bundle.Translations()
sourceLanguageTag := language.NormalizeTag(mc.sourceLanguageTag)
sourceLanguageTag := language.NormalizeTag(mc.sourceLanguage)
sourceTranslations := translations[sourceLanguageTag]
if sourceTranslations == nil {
return fmt.Errorf("no translations found for source locale %s", sourceLanguageTag)
@@ -78,6 +81,26 @@ func (mc *mergeCommand) execute() error {
return nil
}
func (mc *mergeCommand) parse(arguments []string) {
flags := flag.NewFlagSet("merge", flag.ExitOnError)
flags.Usage = usageMerge
sourceLanguage := flags.String("sourceLanguage", "en-us", "")
outdir := flags.String("outdir", ".", "")
format := flags.String("format", "json", "")
flags.Parse(arguments)
mc.translationFiles = flags.Args()
mc.sourceLanguage = *sourceLanguage
mc.outdir = *outdir
mc.format = *format
}
func (mc *mergeCommand) SetArgs(args []string) {
mc.translationFiles = args
}
type marshalFunc func(interface{}) ([]byte, error)
func (mc *mergeCommand) writeFile(label string, translations []translation.Translation, localeID string, marshal marshalFunc) error {
@@ -125,3 +148,59 @@ func marshalInterface(translations []translation.Translation) []interface{} {
}
return mi
}
func usageMerge() {
fmt.Printf(`Merge translation files.
Usage:
goi18n merge [options] [files...]
Translation files:
A translation file contains the strings and translations for a single language.
Translation file names must have a suffix of a supported format (e.g. .json) and
contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
For each language represented by at least one input translation file, goi18n will produce 2 output files:
xx-yy.all.format
This file contains all strings for the language (translated and untranslated).
Use this file when loading strings at runtime.
xx-yy.untranslated.format
This file contains the strings that have not been translated for this language.
The translations for the strings in this file will be extracted from the source language.
After they are translated, merge them back into xx-yy.all.format using goi18n.
Merging:
goi18n will merge multiple translation files for the same language.
Duplicate translations will be merged into the existing translation.
Non-empty fields in the duplicate translation will overwrite those fields in the existing translation.
Empty fields in the duplicate translation are ignored.
Adding a new language:
To produce translation files for a new language, create an empty translation file with the
appropriate name and pass it in to goi18n.
Options:
-sourceLanguage tag
goi18n uses the strings from this language to seed the translations for other languages.
Default: en-us
-outdir directory
goi18n writes the output translation files to this directory.
Default: .
-format format
goi18n encodes the output translation files in this format.
Supported formats: json, yaml
Default: json
`)
os.Exit(1)
}

Просмотреть файл

@@ -33,10 +33,10 @@ func testMergeExecute(t *testing.T, files []string) {
resetDir(t, "testdata/output")
mc := &mergeCommand{
translationFiles: files,
sourceLanguageTag: "en-us",
outdir: "testdata/output",
format: "json",
translationFiles: files,
sourceLanguage: "en-us",
outdir: "testdata/output",
format: "json",
}
if err := mc.execute(); err != nil {
t.Fatal(err)

38
vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/R.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,38 @@
// DON'T CHANGE THIS FILE MANUALLY
// This file was generated using the command:
// $ goi18n constants
package R
// DDays is the identifier for the following localizable string template(s):
// one: "{{.Count}} day"
// other: "{{.Count}} days"
const DDays = "d_days"
// MyHeightInMeters is the identifier for the following localizable string template(s):
// one: "I am {{.Count}} meter tall."
// other: "I am {{.Count}} meters tall."
const MyHeightInMeters = "my_height_in_meters"
// PersonGreeting is the identifier for the following localizable string template(s):
// "Hello {{.Person}}"
const PersonGreeting = "person_greeting"
// PersonUnreadEmailCount is the identifier for the following localizable string template(s):
// one: "{{.Person}} has {{.Count}} unread email."
// other: "{{.Person}} has {{.Count}} unread emails."
const PersonUnreadEmailCount = "person_unread_email_count"
// PersonUnreadEmailCountTimeframe is the identifier for the following localizable string template(s):
// one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
// other: "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
const PersonUnreadEmailCountTimeframe = "person_unread_email_count_timeframe"
// ProgramGreeting is the identifier for the following localizable string template(s):
// "Hello world"
const ProgramGreeting = "program_greeting"
// YourUnreadEmailCount is the identifier for the following localizable string template(s):
// one: "You have {{.Count}} unread email."
// other: "You have {{.Count}} unread emails."
const YourUnreadEmailCount = "your_unread_email_count"

45
vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.constants.json сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,45 @@
[
{
"id": "d_days",
"translation": {
"one": "{{.Count}} day",
"other": "{{.Count}} days"
}
},
{
"id": "my_height_in_meters",
"translation": {
"one": "I am {{.Count}} meter tall.",
"other": "I am {{.Count}} meters tall."
}
},
{
"id": "person_greeting",
"translation": "Hello {{.Person}}"
},
{
"id": "person_unread_email_count",
"translation": {
"one": "{{.Person}} has {{.Count}} unread email.",
"other": "{{.Person}} has {{.Count}} unread emails."
}
},
{
"id": "person_unread_email_count_timeframe",
"translation": {
"one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.",
"other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
}
},
{
"id": "program_greeting",
"translation": "Hello world"
},
{
"id": "your_unread_email_count",
"translation": {
"one": "You have {{.Count}} unread email.",
"other": "You have {{.Count}} unread emails."
}
}
]

5
vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go сгенерированный поставляемый
Просмотреть файл

@@ -260,6 +260,11 @@ func (b *Bundle) translate(lang *language.Language, translationID string, args .
dataMap["Count"] = count
data = dataMap
}
} else {
dataMap := toMap(data)
if c, ok := dataMap["Count"]; ok {
count = c
}
}
p, _ := lang.Plural(count)

20
vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go сгенерированный поставляемый
Просмотреть файл

@@ -270,6 +270,26 @@ func BenchmarkTranslatePluralWithMap(b *testing.B) {
}
}
func BenchmarkTranslatePluralWithMapAndCountField(b *testing.B) {
data := map[string]interface{}{
"Person": "Bob",
"Count": 26,
}
translationTemplate := map[string]interface{}{
"one": "{{.Person}} is {{.Count}} year old.",
"other": "{{.Person}} is {{.Count}} years old.",
}
expected := "Bob is 26 years old."
tf := createBenchmarkTranslateFunc(b, translationTemplate, nil, expected)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tf(data)
}
}
func BenchmarkTranslatePluralWithStruct(b *testing.B) {
data := struct{ Person string }{Person: "Bob"}
tf := createBenchmarkPluralTranslateFunc(b)

34
vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go сгенерированный поставляемый
Просмотреть файл

@@ -30,6 +30,15 @@ func Example() {
fmt.Println(T("person_unread_email_count", 1, bobStruct))
fmt.Println(T("person_unread_email_count", 2, bobStruct))
type Count struct{ Count int }
fmt.Println(T("your_unread_email_count", Count{0}))
fmt.Println(T("your_unread_email_count", Count{1}))
fmt.Println(T("your_unread_email_count", Count{2}))
fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": 0}))
fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": "1"}))
fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": "3.14"}))
fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
"Person": "Bob",
"Timeframe": T("d_days", 0),
@@ -43,6 +52,22 @@ func Example() {
"Timeframe": T("d_days", 2),
}))
fmt.Println(T("person_unread_email_count_timeframe", 1, map[string]interface{}{
"Count": 30,
"Person": "Bob",
"Timeframe": T("d_days", 0),
}))
fmt.Println(T("person_unread_email_count_timeframe", 2, map[string]interface{}{
"Count": 20,
"Person": "Bob",
"Timeframe": T("d_days", 1),
}))
fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
"Count": 10,
"Person": "Bob",
"Timeframe": T("d_days", 2),
}))
// Output:
// Hello world
// Hello Bob
@@ -57,7 +82,16 @@ func Example() {
// Bob has 0 unread emails.
// Bob has 1 unread email.
// Bob has 2 unread emails.
// You have 0 unread emails.
// You have 1 unread email.
// You have 2 unread emails.
// You have 0 unread emails.
// You have 1 unread email.
// You have 3.14 unread emails.
// Bob has 3 unread emails in the past 0 days.
// Bob has 3 unread emails in the past 1 day.
// Bob has 3 unread emails in the past 2 days.
// Bob has 1 unread email in the past 0 days.
// Bob has 2 unread emails in the past 1 day.
// Bob has 3 unread emails in the past 2 days.
}

10
vendor/github.com/nicksnyder/go-i18n/i18n/i18n.go сгенерированный поставляемый
Просмотреть файл

@@ -69,9 +69,15 @@ import (
// If translationID is a non-plural form, then the first variadic argument may be a map[string]interface{}
// or struct that contains template data.
//
// If translationID is a plural form, then the first variadic argument must be an integer type
// If translationID is a plural form, the function accepts two parameter signatures
// 1. T(count int, data struct{})
// The first variadic argument must be an integer type
// (int, int8, int16, int32, int64) or a float formatted as a string (e.g. "123.45").
// The second variadic argument may be a map[string]interface{} or struct that contains template data.
// The second variadic argument may be a map[string]interface{} or struct{} that contains template data.
// 2. T(data struct{})
// data must be a struct{} or map[string]interface{} that contains a Count field and the template data,
// Count field must be an integer type (int, int8, int16, int32, int64)
// or a float formatted as a string (e.g. "123.45").
type TranslateFunc func(translationID string, args ...interface{}) string
// IdentityTfunc returns a TranslateFunc that always returns the translationID passed to it.

25
vendor/github.com/rsc/letsencrypt/README сгенерированный поставляемый
Просмотреть файл

@@ -7,6 +7,31 @@ servers that can prove control over the given domain's DNS records or the
servers pointed at by those records.
Warning
Like any other random code you find on the internet, this package should not
be relied upon in important, production systems without thorough testing to
ensure that it meets your needs.
In the long term you should be using
https://golang.org/x/crypto/acme/autocert instead of this package. Send
improvements there, not here.
This is a package that I wrote for my own personal web sites (swtch.com,
rsc.io) in a hurry when my paid-for SSL certificate was expiring. It has no
tests, has barely been used, and there is some anecdotal evidence that it
does not properly renew certificates in a timely fashion, so servers that
run for more than 3 months may run into trouble. I don't run this code
anymore: to simplify maintenance, I moved the sites off of Ubuntu VMs and
onto Google App Engine, configured with inexpensive long-term certificates
purchased from cheapsslsecurity.com.
This package was interesting primarily as an example of how simple the API
for using LetsEncrypt.org could be made, in contrast to the low-level
implementations that existed at the time. In that respect, it helped inform
the design of the golang.org/x/crypto/acme/autocert package.
Quick Start
A complete HTTP/HTTPS web server using TLS certificates from

24
vendor/github.com/rsc/letsencrypt/lets.go сгенерированный поставляемый
Просмотреть файл

@@ -8,6 +8,30 @@
// that can prove control over the given domain's DNS records or
// the servers pointed at by those records.
//
// Warning
//
// Like any other random code you find on the internet, this package should
// not be relied upon in important, production systems without thorough testing
// to ensure that it meets your needs.
//
// In the long term you should be using
// https://golang.org/x/crypto/acme/autocert instead of this package.
// Send improvements there, not here.
//
// This is a package that I wrote for my own personal web sites (swtch.com, rsc.io)
// in a hurry when my paid-for SSL certificate was expiring. It has no tests,
// has barely been used, and there is some anecdotal evidence that it does
// not properly renew certificates in a timely fashion, so servers that run for
// more than 3 months may run into trouble.
// I don't run this code anymore: to simplify maintenance, I moved the sites
// off of Ubuntu VMs and onto Google App Engine, configured with inexpensive
// long-term certificates purchased from cheapsslsecurity.com.
//
// This package was interesting primarily as an example of how simple the API
// for using LetsEncrypt.org could be made, in contrast to the low-level
// implementations that existed at the time. In that respect, it helped inform
// the design of the golang.org/x/crypto/acme/autocert package.
//
// Quick Start
//
// A complete HTTP/HTTPS web server using TLS certificates from LetsEncrypt.org,

4
vendor/github.com/xenolf/lego/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -3,6 +3,10 @@ go:
- 1.6.3
- 1.7
- tip
services:
- memcached
env:
- MEMCACHED_HOSTS=localhost:11211
install:
- go get -t ./...
script:

2
vendor/github.com/xenolf/lego/Dockerfile сгенерированный поставляемый
Просмотреть файл

@@ -7,7 +7,7 @@ RUN apk update && apk add ca-certificates go git && \
go get -u github.com/xenolf/lego && \
cd /go/src/github.com/xenolf/lego && \
go build -o /usr/bin/lego . && \
apk del ca-certificates go git && \
apk del go git && \
rm -rf /var/cache/apk/* && \
rm -rf /go

65
vendor/github.com/xenolf/lego/acme/client.go сгенерированный поставляемый
Просмотреть файл

@@ -97,7 +97,7 @@ func NewClient(caDirURL string, user User, keyType KeyType) (*Client, error) {
return &Client{directory: dir, user: user, jws: jws, keyType: keyType, solvers: solvers}, nil
}
// SetChallengeProvider specifies a custom provider that will make the solution available
// SetChallengeProvider specifies a custom provider p that can solve the given challenge type.
func (c *Client) SetChallengeProvider(challenge Challenge, p ChallengeProvider) error {
switch challenge {
case HTTP01:
@@ -115,6 +115,9 @@ func (c *Client) SetChallengeProvider(challenge Challenge, p ChallengeProvider)
// SetHTTPAddress specifies a custom interface:port to be used for HTTP based challenges.
// If this option is not used, the default port 80 and all interfaces will be used.
// To only specify a port and no interface use the ":port" notation.
//
// NOTE: This REPLACES any custom HTTP provider previously set by calling
// c.SetChallengeProvider with the default HTTP challenge provider.
func (c *Client) SetHTTPAddress(iface string) error {
host, port, err := net.SplitHostPort(iface)
if err != nil {
@@ -131,6 +134,9 @@ func (c *Client) SetHTTPAddress(iface string) error {
// SetTLSAddress specifies a custom interface:port to be used for TLS based challenges.
// If this option is not used, the default port 443 and all interfaces will be used.
// To only specify a port and no interface use the ":port" notation.
//
// NOTE: This REPLACES any custom TLS-SNI provider previously set by calling
// c.SetChallengeProvider with the default TLS-SNI challenge provider.
func (c *Client) SetTLSAddress(iface string) error {
host, port, err := net.SplitHostPort(iface)
if err != nil {
@@ -347,7 +353,7 @@ DNSNames:
// your issued certificate as a bundle.
// This function will never return a partial certificate. If one domain in the list fails,
// the whole certificate will fail.
func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey) (CertificateResource, map[string]error) {
func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (CertificateResource, map[string]error) {
if bundle {
logf("[INFO][%s] acme: Obtaining bundled SAN certificate", strings.Join(domains, ", "))
} else {
@@ -368,7 +374,7 @@ func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto
logf("[INFO][%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
cert, err := c.requestCertificate(challenges, bundle, privKey)
cert, err := c.requestCertificate(challenges, bundle, privKey, mustStaple)
if err != nil {
for _, chln := range challenges {
failures[chln.Domain] = err
@@ -404,7 +410,7 @@ func (c *Client) RevokeCertificate(certificate []byte) error {
// If bundle is true, the []byte contains both the issuer certificate and
// your issued certificate as a bundle.
// For private key reuse the PrivateKey property of the passed in CertificateResource should be non-nil.
func (c *Client) RenewCertificate(cert CertificateResource, bundle bool) (CertificateResource, error) {
func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple bool) (CertificateResource, error) {
// Input certificate is PEM encoded. Decode it here as we may need the decoded
// cert later on in the renewal process. The input may be a bundle or a single certificate.
certificates, err := parsePEMBundle(cert.Certificate)
@@ -421,50 +427,7 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle bool) (Certif
timeLeft := x509Cert.NotAfter.Sub(time.Now().UTC())
logf("[INFO][%s] acme: Trying renewal with %d hours remaining", cert.Domain, int(timeLeft.Hours()))
// The first step of renewal is to check if we get a renewed cert
// directly from the cert URL.
resp, err := httpGet(cert.CertURL)
if err != nil {
return CertificateResource{}, err
}
defer resp.Body.Close()
serverCertBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return CertificateResource{}, err
}
serverCert, err := x509.ParseCertificate(serverCertBytes)
if err != nil {
return CertificateResource{}, err
}
// If the server responds with a different certificate we are effectively renewed.
// TODO: Further test if we can actually use the new certificate (Our private key works)
if !x509Cert.Equal(serverCert) {
logf("[INFO][%s] acme: Server responded with renewed certificate", cert.Domain)
issuedCert := pemEncode(derCertificateBytes(serverCertBytes))
// If bundle is true, we want to return a certificate bundle.
// To do this, we need the issuer certificate.
if bundle {
// The issuer certificate link is always supplied via an "up" link
// in the response headers of a new certificate.
links := parseLinks(resp.Header["Link"])
issuerCert, err := c.getIssuerCertificate(links["up"])
if err != nil {
// If we fail to acquire the issuer cert, return the issued certificate - do not fail.
logf("[ERROR][%s] acme: Could not bundle issuer certificate: %v", cert.Domain, err)
} else {
// Success - append the issuer cert to the issued cert.
issuerCert = pemEncode(derCertificateBytes(issuerCert))
issuedCert = append(issuedCert, issuerCert...)
}
}
cert.Certificate = issuedCert
return cert, nil
}
// If the certificate is the same, then we need to request a new certificate.
// We always need to request a new certificate to renew.
// Start by checking to see if the certificate was based off a CSR, and
// use that if it's defined.
if len(cert.CSR) > 0 {
@@ -499,7 +462,7 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle bool) (Certif
domains = append(domains, x509Cert.Subject.CommonName)
}
newCert, failures := c.ObtainCertificate(domains, bundle, privKey)
newCert, failures := c.ObtainCertificate(domains, bundle, privKey, mustStaple)
return newCert, failures[cert.Domain]
}
@@ -600,7 +563,7 @@ func (c *Client) getChallenges(domains []string) ([]authorizationResource, map[s
return challenges, failures
}
func (c *Client) requestCertificate(authz []authorizationResource, bundle bool, privKey crypto.PrivateKey) (CertificateResource, error) {
func (c *Client) requestCertificate(authz []authorizationResource, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (CertificateResource, error) {
if len(authz) == 0 {
return CertificateResource{}, errors.New("Passed no authorizations to requestCertificate!")
}
@@ -621,7 +584,7 @@ func (c *Client) requestCertificate(authz []authorizationResource, bundle bool,
}
// TODO: should the CSR be customizable?
csr, err := generateCsr(privKey, commonName.Domain, san)
csr, err := generateCsr(privKey, commonName.Domain, san, mustStaple)
if err != nil {
return CertificateResource{}, err
}

17
vendor/github.com/xenolf/lego/acme/crypto.go сгенерированный поставляемый
Просмотреть файл

@@ -20,6 +20,8 @@ import (
"strings"
"time"
"encoding/asn1"
"golang.org/x/crypto/ocsp"
)
@@ -47,6 +49,12 @@ const (
OCSPServerFailed = ocsp.ServerFailed
)
// Constants for OCSP must staple
var (
tlsFeatureExtensionOID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
ocspMustStapleFeature = []byte{0x30, 0x03, 0x02, 0x01, 0x05}
)
// GetOCSPForCert takes a PEM encoded cert or cert bundle returning the raw OCSP response,
// the parsed response, and an error, if any. The returned []byte can be passed directly
// into the OCSPStaple property of a tls.Certificate. If the bundle only contains the
@@ -206,7 +214,7 @@ func generatePrivateKey(keyType KeyType) (crypto.PrivateKey, error) {
return nil, fmt.Errorf("Invalid KeyType: %s", keyType)
}
func generateCsr(privateKey crypto.PrivateKey, domain string, san []string) ([]byte, error) {
func generateCsr(privateKey crypto.PrivateKey, domain string, san []string, mustStaple bool) ([]byte, error) {
template := x509.CertificateRequest{
Subject: pkix.Name{
CommonName: domain,
@@ -217,6 +225,13 @@ func generateCsr(privateKey crypto.PrivateKey, domain string, san []string) ([]b
template.DNSNames = san
}
if mustStaple {
template.Extensions = append(template.Extensions, pkix.Extension{
Id: tlsFeatureExtensionOID,
Value: ocspMustStapleFeature,
})
}
return x509.CreateCertificateRequest(rand.Reader, &template, privateKey)
}

2
vendor/github.com/xenolf/lego/acme/crypto_test.go сгенерированный поставляемый
Просмотреть файл

@@ -24,7 +24,7 @@ func TestGenerateCSR(t *testing.T) {
t.Fatal("Error generating private key:", err)
}
csr, err := generateCsr(key, "fizz.buzz", nil)
csr, err := generateCsr(key, "fizz.buzz", nil, true)
if err != nil {
t.Error("Error generating CSR:", err)
}

27
vendor/github.com/xenolf/lego/acme/dns_challenge.go сгенерированный поставляемый
Просмотреть файл

@@ -23,14 +23,37 @@ var (
fqdnToZone = map[string]string{}
)
var RecursiveNameservers = []string{
const defaultResolvConf = "/etc/resolv.conf"
var defaultNameservers = []string{
"google-public-dns-a.google.com:53",
"google-public-dns-b.google.com:53",
}
var RecursiveNameservers = getNameservers(defaultResolvConf, defaultNameservers)
// DNSTimeout is used to override the default DNS timeout of 10 seconds.
var DNSTimeout = 10 * time.Second
// getNameservers attempts to get systems nameservers before falling back to the defaults
func getNameservers(path string, defaults []string) []string {
config, err := dns.ClientConfigFromFile(path)
if err != nil || len(config.Servers) == 0 {
return defaults
}
systemNameservers := []string{}
for _, server := range config.Servers {
// ensure all servers have a port number
if _, _, err := net.SplitHostPort(server); err != nil {
systemNameservers = append(systemNameservers, net.JoinHostPort(server, "53"))
} else {
systemNameservers = append(systemNameservers, server)
}
}
return systemNameservers
}
// DNS01Record returns a DNS record which will fulfill the `dns-01` challenge
func DNS01Record(domain, keyAuth string) (fqdn string, value string, ttl int) {
keyAuthShaBytes := sha256.Sum256([]byte(keyAuth))
@@ -75,7 +98,7 @@ func (s *dnsChallenge) Solve(chlng challenge, domain string) error {
fqdn, value, _ := DNS01Record(domain, keyAuth)
logf("[INFO][%s] Checking DNS record propagation...", domain)
logf("[INFO][%s] Checking DNS record propagation using %+v", domain, RecursiveNameservers)
var timeout, interval time.Duration
switch provider := s.provider.(type) {

21
vendor/github.com/xenolf/lego/acme/dns_challenge_test.go сгенерированный поставляемый
Просмотреть файл

@@ -85,6 +85,15 @@ var checkAuthoritativeNssTestsErr = []struct {
},
}
var checkResolvConfServersTests = []struct {
fixture string
expected []string
defaults []string
}{
{"testdata/resolv.conf.1", []string{"10.200.3.249:53", "10.200.3.250:5353", "[2001:4860:4860::8844]:53", "[10.0.0.1]:5353"}, []string{"127.0.0.1:53"}},
{"testdata/resolv.conf.nonexistant", []string{"127.0.0.1:53"}, []string{"127.0.0.1:53"}},
}
func TestDNSValidServerResponse(t *testing.T) {
PreCheckDNS = func(fqdn, value string) (bool, error) {
return true, nil
@@ -183,3 +192,15 @@ func TestCheckAuthoritativeNssErr(t *testing.T) {
}
}
}
func TestResolveConfServers(t *testing.T) {
for _, tt := range checkResolvConfServersTests {
result := getNameservers(tt.fixture, tt.defaults)
sort.Strings(result)
sort.Strings(tt.expected)
if !reflect.DeepEqual(result, tt.expected) {
t.Errorf("#%s: expected %q; got %q", tt.fixture, tt.expected, result)
}
}
}

2
vendor/github.com/xenolf/lego/acme/http_challenge_server.go сгенерированный поставляемый
Просмотреть файл

@@ -63,7 +63,7 @@ func (s *HTTPProviderServer) serve(domain, token, keyAuth string) {
w.Write([]byte(keyAuth))
logf("[INFO][%s] Served key authentication", domain)
} else {
logf("[INFO] Received request for domain %s with method %s", r.Host, r.Method)
logf("[WARN] Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the HOST header properly.", r.Host, r.Method)
w.Write([]byte("TEST"))
}
})

2
vendor/github.com/xenolf/lego/acme/http_challenge_test.go сгенерированный поставляемый
Просмотреть файл

@@ -51,7 +51,7 @@ func TestHTTPChallengeInvalidPort(t *testing.T) {
if err := solver.Solve(clientChallenge, "localhost:123456"); err == nil {
t.Errorf("Solve error: got %v, want error", err)
} else if want := "invalid port 123456"; !strings.HasSuffix(err.Error(), want) {
} else if want, want18 := "invalid port 123456", "123456: invalid port"; !strings.HasSuffix(err.Error(), want) && !strings.HasSuffix(err.Error(), want18) {
t.Errorf("Solve error: got %q, want suffix %q", err.Error(), want)
}
}

8
vendor/github.com/xenolf/lego/acme/messages.go сгенерированный поставляемый
Просмотреть файл

@@ -13,17 +13,10 @@ type directory struct {
RevokeCertURL string `json:"revoke-cert"`
}
type recoveryKeyMessage struct {
Length int `json:"length,omitempty"`
Client jose.JsonWebKey `json:"client,omitempty"`
Server jose.JsonWebKey `json:"client,omitempty"`
}
type registrationMessage struct {
Resource string `json:"resource"`
Contact []string `json:"contact"`
Delete bool `json:"delete,omitempty"`
// RecoveryKey recoveryKeyMessage `json:"recoveryKey,omitempty"`
}
// Registration is returned by the ACME server after the registration
@@ -36,7 +29,6 @@ type Registration struct {
Agreement string `json:"agreement,omitempty"`
Authorizations string `json:"authorizations,omitempty"`
Certificates string `json:"certificates,omitempty"`
// RecoveryKey recoveryKeyMessage `json:"recoveryKey,omitempty"`
}
// RegistrationResource represents all important informations about a registration

5
vendor/github.com/xenolf/lego/acme/testdata/resolv.conf.1 сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,5 @@
domain company.com
nameserver 10.200.3.249
nameserver 10.200.3.250:5353
nameserver 2001:4860:4860::8844
nameserver [10.0.0.1]:5353

2
vendor/github.com/xenolf/lego/acme/tls_sni_challenge_test.go сгенерированный поставляемый
Просмотреть файл

@@ -59,7 +59,7 @@ func TestTLSSNIChallengeInvalidPort(t *testing.T) {
if err := solver.Solve(clientChallenge, "localhost:123456"); err == nil {
t.Errorf("Solve error: got %v, want error", err)
} else if want := "invalid port 123456"; !strings.HasSuffix(err.Error(), want) {
} else if want, want18 := "invalid port 123456", "123456: invalid port"; !strings.HasSuffix(err.Error(), want) && !strings.HasSuffix(err.Error(), want18) {
t.Errorf("Solve error: got %q, want suffix %q", err.Error(), want)
}
}

17
vendor/github.com/xenolf/lego/cli.go сгенерированный поставляемый
Просмотреть файл

@@ -64,6 +64,10 @@ func main() {
Name: "no-bundle",
Usage: "Do not create a certificate bundle by adding the issuers certificate to the new certificate.",
},
cli.BoolFlag{
Name: "must-staple",
Usage: "Include the OCSP must staple TLS extension in the CSR and generated certificate. Only works if the CSR is generated by lego.",
},
},
},
{
@@ -89,6 +93,10 @@ func main() {
Name: "no-bundle",
Usage: "Do not create a certificate bundle by adding the issuers certificate to the new certificate.",
},
cli.BoolFlag{
Name: "must-staple",
Usage: "Include the OCSP must staple TLS extension in the CSR and generated certificate. Only works if the CSR is generated by lego.",
},
},
},
{
@@ -138,6 +146,10 @@ func main() {
Name: "webroot",
Usage: "Set the webroot folder to use for HTTP based challenges to write directly in a file in .well-known/acme-challenge",
},
cli.StringSliceFlag{
Name: "memcached-host",
Usage: "Set the memcached host(s) to use for HTTP based challenges. Challenges will be written to all specified hosts.",
},
cli.StringFlag{
Name: "http",
Usage: "Set the port and interface to use for HTTP based challenges to listen on. Supported: interface:port or :port",
@@ -189,21 +201,26 @@ Here is an example bash command using the CloudFlare DNS provider:
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
fmt.Fprintln(w, "Valid providers and their associated credential environment variables:")
fmt.Fprintln(w)
fmt.Fprintln(w, "\tazure:\tAZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_RESROUCE_GROUP")
fmt.Fprintln(w, "\tauroradns:\tAURORA_USER_ID, AURORA_KEY, AURORA_ENDPOINT")
fmt.Fprintln(w, "\tcloudflare:\tCLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY")
fmt.Fprintln(w, "\tdigitalocean:\tDO_AUTH_TOKEN")
fmt.Fprintln(w, "\tdnsimple:\tDNSIMPLE_EMAIL, DNSIMPLE_API_KEY")
fmt.Fprintln(w, "\tdnsmadeeasy:\tDNSMADEEASY_API_KEY, DNSMADEEASY_API_SECRET")
fmt.Fprintln(w, "\texoscale:\tEXOSCALE_API_KEY, EXOSCALE_API_SECRET, EXOSCALE_ENDPOINT")
fmt.Fprintln(w, "\tgandi:\tGANDI_API_KEY")
fmt.Fprintln(w, "\tgcloud:\tGCE_PROJECT")
fmt.Fprintln(w, "\tlinode:\tLINODE_API_KEY")
fmt.Fprintln(w, "\tmanual:\tnone")
fmt.Fprintln(w, "\tnamecheap:\tNAMECHEAP_API_USER, NAMECHEAP_API_KEY")
fmt.Fprintln(w, "\trackspace:\tRACKSPACE_USER, RACKSPACE_API_KEY")
fmt.Fprintln(w, "\trfc2136:\tRFC2136_TSIG_KEY, RFC2136_TSIG_SECRET,\n\t\tRFC2136_TSIG_ALGORITHM, RFC2136_NAMESERVER")
fmt.Fprintln(w, "\troute53:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION")
fmt.Fprintln(w, "\tdyn:\tDYN_CUSTOMER_NAME, DYN_USER_NAME, DYN_PASSWORD")
fmt.Fprintln(w, "\tvultr:\tVULTR_API_KEY")
fmt.Fprintln(w, "\tovh:\tOVH_ENDPOINT, OVH_APPLICATION_KEY, OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY")
fmt.Fprintln(w, "\tpdns:\tPDNS_API_KEY, PDNS_API_URL")
fmt.Fprintln(w, "\tdnspod:\tDNSPOD_API_KEY")
w.Flush()
fmt.Println(`

35
vendor/github.com/xenolf/lego/cli_handlers.go сгенерированный поставляемый
Просмотреть файл

@@ -15,20 +15,27 @@ import (
"github.com/urfave/cli"
"github.com/xenolf/lego/acme"
"github.com/xenolf/lego/providers/dns/auroradns"
"github.com/xenolf/lego/providers/dns/azure"
"github.com/xenolf/lego/providers/dns/cloudflare"
"github.com/xenolf/lego/providers/dns/digitalocean"
"github.com/xenolf/lego/providers/dns/dnsimple"
"github.com/xenolf/lego/providers/dns/dnsmadeeasy"
"github.com/xenolf/lego/providers/dns/dnspod"
"github.com/xenolf/lego/providers/dns/dyn"
"github.com/xenolf/lego/providers/dns/exoscale"
"github.com/xenolf/lego/providers/dns/gandi"
"github.com/xenolf/lego/providers/dns/googlecloud"
"github.com/xenolf/lego/providers/dns/linode"
"github.com/xenolf/lego/providers/dns/namecheap"
"github.com/xenolf/lego/providers/dns/ns1"
"github.com/xenolf/lego/providers/dns/ovh"
"github.com/xenolf/lego/providers/dns/pdns"
"github.com/xenolf/lego/providers/dns/rackspace"
"github.com/xenolf/lego/providers/dns/rfc2136"
"github.com/xenolf/lego/providers/dns/route53"
"github.com/xenolf/lego/providers/dns/vultr"
"github.com/xenolf/lego/providers/http/memcached"
"github.com/xenolf/lego/providers/http/webroot"
)
@@ -99,6 +106,18 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
// infer that the user also wants to exclude all other challenges
client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
}
if c.GlobalIsSet("memcached-host") {
provider, err := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host"))
if err != nil {
logger().Fatal(err)
}
client.SetChallengeProvider(acme.HTTP01, provider)
// --memcached-host=foo:11211 indicates that the user specifically want to do a HTTP challenge
// infer that the user also wants to exclude all other challenges
client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
}
if c.GlobalIsSet("http") {
if strings.Index(c.GlobalString("http"), ":") == -1 {
logger().Fatalf("The --http switch only accepts interface:port or :port for its argument.")
@@ -117,6 +136,10 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
var err error
var provider acme.ChallengeProvider
switch c.GlobalString("dns") {
case "azure":
provider, err = azure.NewDNSProvider()
case "auroradns":
provider, err = auroradns.NewDNSProvider()
case "cloudflare":
provider, err = cloudflare.NewDNSProvider()
case "digitalocean":
@@ -125,6 +148,8 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
provider, err = dnsimple.NewDNSProvider()
case "dnsmadeeasy":
provider, err = dnsmadeeasy.NewDNSProvider()
case "exoscale":
provider, err = exoscale.NewDNSProvider()
case "dyn":
provider, err = dyn.NewDNSProvider()
case "gandi":
@@ -137,6 +162,8 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
provider, err = acme.NewDNSProviderManual()
case "namecheap":
provider, err = namecheap.NewDNSProvider()
case "rackspace":
provider, err = rackspace.NewDNSProvider()
case "route53":
provider, err = route53.NewDNSProvider()
case "rfc2136":
@@ -147,6 +174,10 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
provider, err = ovh.NewDNSProvider()
case "pdns":
provider, err = pdns.NewDNSProvider()
case "ns1":
provider, err = ns1.NewDNSProvider()
case "dnspod":
provider, err = dnspod.NewDNSProvider()
}
if err != nil {
@@ -320,7 +351,7 @@ func run(c *cli.Context) error {
if hasDomains {
// obtain a certificate, generating a new private key
cert, failures = client.ObtainCertificate(c.GlobalStringSlice("domains"), !c.Bool("no-bundle"), nil)
cert, failures = client.ObtainCertificate(c.GlobalStringSlice("domains"), !c.Bool("no-bundle"), nil, c.Bool("must-staple"))
} else {
// read the CSR
csr, err := readCSRFile(c.GlobalString("csr"))
@@ -433,7 +464,7 @@ func renew(c *cli.Context) error {
certRes.Certificate = certBytes
newCert, err := client.RenewCertificate(certRes, !c.Bool("no-bundle"))
newCert, err := client.RenewCertificate(certRes, !c.Bool("no-bundle"), c.Bool("must-staple"))
if err != nil {
logger().Fatalf("%s", err.Error())
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше