summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ponzu/main.go30
-rw-r--r--cmd/ponzu/options.go62
-rw-r--r--cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go776
-rw-r--r--cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go390
-rw-r--r--cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go130
-rw-r--r--cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go58
-rw-r--r--cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go125
-rw-r--r--cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go190
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/context.go156
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/context_test.go577
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go74
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go28
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go147
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go79
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go105
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/go17.go72
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go300
-rw-r--r--cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go26
18 files changed, 3280 insertions, 45 deletions
diff --git a/cmd/ponzu/main.go b/cmd/ponzu/main.go
index ba85f36..234d3b6 100644
--- a/cmd/ponzu/main.go
+++ b/cmd/ponzu/main.go
@@ -11,7 +11,9 @@ import (
"github.com/bosssauce/ponzu/system/admin"
"github.com/bosssauce/ponzu/system/api"
+ "github.com/bosssauce/ponzu/system/api/analytics"
"github.com/bosssauce/ponzu/system/db"
+ "github.com/bosssauce/ponzu/system/tls"
)
var usage = `
@@ -45,7 +47,7 @@ generate, gen, g <type>:
-[[--port=8080] [--tls]] run <service(,service)>:
+[[--port=8080] [--https]] run <service(,service)>:
Starts the 'ponzu' HTTP server for the JSON API, Admin System, or both.
The segments, separated by a comma, describe which services to start, either
@@ -54,7 +56,7 @@ generate, gen, g <type>:
automatically managed using Let's Encrypt (https://letsencrypt.org)
Example:
- $ ponzu --port=8080 --tls run admin,api
+ $ ponzu --port=8080 --https run admin,api
(or)
$ ponzu run admin
(or)
@@ -71,8 +73,8 @@ generate, gen, g <type>:
`
var (
- port int
- tls bool
+ port int
+ https bool
// for ponzu internal / core development
dev bool
@@ -87,7 +89,7 @@ func init() {
func main() {
flag.IntVar(&port, "port", 8080, "port for ponzu to bind its listener")
- flag.BoolVar(&tls, "tls", false, "enable automatic TLS/SSL certificate management")
+ flag.BoolVar(&https, "https", false, "enable automatic TLS/SSL certificate management")
flag.BoolVar(&dev, "dev", false, "modify environment for Ponzu core development")
flag.StringVar(&fork, "fork", "", "modify repo source for Ponzu core development")
flag.Parse()
@@ -132,10 +134,10 @@ func main() {
case "run":
var addTLS string
- if tls {
- addTLS = "--tls"
+ if https {
+ addTLS = "--https"
} else {
- addTLS = "--tls=false"
+ addTLS = "--https=false"
}
var services string
@@ -168,6 +170,11 @@ func main() {
case "serve", "s":
db.Init()
+ defer db.Close()
+
+ analytics.Init()
+ defer analytics.Close()
+
if len(args) > 1 {
services := strings.Split(args[1], ",")
@@ -184,10 +191,9 @@ func main() {
}
}
- if tls {
- fmt.Println("TLS through Let's Encrypt is not implemented yet.")
- fmt.Println("Please run 'ponzu serve' without the --tls flag for now.")
- os.Exit(1)
+ if https {
+ fmt.Println("Enabling HTTPS...")
+ tls.Enable()
}
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
diff --git a/cmd/ponzu/options.go b/cmd/ponzu/options.go
index cabe91a..b23ab2d 100644
--- a/cmd/ponzu/options.go
+++ b/cmd/ponzu/options.go
@@ -72,36 +72,16 @@ type {{ .name }} struct {
editor editor.Editor
// required: all maintained {{ .name }} fields must have json tags!
- Title string ` + "`json:" + `"title"` + "`" + `
- Content string ` + "`json:" + `"content"` + "`" + `
- Author string ` + "`json:" + `"author"` + "`" + `
- Picture string ` + "`json:" + `"picture"` + "`" + `
- Category []string ` + "`json:" + `"category"` + "`" + `
- ThemeStyle string ` + "`json:" + `"theme"` + "`" + `
+ Title string ` + "`json:" + `"title"` + "`" + `
+ Content string ` + "`json:" + `"content"` + "`" + `
+ Author string ` + "`json:" + `"author"` + "`" + `
+ Photo string ` + "`json:" + `"photo"` + "`" + `
+ Category []string ` + "`json:" + `"category"` + "`" + `
+ Theme string ` + "`json:" + `"theme"` + "`" + `
}
-func init() {
- Types["{{ .name }}"] = func() interface{} { return new({{ .name }}) }
-}
-
-// SetContentID partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) SetContentID(id int) { {{ .initial }}.ID = id }
-
-// ContentID partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) ContentID() int { return {{ .initial }}.ID }
-
-// ContentName partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) ContentName() string { return {{ .initial }}.Title }
-
-// SetSlug partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) SetSlug(slug string) { {{ .initial }}.Slug = slug }
-
-// Editor partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) Editor() *editor.Editor { return &{{ .initial }}.editor }
-
// MarshalEditor writes a buffer of html to edit a {{ .name }} and partially implements editor.Editable
func ({{ .initial }} *{{ .name }}) MarshalEditor() ([]byte, error) {
-/* EXAMPLE CODE (from post.go, the default content type) */
view, err := editor.Form({{ .initial }},
editor.Field{
// Take careful note that the first argument to these Input-like methods
@@ -127,22 +107,18 @@ func ({{ .initial }} *{{ .name }}) MarshalEditor() ([]byte, error) {
}),
},
editor.Field{
- View: editor.File("Picture", {{ .initial }}, map[string]string{
+ View: editor.File("Photo", {{ .initial }}, map[string]string{
"label": "Author Photo",
"placeholder": "Upload a profile picture for the author",
}),
},
editor.Field{
- View: editor.Checkbox("Category", {{ .initial }}, map[string]string{
+ View: editor.Tags("Category", {{ .initial }}, map[string]string{
"label": "{{ .name }} Category",
- }, map[string]string{
- "important": "Important",
- "active": "Active",
- "unplanned": "Unplanned",
}),
},
editor.Field{
- View: editor.Select("ThemeStyle", {{ .initial }}, map[string]string{
+ View: editor.Select("Theme", {{ .initial }}, map[string]string{
"label": "Theme Style",
}, map[string]string{
"dark": "Dark",
@@ -157,6 +133,26 @@ func ({{ .initial }} *{{ .name }}) MarshalEditor() ([]byte, error) {
return view, nil
}
+
+func init() {
+ Types["{{ .name }}"] = func() interface{} { return new({{ .name }}) }
+}
+
+// SetContentID partially implements editor.Editable
+func ({{ .initial }} *{{ .name }}) SetContentID(id int) { {{ .initial }}.ID = id }
+
+// ContentID partially implements editor.Editable
+func ({{ .initial }} *{{ .name }}) ContentID() int { return {{ .initial }}.ID }
+
+// ContentName partially implements editor.Editable
+func ({{ .initial }} *{{ .name }}) ContentName() string { return {{ .initial }}.Title }
+
+// SetSlug partially implements editor.Editable
+func ({{ .initial }} *{{ .name }}) SetSlug(slug string) { {{ .initial }}.Slug = slug }
+
+// Editor partially implements editor.Editable
+func ({{ .initial }} *{{ .name }}) Editor() *editor.Editor { return &{{ .initial }}.editor }
+
`
func newProjectInDir(path string) error {
diff --git a/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go
new file mode 100644
index 0000000..12c9010
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go
@@ -0,0 +1,776 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package autocert provides automatic access to certificates from Let's Encrypt
+// and any other ACME-based CA.
+//
+// This package is a work in progress and makes no API stability promises.
+package autocert
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/tls"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "io"
+ mathrand "math/rand"
+ "net/http"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/crypto/acme"
+ "golang.org/x/net/context"
+)
+
+// pseudoRand is safe for concurrent use.
+var pseudoRand *lockedMathRand
+
+func init() {
+ src := mathrand.NewSource(timeNow().UnixNano())
+ pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
+}
+
+// AcceptTOS always returns true to indicate the acceptance of a CA Terms of Service
+// during account registration.
+func AcceptTOS(tosURL string) bool { return true }
+
+// HostPolicy specifies which host names the Manager is allowed to respond to.
+// It returns a non-nil error if the host should be rejected.
+// The returned error is accessible via tls.Conn.Handshake and its callers.
+// See Manager's HostPolicy field and GetCertificate method docs for more details.
+type HostPolicy func(ctx context.Context, host string) error
+
+// HostWhitelist returns a policy where only the specified host names are allowed.
+// Only exact matches are currently supported. Subdomains, regexp or wildcard
+// will not match.
+func HostWhitelist(hosts ...string) HostPolicy {
+ whitelist := make(map[string]bool, len(hosts))
+ for _, h := range hosts {
+ whitelist[h] = true
+ }
+ return func(_ context.Context, host string) error {
+ if !whitelist[host] {
+ return errors.New("acme/autocert: host not configured")
+ }
+ return nil
+ }
+}
+
+// defaultHostPolicy is used when Manager.HostPolicy is not set.
+func defaultHostPolicy(context.Context, string) error {
+ return nil
+}
+
+// Manager is a stateful certificate manager built on top of acme.Client.
+// It obtains and refreshes certificates automatically,
+// as well as providing them to a TLS server via tls.Config.
+//
+// A simple usage example:
+//
+// m := autocert.Manager{
+// Prompt: autocert.AcceptTOS,
+// HostPolicy: autocert.HostWhitelist("example.org"),
+// }
+// s := &http.Server{
+// Addr: ":https",
+// TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
+// }
+// s.ListenAndServeTLS("", "")
+//
+// To preserve issued certificates and improve overall performance,
+// use a cache implementation of Cache. For instance, DirCache.
+type Manager struct {
+ // Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS).
+ // The registration may require the caller to agree to the CA's TOS.
+ // If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report
+ // whether the caller agrees to the terms.
+ //
+ // To always accept the terms, the callers can use AcceptTOS.
+ Prompt func(tosURL string) bool
+
+ // Cache optionally stores and retrieves previously-obtained certificates.
+ // If nil, certs will only be cached for the lifetime of the Manager.
+ //
+ // Manager passes the Cache certificates data encoded in PEM, with private/public
+ // parts combined in a single Cache.Put call, private key first.
+ Cache Cache
+
+ // HostPolicy controls which domains the Manager will attempt
+ // to retrieve new certificates for. It does not affect cached certs.
+ //
+ // If non-nil, HostPolicy is called before requesting a new cert.
+ // If nil, all hosts are currently allowed. This is not recommended,
+ // as it opens a potential attack where clients connect to a server
+ // by IP address and pretend to be asking for an incorrect host name.
+ // Manager will attempt to obtain a certificate for that host, incorrectly,
+ // eventually reaching the CA's rate limit for certificate requests
+ // and making it impossible to obtain actual certificates.
+ //
+ // See GetCertificate for more details.
+ HostPolicy HostPolicy
+
+ // RenewBefore optionally specifies how early certificates should
+ // be renewed before they expire.
+ //
+ // If zero, they're renewed 1 week before expiration.
+ RenewBefore time.Duration
+
+ // Client is used to perform low-level operations, such as account registration
+ // and requesting new certificates.
+ // If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
+ // directory endpoint and a newly-generated ECDSA P-256 key.
+ //
+ // Mutating the field after the first call of GetCertificate method will have no effect.
+ Client *acme.Client
+
+ // Email optionally specifies a contact email address.
+ // This is used by CAs, such as Let's Encrypt, to notify about problems
+ // with issued certificates.
+ //
+ // If the Client's account key is already registered, Email is not used.
+ Email string
+
+ clientMu sync.Mutex
+ client *acme.Client // initialized by acmeClient method
+
+ stateMu sync.Mutex
+ state map[string]*certState // keyed by domain name
+
+ // tokenCert is keyed by token domain name, which matches server name
+ // of ClientHello. Keys always have ".acme.invalid" suffix.
+ tokenCertMu sync.RWMutex
+ tokenCert map[string]*tls.Certificate
+
+ // renewal tracks the set of domains currently running renewal timers.
+ // It is keyed by domain name.
+ renewalMu sync.Mutex
+ renewal map[string]*domainRenewal
+}
+
+// GetCertificate implements the tls.Config.GetCertificate hook.
+// It provides a TLS certificate for hello.ServerName host, including answering
+// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
+//
+// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
+// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
+// The error is propagated back to the caller of GetCertificate and is user-visible.
+// This does not affect cached certs. See HostPolicy field description for more details.
+func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ name := hello.ServerName
+ if name == "" {
+ return nil, errors.New("acme/autocert: missing server name")
+ }
+
+ // check whether this is a token cert requested for TLS-SNI challenge
+ if strings.HasSuffix(name, ".acme.invalid") {
+ m.tokenCertMu.RLock()
+ defer m.tokenCertMu.RUnlock()
+ if cert := m.tokenCert[name]; cert != nil {
+ return cert, nil
+ }
+ if cert, err := m.cacheGet(name); err == nil {
+ return cert, nil
+ }
+ // TODO: cache error results?
+ return nil, fmt.Errorf("acme/autocert: no token cert for %q", name)
+ }
+
+ // regular domain
+ cert, err := m.cert(name)
+ if err == nil {
+ return cert, nil
+ }
+ if err != ErrCacheMiss {
+ return nil, err
+ }
+
+ // first-time
+ ctx := context.Background() // TODO: use a deadline?
+ if err := m.hostPolicy()(ctx, name); err != nil {
+ return nil, err
+ }
+ cert, err = m.createCert(ctx, name)
+ if err != nil {
+ return nil, err
+ }
+ m.cachePut(name, cert)
+ return cert, nil
+}
+
+// cert returns an existing certificate either from m.state or cache.
+// If a certificate is found in cache but not in m.state, the latter will be filled
+// with the cached value.
+func (m *Manager) cert(name string) (*tls.Certificate, error) {
+ m.stateMu.Lock()
+ if s, ok := m.state[name]; ok {
+ m.stateMu.Unlock()
+ s.RLock()
+ defer s.RUnlock()
+ return s.tlscert()
+ }
+ defer m.stateMu.Unlock()
+ cert, err := m.cacheGet(name)
+ if err != nil {
+ return nil, err
+ }
+ signer, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return nil, errors.New("acme/autocert: private key cannot sign")
+ }
+ if m.state == nil {
+ m.state = make(map[string]*certState)
+ }
+ s := &certState{
+ key: signer,
+ cert: cert.Certificate,
+ leaf: cert.Leaf,
+ }
+ m.state[name] = s
+ go m.renew(name, s.key, s.leaf.NotAfter)
+ return cert, nil
+}
+
+// cacheGet always returns a valid certificate, or an error otherwise.
+func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
+ if m.Cache == nil {
+ return nil, ErrCacheMiss
+ }
+ // TODO: might want to define a cache timeout on m
+ ctx := context.Background()
+ data, err := m.Cache.Get(ctx, domain)
+ if err != nil {
+ return nil, err
+ }
+
+ // private
+ priv, pub := pem.Decode(data)
+ if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
+ return nil, errors.New("acme/autocert: no private key found in cache")
+ }
+ privKey, err := parsePrivateKey(priv.Bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // public
+ var pubDER [][]byte
+ for len(pub) > 0 {
+ var b *pem.Block
+ b, pub = pem.Decode(pub)
+ if b == nil {
+ break
+ }
+ pubDER = append(pubDER, b.Bytes)
+ }
+ if len(pub) > 0 {
+ return nil, errors.New("acme/autocert: invalid public key")
+ }
+
+ // verify and create TLS cert
+ leaf, err := validCert(domain, pubDER, privKey)
+ if err != nil {
+ return nil, err
+ }
+ tlscert := &tls.Certificate{
+ Certificate: pubDER,
+ PrivateKey: privKey,
+ Leaf: leaf,
+ }
+ return tlscert, nil
+}
+
+func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
+ if m.Cache == nil {
+ return nil
+ }
+
+ // contains PEM-encoded data
+ var buf bytes.Buffer
+
+ // private
+ switch key := tlscert.PrivateKey.(type) {
+ case *ecdsa.PrivateKey:
+ if err := encodeECDSAKey(&buf, key); err != nil {
+ return err
+ }
+ case *rsa.PrivateKey:
+ b := x509.MarshalPKCS1PrivateKey(key)
+ pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b}
+ if err := pem.Encode(&buf, pb); err != nil {
+ return err
+ }
+ default:
+ return errors.New("acme/autocert: unknown private key type")
+ }
+
+ // public
+ for _, b := range tlscert.Certificate {
+ pb := &pem.Block{Type: "CERTIFICATE", Bytes: b}
+ if err := pem.Encode(&buf, pb); err != nil {
+ return err
+ }
+ }
+
+ // TODO: might want to define a cache timeout on m
+ ctx := context.Background()
+ return m.Cache.Put(ctx, domain, buf.Bytes())
+}
+
+func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
+ b, err := x509.MarshalECPrivateKey(key)
+ if err != nil {
+ return err
+ }
+ pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+ return pem.Encode(w, pb)
+}
+
+// createCert starts the domain ownership verification and returns a certificate
+// for that domain upon success.
+//
+// If the domain is already being verified, it waits for the existing verification to complete.
+// Either way, createCert blocks for the duration of the whole process.
+func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) {
+ // TODO: maybe rewrite this whole piece using sync.Once
+ state, err := m.certState(domain)
+ if err != nil {
+ return nil, err
+ }
+ // state may exist if another goroutine is already working on it
+ // in which case just wait for it to finish
+ if !state.locked {
+ state.RLock()
+ defer state.RUnlock()
+ return state.tlscert()
+ }
+
+ // We are the first; state is locked.
+ // Unblock the readers when domain ownership is verified
+ // and the we got the cert or the process failed.
+ defer state.Unlock()
+ state.locked = false
+
+ der, leaf, err := m.authorizedCert(ctx, state.key, domain)
+ if err != nil {
+ return nil, err
+ }
+ state.cert = der
+ state.leaf = leaf
+ go m.renew(domain, state.key, state.leaf.NotAfter)
+ return state.tlscert()
+}
+
+// certState returns a new or existing certState.
+// If a new certState is returned, state.exist is false and the state is locked.
+// The returned error is non-nil only in the case where a new state could not be created.
+func (m *Manager) certState(domain string) (*certState, error) {
+ m.stateMu.Lock()
+ defer m.stateMu.Unlock()
+ if m.state == nil {
+ m.state = make(map[string]*certState)
+ }
+ // existing state
+ if state, ok := m.state[domain]; ok {
+ return state, nil
+ }
+ // new locked state
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+ state := &certState{
+ key: key,
+ locked: true,
+ }
+ state.Lock() // will be unlocked by m.certState caller
+ m.state[domain] = state
+ return state, nil
+}
+
+// authorizedCert starts domain ownership verification process and requests a new cert upon success.
+// The key argument is the certificate private key.
+func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
+ // TODO: make m.verify retry or retry m.verify calls here
+ if err := m.verify(ctx, domain); err != nil {
+ return nil, nil, err
+ }
+ client, err := m.acmeClient(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
+ csr, err := certRequest(key, domain)
+ if err != nil {
+ return nil, nil, err
+ }
+ der, _, err = client.CreateCert(ctx, csr, 0, true)
+ if err != nil {
+ return nil, nil, err
+ }
+ leaf, err = validCert(domain, der, key)
+ if err != nil {
+ return nil, nil, err
+ }
+ return der, leaf, nil
+}
+
+// verify starts a new identifier (domain) authorization flow.
+// It prepares a challenge response and then blocks until the authorization
+// is marked as "completed" by the CA (either succeeded or failed).
+//
+// verify returns nil iff the verification was successful.
+func (m *Manager) verify(ctx context.Context, domain string) error {
+ client, err := m.acmeClient(ctx)
+ if err != nil {
+ return err
+ }
+
+ // start domain authorization and get the challenge
+ authz, err := client.Authorize(ctx, domain)
+ if err != nil {
+ return err
+ }
+ // maybe don't need to at all
+ if authz.Status == acme.StatusValid {
+ return nil
+ }
+
+ // pick a challenge: prefer tls-sni-02 over tls-sni-01
+ // TODO: consider authz.Combinations
+ var chal *acme.Challenge
+ for _, c := range authz.Challenges {
+ if c.Type == "tls-sni-02" {
+ chal = c
+ break
+ }
+ if c.Type == "tls-sni-01" {
+ chal = c
+ }
+ }
+ if chal == nil {
+ return errors.New("acme/autocert: no supported challenge type found")
+ }
+
+ // create a token cert for the challenge response
+ var (
+ cert tls.Certificate
+ name string
+ )
+ switch chal.Type {
+ case "tls-sni-01":
+ cert, name, err = client.TLSSNI01ChallengeCert(chal.Token)
+ case "tls-sni-02":
+ cert, name, err = client.TLSSNI02ChallengeCert(chal.Token)
+ default:
+ err = fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
+ }
+ if err != nil {
+ return err
+ }
+ m.putTokenCert(name, &cert)
+ defer func() {
+ // verification has ended at this point
+ // don't need token cert anymore
+ go m.deleteTokenCert(name)
+ }()
+
+ // ready to fulfill the challenge
+ if _, err := client.Accept(ctx, chal); err != nil {
+ return err
+ }
+ // wait for the CA to validate
+ _, err = client.WaitAuthorization(ctx, authz.URI)
+ return err
+}
+
+// putTokenCert stores the cert under the named key in both m.tokenCert map
+// and m.Cache.
+func (m *Manager) putTokenCert(name string, cert *tls.Certificate) {
+ m.tokenCertMu.Lock()
+ defer m.tokenCertMu.Unlock()
+ if m.tokenCert == nil {
+ m.tokenCert = make(map[string]*tls.Certificate)
+ }
+ m.tokenCert[name] = cert
+ m.cachePut(name, cert)
+}
+
+// deleteTokenCert removes the token certificate for the specified domain name
+// from both m.tokenCert map and m.Cache.
+func (m *Manager) deleteTokenCert(name string) {
+ m.tokenCertMu.Lock()
+ defer m.tokenCertMu.Unlock()
+ delete(m.tokenCert, name)
+ if m.Cache != nil {
+ m.Cache.Delete(context.Background(), name)
+ }
+}
+
+// renew starts a cert renewal timer loop, one per domain.
+//
+// The loop is scheduled in two cases:
+// - a cert was fetched from cache for the first time (wasn't in m.state)
+// - a new cert was created by m.createCert
+//
+// The key argument is a certificate private key.
+// The exp argument is the cert expiration time (NotAfter).
+func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) {
+ m.renewalMu.Lock()
+ defer m.renewalMu.Unlock()
+ if m.renewal[domain] != nil {
+ // another goroutine is already on it
+ return
+ }
+ if m.renewal == nil {
+ m.renewal = make(map[string]*domainRenewal)
+ }
+ dr := &domainRenewal{m: m, domain: domain, key: key}
+ m.renewal[domain] = dr
+ dr.start(exp)
+}
+
+// stopRenew stops all currently running cert renewal timers.
+// The timers are not restarted during the lifetime of the Manager.
+func (m *Manager) stopRenew() {
+ m.renewalMu.Lock()
+ defer m.renewalMu.Unlock()
+ for name, dr := range m.renewal {
+ delete(m.renewal, name)
+ dr.stop()
+ }
+}
+
+func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
+ const keyName = "acme_account.key"
+
+ genKey := func() (*ecdsa.PrivateKey, error) {
+ return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ }
+
+ if m.Cache == nil {
+ return genKey()
+ }
+
+ data, err := m.Cache.Get(ctx, keyName)
+ if err == ErrCacheMiss {
+ key, err := genKey()
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ if err := encodeECDSAKey(&buf, key); err != nil {
+ return nil, err
+ }
+ if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil {
+ return nil, err
+ }
+ return key, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ priv, _ := pem.Decode(data)
+ if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
+ return nil, errors.New("acme/autocert: invalid account key found in cache")
+ }
+ return parsePrivateKey(priv.Bytes)
+}
+
+func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
+ m.clientMu.Lock()
+ defer m.clientMu.Unlock()
+ if m.client != nil {
+ return m.client, nil
+ }
+
+ client := m.Client
+ if client == nil {
+ client = &acme.Client{DirectoryURL: acme.LetsEncryptURL}
+ }
+ if client.Key == nil {
+ var err error
+ client.Key, err = m.accountKey(ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+ var contact []string
+ if m.Email != "" {
+ contact = []string{"mailto:" + m.Email}
+ }
+ a := &acme.Account{Contact: contact}
+ _, err := client.Register(ctx, a, m.Prompt)
+ if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict {
+ // conflict indicates the key is already registered
+ m.client = client
+ err = nil
+ }
+ return m.client, err
+}
+
+func (m *Manager) hostPolicy() HostPolicy {
+ if m.HostPolicy != nil {
+ return m.HostPolicy
+ }
+ return defaultHostPolicy
+}
+
+func (m *Manager) renewBefore() time.Duration {
+ if m.RenewBefore > maxRandRenew {
+ return m.RenewBefore
+ }
+ return 7 * 24 * time.Hour // 1 week
+}
+
+// certState is ready when its mutex is unlocked for reading.
+type certState struct {
+ sync.RWMutex
+ locked bool // locked for read/write
+ key crypto.Signer // private key for cert
+ cert [][]byte // DER encoding
+ leaf *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
+}
+
+// tlscert creates a tls.Certificate from s.key and s.cert.
+// Callers should wrap it in s.RLock() and s.RUnlock().
+func (s *certState) tlscert() (*tls.Certificate, error) {
+ if s.key == nil {
+ return nil, errors.New("acme/autocert: missing signer")
+ }
+ if len(s.cert) == 0 {
+ return nil, errors.New("acme/autocert: missing certificate")
+ }
+ return &tls.Certificate{
+ PrivateKey: s.key,
+ Certificate: s.cert,
+ Leaf: s.leaf,
+ }, nil
+}
+
+// certRequest creates a certificate request for the given common name cn
+// and optional SANs.
+func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
+ req := &x509.CertificateRequest{
+ Subject: pkix.Name{CommonName: cn},
+ DNSNames: san,
+ }
+ return x509.CreateCertificateRequest(rand.Reader, req, key)
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+//
+// Inspired by parsePrivateKey in crypto/tls/tls.go.
+func parsePrivateKey(der []byte) (crypto.Signer, error) {
+ if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+ return key, nil
+ }
+ if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+ switch key := key.(type) {
+ case *rsa.PrivateKey:
+ return key, nil
+ case *ecdsa.PrivateKey:
+ return key, nil
+ default:
+ return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping")
+ }
+ }
+ if key, err := x509.ParseECPrivateKey(der); err == nil {
+ return key, nil
+ }
+
+ return nil, errors.New("acme/autocert: failed to parse private key")
+}
+
+// validCert parses a cert chain provided as der argument and verifies the leaf, der[0],
+// corresponds to the private key, as well as the domain match and expiration dates.
+// It doesn't do any revocation checking.
+//
+// The returned value is the verified leaf cert.
+func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
+ // parse public part(s)
+ var n int
+ for _, b := range der {
+ n += len(b)
+ }
+ pub := make([]byte, n)
+ n = 0
+ for _, b := range der {
+ n += copy(pub[n:], b)
+ }
+ x509Cert, err := x509.ParseCertificates(pub)
+ if len(x509Cert) == 0 {
+ return nil, errors.New("acme/autocert: no public key found")
+ }
+ // verify the leaf is not expired and matches the domain name
+ leaf = x509Cert[0]
+ now := timeNow()
+ if now.Before(leaf.NotBefore) {
+ return nil, errors.New("acme/autocert: certificate is not valid yet")
+ }
+ if now.After(leaf.NotAfter) {
+ return nil, errors.New("acme/autocert: expired certificate")
+ }
+ if err := leaf.VerifyHostname(domain); err != nil {
+ return nil, err
+ }
+ // ensure the leaf corresponds to the private key
+ switch pub := leaf.PublicKey.(type) {
+ case *rsa.PublicKey:
+ prv, ok := key.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("acme/autocert: private key type does not match public key type")
+ }
+ if pub.N.Cmp(prv.N) != 0 {
+ return nil, errors.New("acme/autocert: private key does not match public key")
+ }
+ case *ecdsa.PublicKey:
+ prv, ok := key.(*ecdsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("acme/autocert: private key type does not match public key type")
+ }
+ if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
+ return nil, errors.New("acme/autocert: private key does not match public key")
+ }
+ default:
+ return nil, errors.New("acme/autocert: unknown public key algorithm")
+ }
+ return leaf, nil
+}
+
+func retryAfter(v string) time.Duration {
+ if i, err := strconv.Atoi(v); err == nil {
+ return time.Duration(i) * time.Second
+ }
+ if t, err := http.ParseTime(v); err == nil {
+ return t.Sub(timeNow())
+ }
+ return time.Second
+}
+
+type lockedMathRand struct {
+ sync.Mutex
+ rnd *mathrand.Rand
+}
+
+func (r *lockedMathRand) int63n(max int64) int64 {
+ r.Lock()
+ n := r.rnd.Int63n(max)
+ r.Unlock()
+ return n
+}
+
+// for easier testing
+var timeNow = time.Now
diff --git a/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go
new file mode 100644
index 0000000..3a9daa1
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go
@@ -0,0 +1,390 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/tls"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "io"
+ "math/big"
+ "net/http"
+ "net/http/httptest"
+ "reflect"
+ "testing"
+ "time"
+
+ "golang.org/x/crypto/acme"
+ "golang.org/x/net/context"
+)
+
+var discoTmpl = template.Must(template.New("disco").Parse(`{
+ "new-reg": "{{.}}/new-reg",
+ "new-authz": "{{.}}/new-authz",
+ "new-cert": "{{.}}/new-cert"
+}`))
+
+var authzTmpl = template.Must(template.New("authz").Parse(`{
+ "status": "pending",
+ "challenges": [
+ {
+ "uri": "{{.}}/challenge/1",
+ "type": "tls-sni-01",
+ "token": "token-01"
+ },
+ {
+ "uri": "{{.}}/challenge/2",
+ "type": "tls-sni-02",
+ "token": "token-02"
+ }
+ ]
+}`))
+
+type memCache map[string][]byte
+
+func (m memCache) Get(ctx context.Context, key string) ([]byte, error) {
+ v, ok := m[key]
+ if !ok {
+ return nil, ErrCacheMiss
+ }
+ return v, nil
+}
+
+func (m memCache) Put(ctx context.Context, key string, data []byte) error {
+ m[key] = data
+ return nil
+}
+
+func (m memCache) Delete(ctx context.Context, key string) error {
+ delete(m, key)
+ return nil
+}
+
+func dummyCert(pub interface{}, san ...string) ([]byte, error) {
+ return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
+}
+
+func dateDummyCert(pub interface{}, start, end time.Time, san ...string) ([]byte, error) {
+ // use EC key to run faster on 386
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+ t := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ NotBefore: start,
+ NotAfter: end,
+ BasicConstraintsValid: true,
+ KeyUsage: x509.KeyUsageKeyEncipherment,
+ DNSNames: san,
+ }
+ if pub == nil {
+ pub = &key.PublicKey
+ }
+ return x509.CreateCertificate(rand.Reader, t, t, pub, key)
+}
+
+func decodePayload(v interface{}, r io.Reader) error {
+ var req struct{ Payload string }
+ if err := json.NewDecoder(r).Decode(&req); err != nil {
+ return err
+ }
+ payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(payload, v)
+}
+
+func TestGetCertificate(t *testing.T) {
+ const domain = "example.org"
+ man := &Manager{Prompt: AcceptTOS}
+ defer man.stopRenew()
+
+ // echo token-02 | shasum -a 256
+ // then divide result in 2 parts separated by dot
+ tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
+ verifyTokenCert := func() {
+ hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
+ _, err := man.GetCertificate(hello)
+ if err != nil {
+ t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
+ return
+ }
+ }
+
+ // ACME CA server stub
+ var ca *httptest.Server
+ ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("replay-nonce", "nonce")
+ if r.Method == "HEAD" {
+ // a nonce request
+ return
+ }
+
+ switch r.URL.Path {
+ // discovery
+ case "/":
+ if err := discoTmpl.Execute(w, ca.URL); err != nil {
+ t.Fatalf("discoTmpl: %v", err)
+ }
+ // client key registration
+ case "/new-reg":
+ w.Write([]byte("{}"))
+ // domain authorization
+ case "/new-authz":
+ w.Header().Set("location", ca.URL+"/authz/1")
+ w.WriteHeader(http.StatusCreated)
+ if err := authzTmpl.Execute(w, ca.URL); err != nil {
+ t.Fatalf("authzTmpl: %v", err)
+ }
+ // accept tls-sni-02 challenge
+ case "/challenge/2":
+ verifyTokenCert()
+ w.Write([]byte("{}"))
+ // authorization status
+ case "/authz/1":
+ w.Write([]byte(`{"status": "valid"}`))
+ // cert request
+ case "/new-cert":
+ var req struct {
+ CSR string `json:"csr"`
+ }
+ decodePayload(&req, r.Body)
+ b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
+ csr, err := x509.ParseCertificateRequest(b)
+ if err != nil {
+ t.Fatalf("new-cert: CSR: %v", err)
+ }
+ der, err := dummyCert(csr.PublicKey, domain)
+ if err != nil {
+ t.Fatalf("new-cert: dummyCert: %v", err)
+ }
+ chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
+ w.Header().Set("link", chainUp)
+ w.WriteHeader(http.StatusCreated)
+ w.Write(der)
+ // CA chain cert
+ case "/ca-cert":
+ der, err := dummyCert(nil, "ca")
+ if err != nil {
+ t.Fatalf("ca-cert: dummyCert: %v", err)
+ }
+ w.Write(der)
+ default:
+ t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+ }
+ }))
+ defer ca.Close()
+
+ // use EC key to run faster on 386
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ man.Client = &acme.Client{
+ Key: key,
+ DirectoryURL: ca.URL,
+ }
+
+ // simulate tls.Config.GetCertificate
+ var tlscert *tls.Certificate
+ done := make(chan struct{})
+ go func() {
+ hello := &tls.ClientHelloInfo{ServerName: domain}
+ tlscert, err = man.GetCertificate(hello)
+ close(done)
+ }()
+ select {
+ case <-time.After(time.Minute):
+ t.Fatal("man.GetCertificate took too long to return")
+ case <-done:
+ }
+ if err != nil {
+ t.Fatalf("man.GetCertificate: %v", err)
+ }
+
+ // verify the tlscert is the same we responded with from the CA stub
+ if len(tlscert.Certificate) == 0 {
+ t.Fatal("len(tlscert.Certificate) is 0")
+ }
+ cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+ if err != nil {
+ t.Fatalf("x509.ParseCertificate: %v", err)
+ }
+ if len(cert.DNSNames) == 0 || cert.DNSNames[0] != domain {
+ t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
+ }
+
+ // make sure token cert was removed
+ done = make(chan struct{})
+ go func() {
+ for {
+ hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
+ if _, err := man.GetCertificate(hello); err != nil {
+ break
+ }
+ time.Sleep(100 * time.Millisecond)
+ }
+ close(done)
+ }()
+ select {
+ case <-time.After(5 * time.Second):
+ t.Error("token cert was not removed")
+ case <-done:
+ }
+}
+
+func TestAccountKeyCache(t *testing.T) {
+ cache := make(memCache)
+ m := Manager{Cache: cache}
+ ctx := context.Background()
+ k1, err := m.accountKey(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ k2, err := m.accountKey(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(k1, k2) {
+ t.Errorf("account keys don't match: k1 = %#v; k2 = %#v", k1, k2)
+ }
+}
+
+func TestCache(t *testing.T) {
+ privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tmpl := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{CommonName: "example.org"},
+ NotAfter: time.Now().Add(time.Hour),
+ }
+ pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tlscert := &tls.Certificate{
+ Certificate: [][]byte{pub},
+ PrivateKey: privKey,
+ }
+
+ cache := make(memCache)
+ man := &Manager{Cache: cache}
+ defer man.stopRenew()
+ if err := man.cachePut("example.org", tlscert); err != nil {
+ t.Fatalf("man.cachePut: %v", err)
+ }
+ res, err := man.cacheGet("example.org")
+ if err != nil {
+ t.Fatalf("man.cacheGet: %v", err)
+ }
+ if res == nil {
+ t.Fatal("res is nil")
+ }
+}
+
+func TestHostWhitelist(t *testing.T) {
+ policy := HostWhitelist("example.com", "example.org", "*.example.net")
+ tt := []struct {
+ host string
+ allow bool
+ }{
+ {"example.com", true},
+ {"example.org", true},
+ {"one.example.com", false},
+ {"two.example.org", false},
+ {"three.example.net", false},
+ {"dummy", false},
+ }
+ for i, test := range tt {
+ err := policy(nil, test.host)
+ if err != nil && test.allow {
+ t.Errorf("%d: policy(%q): %v; want nil", i, test.host, err)
+ }
+ if err == nil && !test.allow {
+ t.Errorf("%d: policy(%q): nil; want an error", i, test.host)
+ }
+ }
+}
+
+func TestValidCert(t *testing.T) {
+ key1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ key2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ key3, err := rsa.GenerateKey(rand.Reader, 512)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert1, err := dummyCert(key1.Public(), "example.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert2, err := dummyCert(key2.Public(), "example.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert3, err := dummyCert(key3.Public(), "example.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+ now := time.Now()
+ early, err := dateDummyCert(key1.Public(), now.Add(time.Hour), now.Add(2*time.Hour), "example.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+ expired, err := dateDummyCert(key1.Public(), now.Add(-2*time.Hour), now.Add(-time.Hour), "example.org")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ tt := []struct {
+ domain string
+ key crypto.Signer
+ cert [][]byte
+ ok bool
+ }{
+ {"example.org", key1, [][]byte{cert1}, true},
+ {"example.org", key3, [][]byte{cert3}, true},
+ {"example.org", key1, [][]byte{cert1, cert2, cert3}, true},
+ {"example.org", key1, [][]byte{cert1, {1}}, false},
+ {"example.org", key1, [][]byte{{1}}, false},
+ {"example.org", key1, [][]byte{cert2}, false},
+ {"example.org", key2, [][]byte{cert1}, false},
+ {"example.org", key1, [][]byte{cert3}, false},
+ {"example.org", key3, [][]byte{cert1}, false},
+ {"example.net", key1, [][]byte{cert1}, false},
+ {"example.org", key1, [][]byte{early}, false},
+ {"example.org", key1, [][]byte{expired}, false},
+ }
+ for i, test := range tt {
+ leaf, err := validCert(test.domain, test.cert, test.key)
+ if err != nil && test.ok {
+ t.Errorf("%d: err = %v", i, err)
+ }
+ if err == nil && !test.ok {
+ t.Errorf("%d: err is nil", i)
+ }
+ if err == nil && test.ok && leaf == nil {
+ t.Errorf("%d: leaf is nil", i)
+ }
+ }
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go
new file mode 100644
index 0000000..1c67f6c
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go
@@ -0,0 +1,130 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+ "errors"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "golang.org/x/net/context"
+)
+
+// ErrCacheMiss is returned when a certificate is not found in cache.
+var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
+
+// Cache is used by Manager to store and retrieve previously obtained certificates
+// as opaque data.
+//
+// The key argument of the methods refers to a domain name but need not be an FQDN.
+// Cache implementations should not rely on the key naming pattern.
+type Cache interface {
+ // Get returns a certificate data for the specified key.
+ // If there's no such key, Get returns ErrCacheMiss.
+ Get(ctx context.Context, key string) ([]byte, error)
+
+ // Put stores the data in the cache under the specified key.
+ // Inderlying implementations may use any data storage format,
+ // as long as the reverse operation, Get, results in the original data.
+ Put(ctx context.Context, key string, data []byte) error
+
+ // Delete removes a certificate data from the cache under the specified key.
+ // If there's no such key in the cache, Delete returns nil.
+ Delete(ctx context.Context, key string) error
+}
+
+// DirCache implements Cache using a directory on the local filesystem.
+// If the directory does not exist, it will be created with 0700 permissions.
+type DirCache string
+
+// Get reads a certificate data from the specified file name.
+func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
+ name = filepath.Join(string(d), name)
+ var (
+ data []byte
+ err error
+ done = make(chan struct{})
+ )
+ go func() {
+ data, err = ioutil.ReadFile(name)
+ close(done)
+ }()
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case <-done:
+ }
+ if os.IsNotExist(err) {
+ return nil, ErrCacheMiss
+ }
+ return data, err
+}
+
+// Put writes the certificate data to the specified file name.
+// The file will be created with 0600 permissions.
+func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
+ if err := os.MkdirAll(string(d), 0700); err != nil {
+ return err
+ }
+
+ done := make(chan struct{})
+ var err error
+ go func() {
+ defer close(done)
+ var tmp string
+ if tmp, err = d.writeTempFile(name, data); err != nil {
+ return
+ }
+ // prevent overwriting the file if the context was cancelled
+ if ctx.Err() != nil {
+ return // no need to set err
+ }
+ name = filepath.Join(string(d), name)
+ err = os.Rename(tmp, name)
+ }()
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-done:
+ }
+ return err
+}
+
+// Delete removes the specified file name.
+func (d DirCache) Delete(ctx context.Context, name string) error {
+ name = filepath.Join(string(d), name)
+ var (
+ err error
+ done = make(chan struct{})
+ )
+ go func() {
+ err = os.Remove(name)
+ close(done)
+ }()
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-done:
+ }
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ return nil
+}
+
+// writeTempFile writes b to a temporary file, closes the file and returns its path.
+func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
+ // TempFile uses 0600 permissions
+ f, err := ioutil.TempFile(string(d), prefix)
+ if err != nil {
+ return "", err
+ }
+ if _, err := f.Write(b); err != nil {
+ f.Close()
+ return "", err
+ }
+ return f.Name(), f.Close()
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go
new file mode 100644
index 0000000..ad6d4a4
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go
@@ -0,0 +1,58 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+
+ "golang.org/x/net/context"
+)
+
+// make sure DirCache satisfies Cache interface
+var _ Cache = DirCache("/")
+
+func TestDirCache(t *testing.T) {
+ dir, err := ioutil.TempDir("", "autocert")
+ if err != nil {
+ t.Fatal(err)
+ }
+ dir = filepath.Join(dir, "certs") // a nonexistent dir
+ cache := DirCache(dir)
+ ctx := context.Background()
+
+ // test cache miss
+ if _, err := cache.Get(ctx, "nonexistent"); err != ErrCacheMiss {
+ t.Errorf("get: %v; want ErrCacheMiss", err)
+ }
+
+ // test put/get
+ b1 := []byte{1}
+ if err := cache.Put(ctx, "dummy", b1); err != nil {
+ t.Fatalf("put: %v", err)
+ }
+ b2, err := cache.Get(ctx, "dummy")
+ if err != nil {
+ t.Fatalf("get: %v", err)
+ }
+ if !reflect.DeepEqual(b1, b2) {
+ t.Errorf("b1 = %v; want %v", b1, b2)
+ }
+ name := filepath.Join(dir, "dummy")
+ if _, err := os.Stat(name); err != nil {
+ t.Error(err)
+ }
+
+ // test delete
+ if err := cache.Delete(ctx, "dummy"); err != nil {
+ t.Fatalf("delete: %v", err)
+ }
+ if _, err := cache.Get(ctx, "dummy"); err != ErrCacheMiss {
+ t.Errorf("get: %v; want ErrCacheMiss", err)
+ }
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go
new file mode 100644
index 0000000..1a5018c
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go
@@ -0,0 +1,125 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+ "crypto"
+ "sync"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+// maxRandRenew is a maximum deviation from Manager.RenewBefore.
+const maxRandRenew = time.Hour
+
+// domainRenewal tracks the state used by the periodic timers
+// renewing a single domain's cert.
+type domainRenewal struct {
+ m *Manager
+ domain string
+ key crypto.Signer
+
+ timerMu sync.Mutex
+ timer *time.Timer
+}
+
+// start starts a cert renewal timer at the time
+// defined by the certificate expiration time exp.
+//
+// If the timer is already started, calling start is a noop.
+func (dr *domainRenewal) start(exp time.Time) {
+ dr.timerMu.Lock()
+ defer dr.timerMu.Unlock()
+ if dr.timer != nil {
+ return
+ }
+ dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
+}
+
+// stop stops the cert renewal timer.
+// If the timer is already stopped, calling stop is a noop.
+func (dr *domainRenewal) stop() {
+ dr.timerMu.Lock()
+ defer dr.timerMu.Unlock()
+ if dr.timer == nil {
+ return
+ }
+ dr.timer.Stop()
+ dr.timer = nil
+}
+
+// renew is called periodically by a timer.
+// The first renew call is kicked off by dr.start.
+func (dr *domainRenewal) renew() {
+ dr.timerMu.Lock()
+ defer dr.timerMu.Unlock()
+ if dr.timer == nil {
+ return
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
+ defer cancel()
+ // TODO: rotate dr.key at some point?
+ next, err := dr.do(ctx)
+ if err != nil {
+ next = maxRandRenew / 2
+ next += time.Duration(pseudoRand.int63n(int64(next)))
+ }
+ dr.timer = time.AfterFunc(next, dr.renew)
+ testDidRenewLoop(next, err)
+}
+
+// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
+// Instead, it requests a new certificate independently and, upon success,
+// replaces dr.m.state item with a new one and updates cache for the given domain.
+//
+// It may return immediately if the expiration date of the currently cached cert
+// is far enough in the future.
+//
+// The returned value is a time interval after which the renewal should occur again.
+func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
+ // a race is likely unavoidable in a distributed environment
+ // but we try nonetheless
+ if tlscert, err := dr.m.cacheGet(dr.domain); err == nil {
+ next := dr.next(tlscert.Leaf.NotAfter)
+ if next > dr.m.renewBefore()+maxRandRenew {
+ return next, nil
+ }
+ }
+
+ der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain)
+ if err != nil {
+ return 0, err
+ }
+ state := &certState{
+ key: dr.key,
+ cert: der,
+ leaf: leaf,
+ }
+ tlscert, err := state.tlscert()
+ if err != nil {
+ return 0, err
+ }
+ dr.m.cachePut(dr.domain, tlscert)
+ dr.m.stateMu.Lock()
+ defer dr.m.stateMu.Unlock()
+ // m.state is guaranteed to be non-nil at this point
+ dr.m.state[dr.domain] = state
+ return dr.next(leaf.NotAfter), nil
+}
+
+func (dr *domainRenewal) next(expiry time.Time) time.Duration {
+ d := expiry.Sub(timeNow()) - dr.m.renewBefore()
+ // add a bit of randomness to renew deadline
+ n := pseudoRand.int63n(int64(maxRandRenew))
+ d -= time.Duration(n)
+ if d < 0 {
+ return 0
+ }
+ return d
+}
+
+var testDidRenewLoop = func(next time.Duration, err error) {}
diff --git a/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go
new file mode 100644
index 0000000..d1ec52f
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go
@@ -0,0 +1,190 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "golang.org/x/crypto/acme"
+)
+
+func TestRenewalNext(t *testing.T) {
+ now := time.Now()
+ timeNow = func() time.Time { return now }
+ defer func() { timeNow = time.Now }()
+
+ man := &Manager{RenewBefore: 7 * 24 * time.Hour}
+ defer man.stopRenew()
+ tt := []struct {
+ expiry time.Time
+ min, max time.Duration
+ }{
+ {now.Add(90 * 24 * time.Hour), 83*24*time.Hour - maxRandRenew, 83 * 24 * time.Hour},
+ {now.Add(time.Hour), 0, 1},
+ {now, 0, 1},
+ {now.Add(-time.Hour), 0, 1},
+ }
+
+ dr := &domainRenewal{m: man}
+ for i, test := range tt {
+ next := dr.next(test.expiry)
+ if next < test.min || test.max < next {
+ t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max)
+ }
+ }
+}
+
+func TestRenewFromCache(t *testing.T) {
+ const domain = "example.org"
+
+ // ACME CA server stub
+ var ca *httptest.Server
+ ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("replay-nonce", "nonce")
+ if r.Method == "HEAD" {
+ // a nonce request
+ return
+ }
+
+ switch r.URL.Path {
+ // discovery
+ case "/":
+ if err := discoTmpl.Execute(w, ca.URL); err != nil {
+ t.Fatalf("discoTmpl: %v", err)
+ }
+ // client key registration
+ case "/new-reg":
+ w.Write([]byte("{}"))
+ // domain authorization
+ case "/new-authz":
+ w.Header().Set("location", ca.URL+"/authz/1")
+ w.WriteHeader(http.StatusCreated)
+ w.Write([]byte(`{"status": "valid"}`))
+ // cert request
+ case "/new-cert":
+ var req struct {
+ CSR string `json:"csr"`
+ }
+ decodePayload(&req, r.Body)
+ b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
+ csr, err := x509.ParseCertificateRequest(b)
+ if err != nil {
+ t.Fatalf("new-cert: CSR: %v", err)
+ }
+ der, err := dummyCert(csr.PublicKey, domain)
+ if err != nil {
+ t.Fatalf("new-cert: dummyCert: %v", err)
+ }
+ chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
+ w.Header().Set("link", chainUp)
+ w.WriteHeader(http.StatusCreated)
+ w.Write(der)
+ // CA chain cert
+ case "/ca-cert":
+ der, err := dummyCert(nil, "ca")
+ if err != nil {
+ t.Fatalf("ca-cert: dummyCert: %v", err)
+ }
+ w.Write(der)
+ default:
+ t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+ }
+ }))
+ defer ca.Close()
+
+ // use EC key to run faster on 386
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ man := &Manager{
+ Prompt: AcceptTOS,
+ Cache: make(memCache),
+ RenewBefore: 24 * time.Hour,
+ Client: &acme.Client{
+ Key: key,
+ DirectoryURL: ca.URL,
+ },
+ }
+ defer man.stopRenew()
+
+ // cache an almost expired cert
+ now := time.Now()
+ cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
+ if err := man.cachePut(domain, tlscert); err != nil {
+ t.Fatal(err)
+ }
+
+ // veriy the renewal happened
+ defer func() {
+ testDidRenewLoop = func(next time.Duration, err error) {}
+ }()
+ done := make(chan struct{})
+ testDidRenewLoop = func(next time.Duration, err error) {
+ defer close(done)
+ if err != nil {
+ t.Errorf("testDidRenewLoop: %v", err)
+ }
+ // Next should be about 90 days:
+ // dummyCert creates 90days expiry + account for man.RenewBefore.
+ // Previous expiration was within 1 min.
+ future := 88 * 24 * time.Hour
+ if next < future {
+ t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
+ }
+
+ // ensure the new cert is cached
+ after := time.Now().Add(future)
+ tlscert, err := man.cacheGet(domain)
+ if err != nil {
+ t.Fatalf("man.cacheGet: %v", err)
+ }
+ if !tlscert.Leaf.NotAfter.After(after) {
+ t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
+ }
+
+ // verify the old cert is also replaced in memory
+ man.stateMu.Lock()
+ defer man.stateMu.Unlock()
+ s := man.state[domain]
+ if s == nil {
+ t.Fatalf("m.state[%q] is nil", domain)
+ }
+ tlscert, err = s.tlscert()
+ if err != nil {
+ t.Fatalf("s.tlscert: %v", err)
+ }
+ if !tlscert.Leaf.NotAfter.After(after) {
+ t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
+ }
+ }
+
+ // trigger renew
+ hello := &tls.ClientHelloInfo{ServerName: domain}
+ if _, err := man.GetCertificate(hello); err != nil {
+ t.Fatal(err)
+ }
+
+ // wait for renew loop
+ select {
+ case <-time.After(10 * time.Second):
+ t.Fatal("renew took too long to occur")
+ case <-done:
+ }
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/context.go b/cmd/ponzu/vendor/golang.org/x/net/context/context.go
new file mode 100644
index 0000000..134654c
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/context.go
@@ -0,0 +1,156 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package context defines the Context type, which carries deadlines,
+// cancelation signals, and other request-scoped values across API boundaries
+// and between processes.
+//
+// Incoming requests to a server should create a Context, and outgoing calls to
+// servers should accept a Context. The chain of function calls between must
+// propagate the Context, optionally replacing it with a modified copy created
+// using WithDeadline, WithTimeout, WithCancel, or WithValue.
+//
+// Programs that use Contexts should follow these rules to keep interfaces
+// consistent across packages and enable static analysis tools to check context
+// propagation:
+//
+// Do not store Contexts inside a struct type; instead, pass a Context
+// explicitly to each function that needs it. The Context should be the first
+// parameter, typically named ctx:
+//
+// func DoSomething(ctx context.Context, arg Arg) error {
+// // ... use ctx ...
+// }
+//
+// Do not pass a nil Context, even if a function permits it. Pass context.TODO
+// if you are unsure about which Context to use.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The same Context may be passed to functions running in different goroutines;
+// Contexts are safe for simultaneous use by multiple goroutines.
+//
+// See http://blog.golang.org/context for example code for a server that uses
+// Contexts.
+package context // import "golang.org/x/net/context"
+
+import "time"
+
+// A Context carries a deadline, a cancelation signal, and other values across
+// API boundaries.
+//
+// Context's methods may be called by multiple goroutines simultaneously.
+type Context interface {
+ // Deadline returns the time when work done on behalf of this context
+ // should be canceled. Deadline returns ok==false when no deadline is
+ // set. Successive calls to Deadline return the same results.
+ Deadline() (deadline time.Time, ok bool)
+
+ // Done returns a channel that's closed when work done on behalf of this
+ // context should be canceled. Done may return nil if this context can
+ // never be canceled. Successive calls to Done return the same value.
+ //
+ // WithCancel arranges for Done to be closed when cancel is called;
+ // WithDeadline arranges for Done to be closed when the deadline
+ // expires; WithTimeout arranges for Done to be closed when the timeout
+ // elapses.
+ //
+ // Done is provided for use in select statements:
+ //
+ // // Stream generates values with DoSomething and sends them to out
+ // // until DoSomething returns an error or ctx.Done is closed.
+ // func Stream(ctx context.Context, out chan<- Value) error {
+ // for {
+ // v, err := DoSomething(ctx)
+ // if err != nil {
+ // return err
+ // }
+ // select {
+ // case <-ctx.Done():
+ // return ctx.Err()
+ // case out <- v:
+ // }
+ // }
+ // }
+ //
+ // See http://blog.golang.org/pipelines for more examples of how to use
+ // a Done channel for cancelation.
+ Done() <-chan struct{}
+
+ // Err returns a non-nil error value after Done is closed. Err returns
+ // Canceled if the context was canceled or DeadlineExceeded if the
+ // context's deadline passed. No other values for Err are defined.
+ // After Done is closed, successive calls to Err return the same value.
+ Err() error
+
+ // Value returns the value associated with this context for key, or nil
+ // if no value is associated with key. Successive calls to Value with
+ // the same key returns the same result.
+ //
+ // Use context values only for request-scoped data that transits
+ // processes and API boundaries, not for passing optional parameters to
+ // functions.
+ //
+ // A key identifies a specific value in a Context. Functions that wish
+ // to store values in Context typically allocate a key in a global
+ // variable then use that key as the argument to context.WithValue and
+ // Context.Value. A key can be any type that supports equality;
+ // packages should define keys as an unexported type to avoid
+ // collisions.
+ //
+ // Packages that define a Context key should provide type-safe accessors
+ // for the values stores using that key:
+ //
+ // // Package user defines a User type that's stored in Contexts.
+ // package user
+ //
+ // import "golang.org/x/net/context"
+ //
+ // // User is the type of value stored in the Contexts.
+ // type User struct {...}
+ //
+ // // key is an unexported type for keys defined in this package.
+ // // This prevents collisions with keys defined in other packages.
+ // type key int
+ //
+ // // userKey is the key for user.User values in Contexts. It is
+ // // unexported; clients use user.NewContext and user.FromContext
+ // // instead of using this key directly.
+ // var userKey key = 0
+ //
+ // // NewContext returns a new Context that carries value u.
+ // func NewContext(ctx context.Context, u *User) context.Context {
+ // return context.WithValue(ctx, userKey, u)
+ // }
+ //
+ // // FromContext returns the User value stored in ctx, if any.
+ // func FromContext(ctx context.Context) (*User, bool) {
+ // u, ok := ctx.Value(userKey).(*User)
+ // return u, ok
+ // }
+ Value(key interface{}) interface{}
+}
+
+// Background returns a non-nil, empty Context. It is never canceled, has no
+// values, and has no deadline. It is typically used by the main function,
+// initialization, and tests, and as the top-level Context for incoming
+// requests.
+func Background() Context {
+ return background
+}
+
+// TODO returns a non-nil, empty Context. Code should use context.TODO when
+// it's unclear which Context to use or it is not yet available (because the
+// surrounding function has not yet been extended to accept a Context
+// parameter). TODO is recognized by static analysis tools that determine
+// whether Contexts are propagated correctly in a program.
+func TODO() Context {
+ return todo
+}
+
+// A CancelFunc tells an operation to abandon its work.
+// A CancelFunc does not wait for the work to stop.
+// After the first call, subsequent calls to a CancelFunc do nothing.
+type CancelFunc func()
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go b/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go
new file mode 100644
index 0000000..9554dcf
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go
@@ -0,0 +1,577 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7
+
+package context
+
+import (
+ "fmt"
+ "math/rand"
+ "runtime"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+// otherContext is a Context that's not one of the types defined in context.go.
+// This lets us test code paths that differ based on the underlying type of the
+// Context.
+type otherContext struct {
+ Context
+}
+
+func TestBackground(t *testing.T) {
+ c := Background()
+ if c == nil {
+ t.Fatalf("Background returned nil")
+ }
+ select {
+ case x := <-c.Done():
+ t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ if got, want := fmt.Sprint(c), "context.Background"; got != want {
+ t.Errorf("Background().String() = %q want %q", got, want)
+ }
+}
+
+func TestTODO(t *testing.T) {
+ c := TODO()
+ if c == nil {
+ t.Fatalf("TODO returned nil")
+ }
+ select {
+ case x := <-c.Done():
+ t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ if got, want := fmt.Sprint(c), "context.TODO"; got != want {
+ t.Errorf("TODO().String() = %q want %q", got, want)
+ }
+}
+
+func TestWithCancel(t *testing.T) {
+ c1, cancel := WithCancel(Background())
+
+ if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
+ t.Errorf("c1.String() = %q want %q", got, want)
+ }
+
+ o := otherContext{c1}
+ c2, _ := WithCancel(o)
+ contexts := []Context{c1, o, c2}
+
+ for i, c := range contexts {
+ if d := c.Done(); d == nil {
+ t.Errorf("c[%d].Done() == %v want non-nil", i, d)
+ }
+ if e := c.Err(); e != nil {
+ t.Errorf("c[%d].Err() == %v want nil", i, e)
+ }
+
+ select {
+ case x := <-c.Done():
+ t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ }
+
+ cancel()
+ time.Sleep(100 * time.Millisecond) // let cancelation propagate
+
+ for i, c := range contexts {
+ select {
+ case <-c.Done():
+ default:
+ t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
+ }
+ if e := c.Err(); e != Canceled {
+ t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
+ }
+ }
+}
+
+func TestParentFinishesChild(t *testing.T) {
+ // Context tree:
+ // parent -> cancelChild
+ // parent -> valueChild -> timerChild
+ parent, cancel := WithCancel(Background())
+ cancelChild, stop := WithCancel(parent)
+ defer stop()
+ valueChild := WithValue(parent, "key", "value")
+ timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
+ defer stop()
+
+ select {
+ case x := <-parent.Done():
+ t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+ case x := <-cancelChild.Done():
+ t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
+ case x := <-timerChild.Done():
+ t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
+ case x := <-valueChild.Done():
+ t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+
+ // The parent's children should contain the two cancelable children.
+ pc := parent.(*cancelCtx)
+ cc := cancelChild.(*cancelCtx)
+ tc := timerChild.(*timerCtx)
+ pc.mu.Lock()
+ if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
+ t.Errorf("bad linkage: pc.children = %v, want %v and %v",
+ pc.children, cc, tc)
+ }
+ pc.mu.Unlock()
+
+ if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
+ t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
+ }
+ if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
+ t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
+ }
+
+ cancel()
+
+ pc.mu.Lock()
+ if len(pc.children) != 0 {
+ t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
+ }
+ pc.mu.Unlock()
+
+ // parent and children should all be finished.
+ check := func(ctx Context, name string) {
+ select {
+ case <-ctx.Done():
+ default:
+ t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
+ }
+ if e := ctx.Err(); e != Canceled {
+ t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
+ }
+ }
+ check(parent, "parent")
+ check(cancelChild, "cancelChild")
+ check(valueChild, "valueChild")
+ check(timerChild, "timerChild")
+
+ // WithCancel should return a canceled context on a canceled parent.
+ precanceledChild := WithValue(parent, "key", "value")
+ select {
+ case <-precanceledChild.Done():
+ default:
+ t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
+ }
+ if e := precanceledChild.Err(); e != Canceled {
+ t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
+ }
+}
+
+func TestChildFinishesFirst(t *testing.T) {
+ cancelable, stop := WithCancel(Background())
+ defer stop()
+ for _, parent := range []Context{Background(), cancelable} {
+ child, cancel := WithCancel(parent)
+
+ select {
+ case x := <-parent.Done():
+ t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+ case x := <-child.Done():
+ t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+
+ cc := child.(*cancelCtx)
+ pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
+ if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
+ t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
+ }
+
+ if pcok {
+ pc.mu.Lock()
+ if len(pc.children) != 1 || !pc.children[cc] {
+ t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
+ }
+ pc.mu.Unlock()
+ }
+
+ cancel()
+
+ if pcok {
+ pc.mu.Lock()
+ if len(pc.children) != 0 {
+ t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
+ }
+ pc.mu.Unlock()
+ }
+
+ // child should be finished.
+ select {
+ case <-child.Done():
+ default:
+ t.Errorf("<-child.Done() blocked, but shouldn't have")
+ }
+ if e := child.Err(); e != Canceled {
+ t.Errorf("child.Err() == %v want %v", e, Canceled)
+ }
+
+ // parent should not be finished.
+ select {
+ case x := <-parent.Done():
+ t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+ default:
+ }
+ if e := parent.Err(); e != nil {
+ t.Errorf("parent.Err() == %v want nil", e)
+ }
+ }
+}
+
+func testDeadline(c Context, wait time.Duration, t *testing.T) {
+ select {
+ case <-time.After(wait):
+ t.Fatalf("context should have timed out")
+ case <-c.Done():
+ }
+ if e := c.Err(); e != DeadlineExceeded {
+ t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded)
+ }
+}
+
+func TestDeadline(t *testing.T) {
+ c, _ := WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
+ if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+ t.Errorf("c.String() = %q want prefix %q", got, prefix)
+ }
+ testDeadline(c, 200*time.Millisecond, t)
+
+ c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
+ o := otherContext{c}
+ testDeadline(o, 200*time.Millisecond, t)
+
+ c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
+ o = otherContext{c}
+ c, _ = WithDeadline(o, time.Now().Add(300*time.Millisecond))
+ testDeadline(c, 200*time.Millisecond, t)
+}
+
+func TestTimeout(t *testing.T) {
+ c, _ := WithTimeout(Background(), 100*time.Millisecond)
+ if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+ t.Errorf("c.String() = %q want prefix %q", got, prefix)
+ }
+ testDeadline(c, 200*time.Millisecond, t)
+
+ c, _ = WithTimeout(Background(), 100*time.Millisecond)
+ o := otherContext{c}
+ testDeadline(o, 200*time.Millisecond, t)
+
+ c, _ = WithTimeout(Background(), 100*time.Millisecond)
+ o = otherContext{c}
+ c, _ = WithTimeout(o, 300*time.Millisecond)
+ testDeadline(c, 200*time.Millisecond, t)
+}
+
+func TestCanceledTimeout(t *testing.T) {
+ c, _ := WithTimeout(Background(), 200*time.Millisecond)
+ o := otherContext{c}
+ c, cancel := WithTimeout(o, 400*time.Millisecond)
+ cancel()
+ time.Sleep(100 * time.Millisecond) // let cancelation propagate
+ select {
+ case <-c.Done():
+ default:
+ t.Errorf("<-c.Done() blocked, but shouldn't have")
+ }
+ if e := c.Err(); e != Canceled {
+ t.Errorf("c.Err() == %v want %v", e, Canceled)
+ }
+}
+
+type key1 int
+type key2 int
+
+var k1 = key1(1)
+var k2 = key2(1) // same int as k1, different type
+var k3 = key2(3) // same type as k2, different int
+
+func TestValues(t *testing.T) {
+ check := func(c Context, nm, v1, v2, v3 string) {
+ if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
+ t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
+ }
+ if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
+ t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
+ }
+ if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
+ t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
+ }
+ }
+
+ c0 := Background()
+ check(c0, "c0", "", "", "")
+
+ c1 := WithValue(Background(), k1, "c1k1")
+ check(c1, "c1", "c1k1", "", "")
+
+ if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
+ t.Errorf("c.String() = %q want %q", got, want)
+ }
+
+ c2 := WithValue(c1, k2, "c2k2")
+ check(c2, "c2", "c1k1", "c2k2", "")
+
+ c3 := WithValue(c2, k3, "c3k3")
+ check(c3, "c2", "c1k1", "c2k2", "c3k3")
+
+ c4 := WithValue(c3, k1, nil)
+ check(c4, "c4", "", "c2k2", "c3k3")
+
+ o0 := otherContext{Background()}
+ check(o0, "o0", "", "", "")
+
+ o1 := otherContext{WithValue(Background(), k1, "c1k1")}
+ check(o1, "o1", "c1k1", "", "")
+
+ o2 := WithValue(o1, k2, "o2k2")
+ check(o2, "o2", "c1k1", "o2k2", "")
+
+ o3 := otherContext{c4}
+ check(o3, "o3", "", "c2k2", "c3k3")
+
+ o4 := WithValue(o3, k3, nil)
+ check(o4, "o4", "", "c2k2", "")
+}
+
+func TestAllocs(t *testing.T) {
+ bg := Background()
+ for _, test := range []struct {
+ desc string
+ f func()
+ limit float64
+ gccgoLimit float64
+ }{
+ {
+ desc: "Background()",
+ f: func() { Background() },
+ limit: 0,
+ gccgoLimit: 0,
+ },
+ {
+ desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
+ f: func() {
+ c := WithValue(bg, k1, nil)
+ c.Value(k1)
+ },
+ limit: 3,
+ gccgoLimit: 3,
+ },
+ {
+ desc: "WithTimeout(bg, 15*time.Millisecond)",
+ f: func() {
+ c, _ := WithTimeout(bg, 15*time.Millisecond)
+ <-c.Done()
+ },
+ limit: 8,
+ gccgoLimit: 16,
+ },
+ {
+ desc: "WithCancel(bg)",
+ f: func() {
+ c, cancel := WithCancel(bg)
+ cancel()
+ <-c.Done()
+ },
+ limit: 5,
+ gccgoLimit: 8,
+ },
+ {
+ desc: "WithTimeout(bg, 100*time.Millisecond)",
+ f: func() {
+ c, cancel := WithTimeout(bg, 100*time.Millisecond)
+ cancel()
+ <-c.Done()
+ },
+ limit: 8,
+ gccgoLimit: 25,
+ },
+ } {
+ limit := test.limit
+ if runtime.Compiler == "gccgo" {
+ // gccgo does not yet do escape analysis.
+ // TODO(iant): Remove this when gccgo does do escape analysis.
+ limit = test.gccgoLimit
+ }
+ if n := testing.AllocsPerRun(100, test.f); n > limit {
+ t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
+ }
+ }
+}
+
+func TestSimultaneousCancels(t *testing.T) {
+ root, cancel := WithCancel(Background())
+ m := map[Context]CancelFunc{root: cancel}
+ q := []Context{root}
+ // Create a tree of contexts.
+ for len(q) != 0 && len(m) < 100 {
+ parent := q[0]
+ q = q[1:]
+ for i := 0; i < 4; i++ {
+ ctx, cancel := WithCancel(parent)
+ m[ctx] = cancel
+ q = append(q, ctx)
+ }
+ }
+ // Start all the cancels in a random order.
+ var wg sync.WaitGroup
+ wg.Add(len(m))
+ for _, cancel := range m {
+ go func(cancel CancelFunc) {
+ cancel()
+ wg.Done()
+ }(cancel)
+ }
+ // Wait on all the contexts in a random order.
+ for ctx := range m {
+ select {
+ case <-ctx.Done():
+ case <-time.After(1 * time.Second):
+ buf := make([]byte, 10<<10)
+ n := runtime.Stack(buf, true)
+ t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
+ }
+ }
+ // Wait for all the cancel functions to return.
+ done := make(chan struct{})
+ go func() {
+ wg.Wait()
+ close(done)
+ }()
+ select {
+ case <-done:
+ case <-time.After(1 * time.Second):
+ buf := make([]byte, 10<<10)
+ n := runtime.Stack(buf, true)
+ t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
+ }
+}
+
+func TestInterlockedCancels(t *testing.T) {
+ parent, cancelParent := WithCancel(Background())
+ child, cancelChild := WithCancel(parent)
+ go func() {
+ parent.Done()
+ cancelChild()
+ }()
+ cancelParent()
+ select {
+ case <-child.Done():
+ case <-time.After(1 * time.Second):
+ buf := make([]byte, 10<<10)
+ n := runtime.Stack(buf, true)
+ t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
+ }
+}
+
+func TestLayersCancel(t *testing.T) {
+ testLayers(t, time.Now().UnixNano(), false)
+}
+
+func TestLayersTimeout(t *testing.T) {
+ testLayers(t, time.Now().UnixNano(), true)
+}
+
+func testLayers(t *testing.T, seed int64, testTimeout bool) {
+ rand.Seed(seed)
+ errorf := func(format string, a ...interface{}) {
+ t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
+ }
+ const (
+ timeout = 200 * time.Millisecond
+ minLayers = 30
+ )
+ type value int
+ var (
+ vals []*value
+ cancels []CancelFunc
+ numTimers int
+ ctx = Background()
+ )
+ for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
+ switch rand.Intn(3) {
+ case 0:
+ v := new(value)
+ ctx = WithValue(ctx, v, v)
+ vals = append(vals, v)
+ case 1:
+ var cancel CancelFunc
+ ctx, cancel = WithCancel(ctx)
+ cancels = append(cancels, cancel)
+ case 2:
+ var cancel CancelFunc
+ ctx, cancel = WithTimeout(ctx, timeout)
+ cancels = append(cancels, cancel)
+ numTimers++
+ }
+ }
+ checkValues := func(when string) {
+ for _, key := range vals {
+ if val := ctx.Value(key).(*value); key != val {
+ errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
+ }
+ }
+ }
+ select {
+ case <-ctx.Done():
+ errorf("ctx should not be canceled yet")
+ default:
+ }
+ if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
+ t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
+ }
+ t.Log(ctx)
+ checkValues("before cancel")
+ if testTimeout {
+ select {
+ case <-ctx.Done():
+ case <-time.After(timeout + 100*time.Millisecond):
+ errorf("ctx should have timed out")
+ }
+ checkValues("after timeout")
+ } else {
+ cancel := cancels[rand.Intn(len(cancels))]
+ cancel()
+ select {
+ case <-ctx.Done():
+ default:
+ errorf("ctx should be canceled")
+ }
+ checkValues("after cancel")
+ }
+}
+
+func TestCancelRemoves(t *testing.T) {
+ checkChildren := func(when string, ctx Context, want int) {
+ if got := len(ctx.(*cancelCtx).children); got != want {
+ t.Errorf("%s: context has %d children, want %d", when, got, want)
+ }
+ }
+
+ ctx, _ := WithCancel(Background())
+ checkChildren("after creation", ctx, 0)
+ _, cancel := WithCancel(ctx)
+ checkChildren("with WithCancel child ", ctx, 1)
+ cancel()
+ checkChildren("after cancelling WithCancel child", ctx, 0)
+
+ ctx, _ = WithCancel(Background())
+ checkChildren("after creation", ctx, 0)
+ _, cancel = WithTimeout(ctx, 60*time.Minute)
+ checkChildren("with WithTimeout child ", ctx, 1)
+ cancel()
+ checkChildren("after cancelling WithTimeout child", ctx, 0)
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
new file mode 100644
index 0000000..606cf1f
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
@@ -0,0 +1,74 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
+package ctxhttp // import "golang.org/x/net/context/ctxhttp"
+
+import (
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "golang.org/x/net/context"
+)
+
+// Do sends an HTTP request with the provided http.Client and returns
+// an HTTP response.
+//
+// If the client is nil, http.DefaultClient is used.
+//
+// The provided ctx must be non-nil. If it is canceled or times out,
+// ctx.Err() will be returned.
+func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
+ if client == nil {
+ client = http.DefaultClient
+ }
+ resp, err := client.Do(req.WithContext(ctx))
+ // If we got an error, and the context has been canceled,
+ // the context's error is probably more useful.
+ if err != nil {
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ default:
+ }
+ }
+ return resp, err
+}
+
+// Get issues a GET request via the Do function.
+func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return Do(ctx, client, req)
+}
+
+// Head issues a HEAD request via the Do function.
+func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+ req, err := http.NewRequest("HEAD", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return Do(ctx, client, req)
+}
+
+// Post issues a POST request via the Do function.
+func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
+ req, err := http.NewRequest("POST", url, body)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", bodyType)
+ return Do(ctx, client, req)
+}
+
+// PostForm issues a POST request via the Do function.
+func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
+ return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
new file mode 100644
index 0000000..9f0f90f
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
@@ -0,0 +1,28 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,go1.7
+
+package ctxhttp
+
+import (
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "context"
+)
+
+func TestGo17Context(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "ok")
+ }))
+ ctx := context.Background()
+ resp, err := Get(ctx, http.DefaultClient, ts.URL)
+ if resp == nil || err != nil {
+ t.Fatalf("error received from client: %v %v", err, resp)
+ }
+ resp.Body.Close()
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
new file mode 100644
index 0000000..926870c
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
@@ -0,0 +1,147 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7
+
+package ctxhttp // import "golang.org/x/net/context/ctxhttp"
+
+import (
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "golang.org/x/net/context"
+)
+
+func nop() {}
+
+var (
+ testHookContextDoneBeforeHeaders = nop
+ testHookDoReturned = nop
+ testHookDidBodyClose = nop
+)
+
+// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
+// If the client is nil, http.DefaultClient is used.
+// If the context is canceled or times out, ctx.Err() will be returned.
+func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
+ if client == nil {
+ client = http.DefaultClient
+ }
+
+ // TODO(djd): Respect any existing value of req.Cancel.
+ cancel := make(chan struct{})
+ req.Cancel = cancel
+
+ type responseAndError struct {
+ resp *http.Response
+ err error
+ }
+ result := make(chan responseAndError, 1)
+
+ // Make local copies of test hooks closed over by goroutines below.
+ // Prevents data races in tests.
+ testHookDoReturned := testHookDoReturned
+ testHookDidBodyClose := testHookDidBodyClose
+
+ go func() {
+ resp, err := client.Do(req)
+ testHookDoReturned()
+ result <- responseAndError{resp, err}
+ }()
+
+ var resp *http.Response
+
+ select {
+ case <-ctx.Done():
+ testHookContextDoneBeforeHeaders()
+ close(cancel)
+ // Clean up after the goroutine calling client.Do:
+ go func() {
+ if r := <-result; r.resp != nil {
+ testHookDidBodyClose()
+ r.resp.Body.Close()
+ }
+ }()
+ return nil, ctx.Err()
+ case r := <-result:
+ var err error
+ resp, err = r.resp, r.err
+ if err != nil {
+ return resp, err
+ }
+ }
+
+ c := make(chan struct{})
+ go func() {
+ select {
+ case <-ctx.Done():
+ close(cancel)
+ case <-c:
+ // The response's Body is closed.
+ }
+ }()
+ resp.Body = &notifyingReader{resp.Body, c}
+
+ return resp, nil
+}
+
+// Get issues a GET request via the Do function.
+func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return Do(ctx, client, req)
+}
+
+// Head issues a HEAD request via the Do function.
+func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+ req, err := http.NewRequest("HEAD", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return Do(ctx, client, req)
+}
+
+// Post issues a POST request via the Do function.
+func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
+ req, err := http.NewRequest("POST", url, body)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", bodyType)
+ return Do(ctx, client, req)
+}
+
+// PostForm issues a POST request via the Do function.
+func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
+ return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
+}
+
+// notifyingReader is an io.ReadCloser that closes the notify channel after
+// Close is called or a Read fails on the underlying ReadCloser.
+type notifyingReader struct {
+ io.ReadCloser
+ notify chan<- struct{}
+}
+
+func (r *notifyingReader) Read(p []byte) (int, error) {
+ n, err := r.ReadCloser.Read(p)
+ if err != nil && r.notify != nil {
+ close(r.notify)
+ r.notify = nil
+ }
+ return n, err
+}
+
+func (r *notifyingReader) Close() error {
+ err := r.ReadCloser.Close()
+ if r.notify != nil {
+ close(r.notify)
+ r.notify = nil
+ }
+ return err
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
new file mode 100644
index 0000000..9159cf0
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
@@ -0,0 +1,79 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!go1.7
+
+package ctxhttp
+
+import (
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "sync"
+ "testing"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+// golang.org/issue/14065
+func TestClosesResponseBodyOnCancel(t *testing.T) {
+ defer func() { testHookContextDoneBeforeHeaders = nop }()
+ defer func() { testHookDoReturned = nop }()
+ defer func() { testHookDidBodyClose = nop }()
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+ defer ts.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ // closed when Do enters select case <-ctx.Done()
+ enteredDonePath := make(chan struct{})
+
+ testHookContextDoneBeforeHeaders = func() {
+ close(enteredDonePath)
+ }
+
+ testHookDoReturned = func() {
+ // We now have the result (the Flush'd headers) at least,
+ // so we can cancel the request.
+ cancel()
+
+ // But block the client.Do goroutine from sending
+ // until Do enters into the <-ctx.Done() path, since
+ // otherwise if both channels are readable, select
+ // picks a random one.
+ <-enteredDonePath
+ }
+
+ sawBodyClose := make(chan struct{})
+ testHookDidBodyClose = func() { close(sawBodyClose) }
+
+ tr := &http.Transport{}
+ defer tr.CloseIdleConnections()
+ c := &http.Client{Transport: tr}
+ req, _ := http.NewRequest("GET", ts.URL, nil)
+ _, doErr := Do(ctx, c, req)
+
+ select {
+ case <-sawBodyClose:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout waiting for body to close")
+ }
+
+ if doErr != ctx.Err() {
+ t.Errorf("Do error = %v; want %v", doErr, ctx.Err())
+ }
+}
+
+type noteCloseConn struct {
+ net.Conn
+ onceClose sync.Once
+ closefn func()
+}
+
+func (c *noteCloseConn) Close() error {
+ c.onceClose.Do(c.closefn)
+ return c.Conn.Close()
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
new file mode 100644
index 0000000..1e41551
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
@@ -0,0 +1,105 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+package ctxhttp
+
+import (
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+const (
+ requestDuration = 100 * time.Millisecond
+ requestBody = "ok"
+)
+
+func okHandler(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(requestDuration)
+ io.WriteString(w, requestBody)
+}
+
+func TestNoTimeout(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(okHandler))
+ defer ts.Close()
+
+ ctx := context.Background()
+ res, err := Get(ctx, nil, ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(slurp) != requestBody {
+ t.Errorf("body = %q; want %q", slurp, requestBody)
+ }
+}
+
+func TestCancelBeforeHeaders(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ blockServer := make(chan struct{})
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ cancel()
+ <-blockServer
+ io.WriteString(w, requestBody)
+ }))
+ defer ts.Close()
+ defer close(blockServer)
+
+ res, err := Get(ctx, nil, ts.URL)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("Get returned unexpected nil error")
+ }
+ if err != context.Canceled {
+ t.Errorf("err = %v; want %v", err, context.Canceled)
+ }
+}
+
+func TestCancelAfterHangingRequest(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ w.(http.Flusher).Flush()
+ <-w.(http.CloseNotifier).CloseNotify()
+ }))
+ defer ts.Close()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ resp, err := Get(ctx, nil, ts.URL)
+ if err != nil {
+ t.Fatalf("unexpected error in Get: %v", err)
+ }
+
+ // Cancel befer reading the body.
+ // Reading Request.Body should fail, since the request was
+ // canceled before anything was written.
+ cancel()
+
+ done := make(chan struct{})
+
+ go func() {
+ b, err := ioutil.ReadAll(resp.Body)
+ if len(b) != 0 || err == nil {
+ t.Errorf(`Read got (%q, %v); want ("", error)`, b, err)
+ }
+ close(done)
+ }()
+
+ select {
+ case <-time.After(1 * time.Second):
+ t.Errorf("Test timed out")
+ case <-done:
+ }
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/go17.go b/cmd/ponzu/vendor/golang.org/x/net/context/go17.go
new file mode 100644
index 0000000..f8cda19
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/go17.go
@@ -0,0 +1,72 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package context
+
+import (
+ "context" // standard library's context, as of Go 1.7
+ "time"
+)
+
+var (
+ todo = context.TODO()
+ background = context.Background()
+)
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = context.Canceled
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded = context.DeadlineExceeded
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+ ctx, f := context.WithCancel(parent)
+ return ctx, CancelFunc(f)
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
+ ctx, f := context.WithDeadline(parent, deadline)
+ return ctx, CancelFunc(f)
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// defer cancel() // releases resources if slowOperation completes before timeout elapses
+// return slowOperation(ctx)
+// }
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+ return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+func WithValue(parent Context, key interface{}, val interface{}) Context {
+ return context.WithValue(parent, key, val)
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go b/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go
new file mode 100644
index 0000000..5a30aca
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go
@@ -0,0 +1,300 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7
+
+package context
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+)
+
+// An emptyCtx is never canceled, has no values, and has no deadline. It is not
+// struct{}, since vars of this type must have distinct addresses.
+type emptyCtx int
+
+func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
+ return
+}
+
+func (*emptyCtx) Done() <-chan struct{} {
+ return nil
+}
+
+func (*emptyCtx) Err() error {
+ return nil
+}
+
+func (*emptyCtx) Value(key interface{}) interface{} {
+ return nil
+}
+
+func (e *emptyCtx) String() string {
+ switch e {
+ case background:
+ return "context.Background"
+ case todo:
+ return "context.TODO"
+ }
+ return "unknown empty Context"
+}
+
+var (
+ background = new(emptyCtx)
+ todo = new(emptyCtx)
+)
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = errors.New("context canceled")
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded = errors.New("context deadline exceeded")
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+ c := newCancelCtx(parent)
+ propagateCancel(parent, c)
+ return c, func() { c.cancel(true, Canceled) }
+}
+
+// newCancelCtx returns an initialized cancelCtx.
+func newCancelCtx(parent Context) *cancelCtx {
+ return &cancelCtx{
+ Context: parent,
+ done: make(chan struct{}),
+ }
+}
+
+// propagateCancel arranges for child to be canceled when parent is.
+func propagateCancel(parent Context, child canceler) {
+ if parent.Done() == nil {
+ return // parent is never canceled
+ }
+ if p, ok := parentCancelCtx(parent); ok {
+ p.mu.Lock()
+ if p.err != nil {
+ // parent has already been canceled
+ child.cancel(false, p.err)
+ } else {
+ if p.children == nil {
+ p.children = make(map[canceler]bool)
+ }
+ p.children[child] = true
+ }
+ p.mu.Unlock()
+ } else {
+ go func() {
+ select {
+ case <-parent.Done():
+ child.cancel(false, parent.Err())
+ case <-child.Done():
+ }
+ }()
+ }
+}
+
+// parentCancelCtx follows a chain of parent references until it finds a
+// *cancelCtx. This function understands how each of the concrete types in this
+// package represents its parent.
+func parentCancelCtx(parent Context) (*cancelCtx, bool) {
+ for {
+ switch c := parent.(type) {
+ case *cancelCtx:
+ return c, true
+ case *timerCtx:
+ return c.cancelCtx, true
+ case *valueCtx:
+ parent = c.Context
+ default:
+ return nil, false
+ }
+ }
+}
+
+// removeChild removes a context from its parent.
+func removeChild(parent Context, child canceler) {
+ p, ok := parentCancelCtx(parent)
+ if !ok {
+ return
+ }
+ p.mu.Lock()
+ if p.children != nil {
+ delete(p.children, child)
+ }
+ p.mu.Unlock()
+}
+
+// A canceler is a context type that can be canceled directly. The
+// implementations are *cancelCtx and *timerCtx.
+type canceler interface {
+ cancel(removeFromParent bool, err error)
+ Done() <-chan struct{}
+}
+
+// A cancelCtx can be canceled. When canceled, it also cancels any children
+// that implement canceler.
+type cancelCtx struct {
+ Context
+
+ done chan struct{} // closed by the first cancel call.
+
+ mu sync.Mutex
+ children map[canceler]bool // set to nil by the first cancel call
+ err error // set to non-nil by the first cancel call
+}
+
+func (c *cancelCtx) Done() <-chan struct{} {
+ return c.done
+}
+
+func (c *cancelCtx) Err() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ return c.err
+}
+
+func (c *cancelCtx) String() string {
+ return fmt.Sprintf("%v.WithCancel", c.Context)
+}
+
+// cancel closes c.done, cancels each of c's children, and, if
+// removeFromParent is true, removes c from its parent's children.
+func (c *cancelCtx) cancel(removeFromParent bool, err error) {
+ if err == nil {
+ panic("context: internal error: missing cancel error")
+ }
+ c.mu.Lock()
+ if c.err != nil {
+ c.mu.Unlock()
+ return // already canceled
+ }
+ c.err = err
+ close(c.done)
+ for child := range c.children {
+ // NOTE: acquiring the child's lock while holding parent's lock.
+ child.cancel(false, err)
+ }
+ c.children = nil
+ c.mu.Unlock()
+
+ if removeFromParent {
+ removeChild(c.Context, c)
+ }
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
+ if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
+ // The current deadline is already sooner than the new one.
+ return WithCancel(parent)
+ }
+ c := &timerCtx{
+ cancelCtx: newCancelCtx(parent),
+ deadline: deadline,
+ }
+ propagateCancel(parent, c)
+ d := deadline.Sub(time.Now())
+ if d <= 0 {
+ c.cancel(true, DeadlineExceeded) // deadline has already passed
+ return c, func() { c.cancel(true, Canceled) }
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.err == nil {
+ c.timer = time.AfterFunc(d, func() {
+ c.cancel(true, DeadlineExceeded)
+ })
+ }
+ return c, func() { c.cancel(true, Canceled) }
+}
+
+// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
+// implement Done and Err. It implements cancel by stopping its timer then
+// delegating to cancelCtx.cancel.
+type timerCtx struct {
+ *cancelCtx
+ timer *time.Timer // Under cancelCtx.mu.
+
+ deadline time.Time
+}
+
+func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
+ return c.deadline, true
+}
+
+func (c *timerCtx) String() string {
+ return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
+}
+
+func (c *timerCtx) cancel(removeFromParent bool, err error) {
+ c.cancelCtx.cancel(false, err)
+ if removeFromParent {
+ // Remove this timerCtx from its parent cancelCtx's children.
+ removeChild(c.cancelCtx.Context, c)
+ }
+ c.mu.Lock()
+ if c.timer != nil {
+ c.timer.Stop()
+ c.timer = nil
+ }
+ c.mu.Unlock()
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// defer cancel() // releases resources if slowOperation completes before timeout elapses
+// return slowOperation(ctx)
+// }
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+ return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+func WithValue(parent Context, key interface{}, val interface{}) Context {
+ return &valueCtx{parent, key, val}
+}
+
+// A valueCtx carries a key-value pair. It implements Value for that key and
+// delegates all other calls to the embedded Context.
+type valueCtx struct {
+ Context
+ key, val interface{}
+}
+
+func (c *valueCtx) String() string {
+ return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
+}
+
+func (c *valueCtx) Value(key interface{}) interface{} {
+ if c.key == key {
+ return c.val
+ }
+ return c.Context.Value(key)
+}
diff --git a/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go b/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go
new file mode 100644
index 0000000..a6754dc
--- /dev/null
+++ b/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go
@@ -0,0 +1,26 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+ "fmt"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+func ExampleWithTimeout() {
+ // Pass a context with a timeout to tell a blocking function that it
+ // should abandon its work after the timeout elapses.
+ ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)
+ select {
+ case <-time.After(200 * time.Millisecond):
+ fmt.Println("overslept")
+ case <-ctx.Done():
+ fmt.Println(ctx.Err()) // prints "context deadline exceeded"
+ }
+ // Output:
+ // context deadline exceeded
+}