...
1
2
3
4
5 package autocert
6
7 import (
8 "context"
9 "errors"
10 "os"
11 "path/filepath"
12 )
13
14
15 var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
16
17
18
19
20
21
22 type Cache interface {
23
24
25 Get(ctx context.Context, key string) ([]byte, error)
26
27
28
29
30 Put(ctx context.Context, key string, data []byte) error
31
32
33
34 Delete(ctx context.Context, key string) error
35 }
36
37
38
39 type DirCache string
40
41
42 func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
43 name = filepath.Join(string(d), filepath.Clean("/"+name))
44 var (
45 data []byte
46 err error
47 done = make(chan struct{})
48 )
49 go func() {
50 data, err = os.ReadFile(name)
51 close(done)
52 }()
53 select {
54 case <-ctx.Done():
55 return nil, ctx.Err()
56 case <-done:
57 }
58 if os.IsNotExist(err) {
59 return nil, ErrCacheMiss
60 }
61 return data, err
62 }
63
64
65
66 func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
67 if err := os.MkdirAll(string(d), 0700); err != nil {
68 return err
69 }
70
71 done := make(chan struct{})
72 var err error
73 go func() {
74 defer close(done)
75 var tmp string
76 if tmp, err = d.writeTempFile(name, data); err != nil {
77 return
78 }
79 defer os.Remove(tmp)
80 select {
81 case <-ctx.Done():
82
83 default:
84 newName := filepath.Join(string(d), filepath.Clean("/"+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
97 func (d DirCache) Delete(ctx context.Context, name string) error {
98 name = filepath.Join(string(d), filepath.Clean("/"+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
119 func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) {
120
121 f, err := os.CreateTemp(string(d), prefix)
122 if err != nil {
123 return "", err
124 }
125 defer func() {
126 if reterr != nil {
127 os.Remove(f.Name())
128 }
129 }()
130 if _, err := f.Write(b); err != nil {
131 f.Close()
132 return "", err
133 }
134 return f.Name(), f.Close()
135 }
136
View as plain text