...

Source file src/golang.org/x/crypto/acme/autocert/cache.go

Documentation: golang.org/x/crypto/acme/autocert

     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  	"os"
    11  	"path/filepath"
    12  )
    13  
    14  // ErrCacheMiss is returned when a certificate is not found in cache.
    15  var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
    16  
    17  // Cache is used by Manager to store and retrieve previously obtained certificates
    18  // and other account data as opaque blobs.
    19  //
    20  // Cache implementations should not rely on the key naming pattern. Keys can
    21  // include any printable ASCII characters, except the following: \/:*?"<>|
    22  type Cache interface {
    23  	// Get returns a certificate data for the specified key.
    24  	// If there's no such key, Get returns ErrCacheMiss.
    25  	Get(ctx context.Context, key string) ([]byte, error)
    26  
    27  	// Put stores the data in the cache under the specified key.
    28  	// Underlying implementations may use any data storage format,
    29  	// as long as the reverse operation, Get, results in the original data.
    30  	Put(ctx context.Context, key string, data []byte) error
    31  
    32  	// Delete removes a certificate data from the cache under the specified key.
    33  	// If there's no such key in the cache, Delete returns nil.
    34  	Delete(ctx context.Context, key string) error
    35  }
    36  
    37  // DirCache implements Cache using a directory on the local filesystem.
    38  // If the directory does not exist, it will be created with 0700 permissions.
    39  type DirCache string
    40  
    41  // Get reads a certificate data from the specified file name.
    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  // Put writes the certificate data to the specified file name.
    65  // The file will be created with 0600 permissions.
    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  			// Don't overwrite the file if the context was canceled.
    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  // Delete removes the specified file name.
    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  // writeTempFile writes b to a temporary file, closes the file and returns its path.
   119  func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) {
   120  	// TempFile uses 0600 permissions
   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