github.com/segakazzz/buffalo@v0.16.22-0.20210119082501-1f52048d3feb/render/download.go (about)

     1  package render
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"mime"
     8  	"net/http"
     9  	"path/filepath"
    10  	"strconv"
    11  )
    12  
    13  type downloadRenderer struct {
    14  	ctx    context.Context
    15  	name   string
    16  	reader io.Reader
    17  }
    18  
    19  func (r downloadRenderer) ContentType() string {
    20  	ext := filepath.Ext(r.name)
    21  	t := mime.TypeByExtension(ext)
    22  	if t == "" {
    23  		t = "application/octet-stream"
    24  	}
    25  
    26  	return t
    27  }
    28  
    29  func (r downloadRenderer) Render(w io.Writer, d Data) error {
    30  	written, err := io.Copy(w, r.reader)
    31  	if err != nil {
    32  		return err
    33  	}
    34  
    35  	ctx, ok := r.ctx.(responsible)
    36  	if !ok {
    37  		return fmt.Errorf("context has no response writer")
    38  	}
    39  
    40  	header := ctx.Response().Header()
    41  	disposition := fmt.Sprintf("attachment; filename=%s", r.name)
    42  	header.Add("Content-Disposition", disposition)
    43  	contentLength := strconv.Itoa(int(written))
    44  	header.Add("Content-Length", contentLength)
    45  
    46  	return nil
    47  }
    48  
    49  // Download renders a file attachment automatically setting following headers:
    50  //
    51  //   Content-Type
    52  //   Content-Length
    53  //   Content-Disposition
    54  //
    55  // Content-Type is set using mime#TypeByExtension with the filename's extension. Content-Type will default to
    56  // application/octet-stream if using a filename with an unknown extension.
    57  func Download(ctx context.Context, name string, r io.Reader) Renderer {
    58  	return downloadRenderer{
    59  		ctx:    ctx,
    60  		name:   name,
    61  		reader: r,
    62  	}
    63  }
    64  
    65  // Download renders a file attachment automatically setting following headers:
    66  //
    67  //   Content-Type
    68  //   Content-Length
    69  //   Content-Disposition
    70  //
    71  // Content-Type is set using mime#TypeByExtension with the filename's extension. Content-Type will default to
    72  // application/octet-stream if using a filename with an unknown extension.
    73  func (e *Engine) Download(ctx context.Context, name string, r io.Reader) Renderer {
    74  	return Download(ctx, name, r)
    75  }
    76  
    77  type responsible interface {
    78  	Response() http.ResponseWriter
    79  }