OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / crypto / acme / autocert / listener.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package autocert
6
7 import (
8         "crypto/tls"
9         "log"
10         "net"
11         "os"
12         "path/filepath"
13         "runtime"
14         "time"
15 )
16
17 // NewListener returns a net.Listener that listens on the standard TLS
18 // port (443) on all interfaces and returns *tls.Conn connections with
19 // LetsEncrypt certificates for the provided domain or domains.
20 //
21 // It enables one-line HTTPS servers:
22 //
23 //     log.Fatal(http.Serve(autocert.NewListener("example.com"), handler))
24 //
25 // NewListener is a convenience function for a common configuration.
26 // More complex or custom configurations can use the autocert.Manager
27 // type instead.
28 //
29 // Use of this function implies acceptance of the LetsEncrypt Terms of
30 // Service. If domains is not empty, the provided domains are passed
31 // to HostWhitelist. If domains is empty, the listener will do
32 // LetsEncrypt challenges for any requested domain, which is not
33 // recommended.
34 //
35 // Certificates are cached in a "golang-autocert" directory under an
36 // operating system-specific cache or temp directory. This may not
37 // be suitable for servers spanning multiple machines.
38 //
39 // The returned listener uses a *tls.Config that enables HTTP/2, and
40 // should only be used with servers that support HTTP/2.
41 //
42 // The returned Listener also enables TCP keep-alives on the accepted
43 // connections. The returned *tls.Conn are returned before their TLS
44 // handshake has completed.
45 func NewListener(domains ...string) net.Listener {
46         m := &Manager{
47                 Prompt: AcceptTOS,
48         }
49         if len(domains) > 0 {
50                 m.HostPolicy = HostWhitelist(domains...)
51         }
52         dir := cacheDir()
53         if err := os.MkdirAll(dir, 0700); err != nil {
54                 log.Printf("warning: autocert.NewListener not using a cache: %v", err)
55         } else {
56                 m.Cache = DirCache(dir)
57         }
58         return m.Listener()
59 }
60
61 // Listener listens on the standard TLS port (443) on all interfaces
62 // and returns a net.Listener returning *tls.Conn connections.
63 //
64 // The returned listener uses a *tls.Config that enables HTTP/2, and
65 // should only be used with servers that support HTTP/2.
66 //
67 // The returned Listener also enables TCP keep-alives on the accepted
68 // connections. The returned *tls.Conn are returned before their TLS
69 // handshake has completed.
70 //
71 // Unlike NewListener, it is the caller's responsibility to initialize
72 // the Manager m's Prompt, Cache, HostPolicy, and other desired options.
73 func (m *Manager) Listener() net.Listener {
74         ln := &listener{
75                 m: m,
76                 conf: &tls.Config{
77                         GetCertificate: m.GetCertificate,           // bonus: panic on nil m
78                         NextProtos:     []string{"h2", "http/1.1"}, // Enable HTTP/2
79                 },
80         }
81         ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
82         return ln
83 }
84
85 type listener struct {
86         m    *Manager
87         conf *tls.Config
88
89         tcpListener  net.Listener
90         tcpListenErr error
91 }
92
93 func (ln *listener) Accept() (net.Conn, error) {
94         if ln.tcpListenErr != nil {
95                 return nil, ln.tcpListenErr
96         }
97         conn, err := ln.tcpListener.Accept()
98         if err != nil {
99                 return nil, err
100         }
101         tcpConn := conn.(*net.TCPConn)
102
103         // Because Listener is a convenience function, help out with
104         // this too.  This is not possible for the caller to set once
105         // we return a *tcp.Conn wrapping an inaccessible net.Conn.
106         // If callers don't want this, they can do things the manual
107         // way and tweak as needed. But this is what net/http does
108         // itself, so copy that. If net/http changes, we can change
109         // here too.
110         tcpConn.SetKeepAlive(true)
111         tcpConn.SetKeepAlivePeriod(3 * time.Minute)
112
113         return tls.Server(tcpConn, ln.conf), nil
114 }
115
116 func (ln *listener) Addr() net.Addr {
117         if ln.tcpListener != nil {
118                 return ln.tcpListener.Addr()
119         }
120         // net.Listen failed. Return something non-nil in case callers
121         // call Addr before Accept:
122         return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
123 }
124
125 func (ln *listener) Close() error {
126         if ln.tcpListenErr != nil {
127                 return ln.tcpListenErr
128         }
129         return ln.tcpListener.Close()
130 }
131
132 func homeDir() string {
133         if runtime.GOOS == "windows" {
134                 return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
135         }
136         if h := os.Getenv("HOME"); h != "" {
137                 return h
138         }
139         return "/"
140 }
141
142 func cacheDir() string {
143         const base = "golang-autocert"
144         switch runtime.GOOS {
145         case "darwin":
146                 return filepath.Join(homeDir(), "Library", "Caches", base)
147         case "windows":
148                 for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
149                         if v := os.Getenv(ev); v != "" {
150                                 return filepath.Join(v, base)
151                         }
152                 }
153                 // Worst case:
154                 return filepath.Join(homeDir(), base)
155         }
156         if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
157                 return filepath.Join(xdg, base)
158         }
159         return filepath.Join(homeDir(), ".cache", base)
160 }