github.com/puellanivis/breton@v0.2.16/lib/files/datafiles/data.go (about)

     1  // Package datafiles implements the "data:" URL scheme.
     2  package datafiles
     3  
     4  import (
     5  	"context"
     6  	"encoding/base64"
     7  	"net/http"
     8  	"net/url"
     9  	"os"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/puellanivis/breton/lib/files"
    14  	"github.com/puellanivis/breton/lib/files/wrapper"
    15  )
    16  
    17  type handler struct{}
    18  
    19  func init() {
    20  	files.RegisterScheme(&handler{}, "data")
    21  }
    22  
    23  var b64enc = base64.StdEncoding
    24  
    25  func (h *handler) Create(ctx context.Context, uri *url.URL) (files.Writer, error) {
    26  	return nil, files.PathError("create", uri.String(), os.ErrInvalid)
    27  }
    28  
    29  type withHeaders struct {
    30  	files.Reader
    31  	header http.Header
    32  }
    33  
    34  func (w *withHeaders) Header() http.Header {
    35  	return w.header
    36  }
    37  
    38  func (h *handler) Open(ctx context.Context, uri *url.URL) (files.Reader, error) {
    39  	if uri.Host != "" || uri.User != nil {
    40  		return nil, files.PathError("open", uri.String(), os.ErrInvalid)
    41  	}
    42  
    43  	path := uri.Path
    44  	if path == "" {
    45  		path = uri.Opaque
    46  		if p, err := url.PathUnescape(path); err == nil {
    47  			path = p
    48  		}
    49  	}
    50  
    51  	i := strings.IndexByte(path, ',')
    52  	if i < 0 {
    53  		return nil, files.PathError("open", uri.String(), os.ErrInvalid)
    54  	}
    55  
    56  	contentType, data := path[:i], []byte(path[i+1:])
    57  	var isBase64 bool
    58  
    59  	if strings.HasSuffix(contentType, ";base64") {
    60  		contentType = strings.TrimSuffix(contentType, ";base64")
    61  		isBase64 = true
    62  	}
    63  
    64  	if contentType == "" {
    65  		contentType = "text/plain;charset=US-ASCII"
    66  	}
    67  
    68  	header := make(http.Header)
    69  	header.Set("Content-Type", contentType)
    70  
    71  	if isBase64 {
    72  		b := make([]byte, b64enc.DecodedLen(len(data)))
    73  
    74  		n, err := b64enc.Decode(b, data)
    75  		if err != nil {
    76  			return nil, files.PathError("decode", uri.String(), err)
    77  		}
    78  
    79  		data = b[:n]
    80  	}
    81  
    82  	return &withHeaders{
    83  		Reader: wrapper.NewReaderFromBytes(data, uri, time.Now()),
    84  		header: header,
    85  	}, nil
    86  }
    87  
    88  func (h *handler) List(ctx context.Context, uri *url.URL) ([]os.FileInfo, error) {
    89  	return nil, files.PathError("readdir", uri.String(), os.ErrInvalid)
    90  }