You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

131 lines
3.3 KiB

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