mirror of https://github.com/perkeep/perkeep.git
split off download handler code from the UIHandler.
Change-Id: Ifb0e80419f8712087ad9cad8214af330c7af8420
This commit is contained in:
parent
9de129e71c
commit
c201c98959
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright 2011 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"http"
|
||||
"log"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"camli/blobref"
|
||||
"camli/blobserver"
|
||||
"camli/schema"
|
||||
)
|
||||
|
||||
type DownloadHandler struct {
|
||||
Fetcher blobref.StreamingFetcher
|
||||
Cache blobserver.Storage
|
||||
}
|
||||
|
||||
func (dh *DownloadHandler) storageSeekFetcher() (blobref.SeekFetcher, os.Error) {
|
||||
return blobref.SeekerFromStreamingFetcher(dh.Fetcher) // TODO: pass dh.Cache?
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
fetchSeeker, err := dh.storageSeekFetcher()
|
||||
if err != nil {
|
||||
http.Error(rw, err.String(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
fr, err := schema.NewFileReader(fetchSeeker, file)
|
||||
if err != nil {
|
||||
http.Error(rw, "Can't serve file: "+err.String(), 500)
|
||||
return
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// TODO: fr.FileSchema() and guess a mime type? For now:
|
||||
schema := fr.FileSchema()
|
||||
rw.Header().Set("Content-Type", "application/octet-stream")
|
||||
rw.Header().Set("Content-Length", fmt.Sprintf("%d", schema.Size))
|
||||
|
||||
if req.Method == "HEAD" {
|
||||
vbr := blobref.Parse(req.FormValue("verifycontents"))
|
||||
if vbr == nil {
|
||||
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
|
||||
}
|
||||
|
||||
n, err := io.Copy(rw, fr)
|
||||
log.Printf("For %q request of %s: copied %d, %v", req.Method, req.URL.RawPath, n, err)
|
||||
if err != nil {
|
||||
log.Printf("error serving download of file schema %s: %v", file, err)
|
||||
return
|
||||
}
|
||||
if n != int64(schema.Size) {
|
||||
log.Printf("error serving download of file schema %s: sent %d, expected size of %d",
|
||||
file, n, schema.Size)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
|
@ -253,23 +253,12 @@ func (ui *UIHandler) storageSeekFetcher() (blobref.SeekFetcher, os.Error) {
|
|||
}
|
||||
|
||||
func (ui *UIHandler) serveDownload(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "GET" && req.Method != "HEAD" {
|
||||
http.Error(rw, "Invalid download method", 400)
|
||||
return
|
||||
}
|
||||
if ui.Storage == nil {
|
||||
http.Error(rw, "No BlobRoot configured", 500)
|
||||
return
|
||||
}
|
||||
|
||||
fetchSeeker, err := ui.storageSeekFetcher()
|
||||
if err != nil {
|
||||
http.Error(rw, err.String(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
suffix := req.Header.Get("X-PrefixHandler-PathSuffix")
|
||||
|
||||
m := downloadPattern.FindStringSubmatch(suffix)
|
||||
if m == nil {
|
||||
httputil.ErrorRouting(rw, req)
|
||||
|
@ -282,50 +271,11 @@ func (ui *UIHandler) serveDownload(rw http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
filename := m[2]
|
||||
if len(filename) > 0 {
|
||||
filename = filename[1:] // remove leading slash
|
||||
}
|
||||
|
||||
fr, err := schema.NewFileReader(fetchSeeker, fbr)
|
||||
if err != nil {
|
||||
http.Error(rw, "Can't serve file: "+err.String(), 500)
|
||||
return
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// TODO: fr.FileSchema() and guess a mime type? For now:
|
||||
schema := fr.FileSchema()
|
||||
rw.Header().Set("Content-Type", "application/octet-stream")
|
||||
rw.Header().Set("Content-Length", fmt.Sprintf("%d", schema.Size))
|
||||
|
||||
if req.Method == "HEAD" {
|
||||
vbr := blobref.Parse(req.FormValue("verifycontents"))
|
||||
if vbr == nil {
|
||||
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
|
||||
}
|
||||
|
||||
n, err := io.Copy(rw, fr)
|
||||
log.Printf("For %q request of %s: copied %d, %v", req.Method, req.URL.RawPath, n, err)
|
||||
if err != nil {
|
||||
log.Printf("error serving download of file schema %s: %v", fbr, err)
|
||||
return
|
||||
}
|
||||
if n != int64(schema.Size) {
|
||||
log.Printf("error serving download of file schema %s: sent %d, expected size of %d",
|
||||
fbr, n, schema.Size)
|
||||
return
|
||||
dh := &DownloadHandler{
|
||||
Fetcher: ui.Storage,
|
||||
Cache: ui.Cache,
|
||||
}
|
||||
dh.ServeHTTP(rw, req, fbr)
|
||||
}
|
||||
|
||||
func (ui *UIHandler) serveThumbnail(rw http.ResponseWriter, req *http.Request) {
|
||||
|
@ -365,11 +315,6 @@ func (ui *UIHandler) serveThumbnail(rw http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
filename := m[2]
|
||||
if len(filename) > 0 {
|
||||
filename = filename[1:] // remove leading slash
|
||||
}
|
||||
|
||||
fr, err := schema.NewFileReader(fetchSeeker, blobref)
|
||||
if err != nil {
|
||||
http.Error(rw, "Can't serve file: "+err.String(), 500)
|
||||
|
|
Loading…
Reference in New Issue