OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / acme / autocert / cache.go
1 // Copyright 2016 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         "context"
9         "errors"
10         "io/ioutil"
11         "os"
12         "path/filepath"
13 )
14
15 // ErrCacheMiss is returned when a certificate is not found in cache.
16 var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
17
18 // Cache is used by Manager to store and retrieve previously obtained certificates
19 // as opaque data.
20 //
21 // The key argument of the methods refers to a domain name but need not be an FQDN.
22 // Cache implementations should not rely on the key naming pattern.
23 type Cache interface {
24         // Get returns a certificate data for the specified key.
25         // If there's no such key, Get returns ErrCacheMiss.
26         Get(ctx context.Context, key string) ([]byte, error)
27
28         // Put stores the data in the cache under the specified key.
29         // Underlying implementations may use any data storage format,
30         // as long as the reverse operation, Get, results in the original data.
31         Put(ctx context.Context, key string, data []byte) error
32
33         // Delete removes a certificate data from the cache under the specified key.
34         // If there's no such key in the cache, Delete returns nil.
35         Delete(ctx context.Context, key string) error
36 }
37
38 // DirCache implements Cache using a directory on the local filesystem.
39 // If the directory does not exist, it will be created with 0700 permissions.
40 type DirCache string
41
42 // Get reads a certificate data from the specified file name.
43 func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
44         name = filepath.Join(string(d), name)
45         var (
46                 data []byte
47                 err  error
48                 done = make(chan struct{})
49         )
50         go func() {
51                 data, err = ioutil.ReadFile(name)
52                 close(done)
53         }()
54         select {
55         case <-ctx.Done():
56                 return nil, ctx.Err()
57         case <-done:
58         }
59         if os.IsNotExist(err) {
60                 return nil, ErrCacheMiss
61         }
62         return data, err
63 }
64
65 // Put writes the certificate data to the specified file name.
66 // The file will be created with 0600 permissions.
67 func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
68         if err := os.MkdirAll(string(d), 0700); err != nil {
69                 return err
70         }
71
72         done := make(chan struct{})
73         var err error
74         go func() {
75                 defer close(done)
76                 var tmp string
77                 if tmp, err = d.writeTempFile(name, data); err != nil {
78                         return
79                 }
80                 select {
81                 case <-ctx.Done():
82                         // Don't overwrite the file if the context was canceled.
83                 default:
84                         newName := filepath.Join(string(d), name)
85                         err = os.Rename(tmp, newName)
86                 }
87         }()
88         select {
89         case <-ctx.Done():
90                 return ctx.Err()
91         case <-done:
92         }
93         return err
94 }
95
96 // Delete removes the specified file name.
97 func (d DirCache) Delete(ctx context.Context, name string) error {
98         name = filepath.Join(string(d), name)
99         var (
100                 err  error
101                 done = make(chan struct{})
102         )
103         go func() {
104                 err = os.Remove(name)
105                 close(done)
106         }()
107         select {
108         case <-ctx.Done():
109                 return ctx.Err()
110         case <-done:
111         }
112         if err != nil && !os.IsNotExist(err) {
113                 return err
114         }
115         return nil
116 }
117
118 // writeTempFile writes b to a temporary file, closes the file and returns its path.
119 func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
120         // TempFile uses 0600 permissions
121         f, err := ioutil.TempFile(string(d), prefix)
122         if err != nil {
123                 return "", err
124         }
125         if _, err := f.Write(b); err != nil {
126                 f.Close()
127                 return "", err
128         }
129         return f.Name(), f.Close()
130 }