func (dh *DownloadHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, file blob.Ref) { if req.Method != "GET" && req.Method != "HEAD" { http.Error(rw, "Invalid download method", 400) return } if req.Header.Get("If-Modified-Since") != "" { // Immutable, so any copy's a good copy. rw.WriteHeader(http.StatusNotModified) return } fr, err := schema.NewFileReader(dh.blobSource(), file) if err != nil { http.Error(rw, "Can't serve file: "+err.Error(), 500) return } defer fr.Close() schema := fr.FileSchema() h := rw.Header() h.Set("Content-Length", fmt.Sprintf("%d", schema.SumPartsSize())) h.Set("Expires", time.Now().Add(oneYear).Format(http.TimeFormat)) mimeType := magic.MIMETypeFromReaderAt(fr) if dh.ForceMime != "" { mimeType = dh.ForceMime } if mimeType == "" { mimeType = "application/octet-stream" } h.Set("Content-Type", mimeType) if mimeType == "application/octet-stream" { // Chrome seems to silently do nothing on // application/octet-stream unless this is set. // Maybe it's confused by lack of URL it recognizes // along with lack of mime type? rw.Header().Set("Content-Disposition", "attachment; filename=file-"+file.String()+".dat") } if req.Method == "HEAD" && req.FormValue("verifycontents") != "" { vbr, ok := blob.Parse(req.FormValue("verifycontents")) if !ok { return } hash := vbr.Hash() if hash == nil { return } io.Copy(hash, fr) // ignore errors, caught later if vbr.HashMatches(hash) { rw.Header().Set("X-Camli-Contents", vbr.String()) } return } http.ServeContent(rw, req, "", time.Now(), fr) }
func (dh *DownloadHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, file *blobref.BlobRef) { if req.Method != "GET" && req.Method != "HEAD" { http.Error(rw, "Invalid download method", 400) return } fr, err := schema.NewFileReader(dh.storageSeekFetcher(), file) if err != nil { http.Error(rw, "Can't serve file: "+err.Error(), 500) return } defer fr.Close() schema := fr.FileSchema() rw.Header().Set("Content-Length", fmt.Sprintf("%d", schema.SumPartsSize())) mimeType, reader := magic.MimeTypeFromReader(fr) if dh.ForceMime != "" { mimeType = dh.ForceMime } if mimeType == "" { mimeType = "application/octet-stream" } rw.Header().Set("Content-Type", mimeType) if mimeType == "application/octet-stream" { // Chrome seems to silently do nothing on // application/octet-stream unless this is set. // Maybe it's confused by lack of URL it recognizes // along with lack of mime type? rw.Header().Set("Content-Disposition", "attachment; filename=file-"+file.String()+".dat") } if req.Method == "HEAD" { vbr := blobref.Parse(req.FormValue("verifycontents")) if vbr == nil { return } hash := vbr.Hash() if hash == nil { return } io.Copy(hash, reader) // ignore errors, caught later if vbr.HashMatches(hash) { rw.Header().Set("X-Camli-Contents", vbr.String()) } return } n, err := io.Copy(rw, reader) log.Printf("For %q request of %s: copied %d, %v", req.Method, req.URL.Path, n, err) if err != nil { log.Printf("error serving download of file schema %s: %v", file, err) return } if size := schema.SumPartsSize(); n != int64(size) { log.Printf("error serving download of file schema %s: sent %d, expected size of %d", file, n, size) return } }