// Fast path for blobpacked. func fileInfoPacked(sh *search.Handler, src blob.Fetcher, req *http.Request, file blob.Ref) (packFileInfo fileInfo, ok bool) { if sh == nil { return fileInfo{whyNot: "no search"}, false } wf, ok := src.(blobserver.WholeRefFetcher) if !ok { return fileInfo{whyNot: "fetcher type"}, false } if req != nil && req.Header.Get("Range") != "" { // TODO: not handled yet. Maybe not even important, // considering rarity. return fileInfo{whyNot: "range header"}, false } des, err := sh.Describe(&search.DescribeRequest{BlobRef: file}) if err != nil { log.Printf("ui: fileInfoPacked: skipping fast path due to error from search: %v", err) return fileInfo{whyNot: "search error"}, false } db, ok := des.Meta[file.String()] if !ok || db.File == nil { return fileInfo{whyNot: "search index doesn't know file"}, false } fi := db.File if !fi.WholeRef.Valid() { return fileInfo{whyNot: "no wholeref from search index"}, false } offset := int64(0) rc, wholeSize, err := wf.OpenWholeRef(fi.WholeRef, offset) if err == os.ErrNotExist { return fileInfo{whyNot: "WholeRefFetcher returned ErrNotexist"}, false } if wholeSize != fi.Size { log.Printf("ui: fileInfoPacked: OpenWholeRef size %d != index size %d; ignoring fast path", wholeSize, fi.Size) return fileInfo{whyNot: "WholeRefFetcher and index don't agree"}, false } if err != nil { log.Printf("ui: fileInfoPacked: skipping fast path due to error from WholeRefFetcher (%T): %v", src, err) return fileInfo{whyNot: "WholeRefFetcher error"}, false } return fileInfo{ mime: fi.MIMEType, name: fi.FileName, size: fi.Size, rs: readerutil.NewFakeSeeker(rc, fi.Size-offset), close: rc.Close, }, true }
// ServeBlobRef serves a blob. func ServeBlobRef(rw http.ResponseWriter, req *http.Request, blobRef blob.Ref, fetcher blob.Fetcher) { rc, size, err := fetcher.Fetch(blobRef) switch err { case nil: break case os.ErrNotExist: rw.WriteHeader(http.StatusNotFound) fmt.Fprintf(rw, "Blob %q not found", blobRef) return default: httputil.ServeError(rw, req, err) return } defer rc.Close() rw.Header().Set("Content-Type", "application/octet-stream") var content io.ReadSeeker = readerutil.NewFakeSeeker(rc, int64(size)) rangeHeader := req.Header.Get("Range") != "" const small = 32 << 10 var b *blob.Blob if rangeHeader || size < small { // Slurp to memory, so we can actually seek on it (for Range support), // or if we're going to be showing it in the browser (below). b, err = blob.FromReader(blobRef, rc, size) if err != nil { httputil.ServeError(rw, req, err) return } content = b.Open() } if !rangeHeader && size < small { // If it's small and all UTF-8, assume it's text and // just render it in the browser. This is more for // demos/debuggability than anything else. It isn't // part of the spec. if b.IsUTF8() { rw.Header().Set("Content-Type", "text/plain; charset=utf-8") } } http.ServeContent(rw, req, "", dummyModTime, content) }