github.com/tooolbox/grab@v2.0.0+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 }