github.com/cavaliergopher/grab/v3@v3.0.1/util.go (about)

     1  package grab
     2  
     3  import (
     4  	"fmt"
     5  	"mime"
     6  	"net/http"
     7  	"os"
     8  	"path"
     9  	"path/filepath"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  // setLastModified sets the last modified timestamp of a local file according to
    15  // the Last-Modified header returned by a remote server.
    16  func setLastModified(resp *http.Response, filename string) error {
    17  	// https://tools.ietf.org/html/rfc7232#section-2.2
    18  	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified
    19  	header := resp.Header.Get("Last-Modified")
    20  	if header == "" {
    21  		return nil
    22  	}
    23  	lastmod, err := time.Parse(http.TimeFormat, header)
    24  	if err != nil {
    25  		return nil
    26  	}
    27  	return os.Chtimes(filename, lastmod, lastmod)
    28  }
    29  
    30  // mkdirp creates all missing parent directories for the destination file path.
    31  func mkdirp(path string) error {
    32  	dir := filepath.Dir(path)
    33  	if fi, err := os.Stat(dir); err != nil {
    34  		if !os.IsNotExist(err) {
    35  			return fmt.Errorf("error checking destination directory: %v", err)
    36  		}
    37  		if err := os.MkdirAll(dir, 0777); err != nil {
    38  			return fmt.Errorf("error creating destination directory: %v", err)
    39  		}
    40  	} else if !fi.IsDir() {
    41  		panic("grab: developer error: destination path is not directory")
    42  	}
    43  	return nil
    44  }
    45  
    46  // guessFilename returns a filename for the given http.Response. If none can be
    47  // determined ErrNoFilename is returned.
    48  //
    49  // TODO: NoStore operations should not require a filename
    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  			if val, ok := params["filename"]; ok {
    55  				filename = val
    56  			} // else filename directive is missing.. fallback to URL.Path
    57  		}
    58  	}
    59  
    60  	// sanitize
    61  	if filename == "" || strings.HasSuffix(filename, "/") || strings.Contains(filename, "\x00") {
    62  		return "", ErrNoFilename
    63  	}
    64  
    65  	filename = filepath.Base(path.Clean("/" + filename))
    66  	if filename == "" || filename == "." || filename == "/" {
    67  		return "", ErrNoFilename
    68  	}
    69  
    70  	return filename, nil
    71  }