github.com/tyler-smith/grab@v2.0.1-0.20190224022517-abcee96e61b1+incompatible/util.go (about)

     1  package grab
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"hash"
     7  	"mime"
     8  	"net/http"
     9  	"os"
    10  	"path"
    11  	"path/filepath"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  // setLastModified sets the last modified timestamp of a local file according to
    17  // the Last-Modified header returned by a remote server.
    18  func setLastModified(resp *http.Response, filename string) error {
    19  	// https://tools.ietf.org/html/rfc7232#section-2.2
    20  	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified
    21  	header := resp.Header.Get("Last-Modified")
    22  	if header == "" {
    23  		return nil
    24  	}
    25  	lastmod, err := time.Parse(http.TimeFormat, header)
    26  	if err != nil {
    27  		return nil
    28  	}
    29  	return os.Chtimes(filename, lastmod, lastmod)
    30  }
    31  
    32  // mkdirp creates all missing parent directories for the destination file path.
    33  func mkdirp(path string) error {
    34  	dir := filepath.Dir(path)
    35  	if fi, err := os.Stat(dir); err != nil {
    36  		if !os.IsNotExist(err) {
    37  			return fmt.Errorf("error checking destination directory: %v", err)
    38  		}
    39  		if err := os.MkdirAll(dir, 0755); err != nil {
    40  			return fmt.Errorf("error creating destination directory: %v", err)
    41  		}
    42  	} else if !fi.IsDir() {
    43  		panic("destination path is not directory")
    44  	}
    45  	return nil
    46  }
    47  
    48  // guessFilename returns a filename for the given http.Response. If none can be
    49  // determined ErrNoFilename is returned.
    50  func guessFilename(resp *http.Response) (string, error) {
    51  	filename := resp.Request.URL.Path
    52  	if cd := resp.Header.Get("Content-Disposition"); cd != "" {
    53  		if _, params, err := mime.ParseMediaType(cd); err == nil {
    54  			filename = params["filename"]
    55  		}
    56  	}
    57  
    58  	// sanitize
    59  	if filename == "" || strings.HasSuffix(filename, "/") || strings.Contains(filename, "\x00") {
    60  		return "", ErrNoFilename
    61  	}
    62  
    63  	filename = filepath.Base(path.Clean("/" + filename))
    64  	if filename == "" || filename == "." || filename == "/" {
    65  		return "", ErrNoFilename
    66  	}
    67  
    68  	return filename, nil
    69  }
    70  
    71  // checksum returns a hash of the given file, using the given hash algorithm.
    72  func checksum(ctx context.Context, filename string, h hash.Hash) (b []byte, err error) {
    73  	var f *os.File
    74  	f, err = os.Open(filename)
    75  	if err != nil {
    76  		return
    77  	}
    78  	defer func() {
    79  		err = f.Close()
    80  	}()
    81  
    82  	t := newTransfer(ctx, nil, h, f, nil)
    83  	if _, err = t.copy(); err != nil {
    84  		return
    85  	}
    86  
    87  	b = h.Sum(nil)
    88  	return
    89  }