perkeep/blobserver/go/upload.go

126 lines
2.4 KiB
Go

package main
import (
"http"
"fmt"
"io"
"io/ioutil"
"os"
)
// For `make`:
//import "./util/_obj/util"
// For `gofr`:
import "util/util"
func handleMultiPartUpload(conn *http.Conn, req *http.Request) {
if !(req.Method == "POST" && req.URL.Path == "/camli/upload") {
badRequestError(conn, "Inconfigured handler.")
return
}
multipart, err := req.MultipartReader()
if multipart == nil {
badRequestError(conn, fmt.Sprintf(
"Expected multipart/form-data POST request; %v", err))
return
}
for {
part, err := multipart.NextPart()
if err != nil {
fmt.Println("Error reading multipart section:", err)
break
}
if part == nil {
break
}
formName := part.FormName()
fmt.Printf("New value [%s], part=%v\n", formName, part)
ref := ParseBlobRef(formName)
if ref == nil {
fmt.Printf("Ignoring form key [%s]\n", formName)
continue
}
ok, err := receiveBlob(ref, part)
if !ok {
fmt.Printf("Error receiving blob %v: %v\n", ref, err)
} else {
fmt.Printf("Received blob %v\n", ref)
}
}
fmt.Println("Done reading multipart body.")
}
func receiveBlob(blobRef *BlobRef, source io.Reader) (ok bool, err os.Error) {
hashedDirectory := blobRef.DirectoryName()
err = os.MkdirAll(hashedDirectory, 0700)
if err != nil {
return
}
var tempFile *os.File
tempFile, err = ioutil.TempFile(hashedDirectory, blobRef.FileBaseName()+".tmp")
if err != nil {
return
}
success := false // set true later
defer func() {
if !success {
fmt.Println("Removing temp file: ", tempFile.Name())
os.Remove(tempFile.Name())
}
}()
hash := blobRef.Hash()
var written int64
written, err = io.Copy(util.NewTee(hash, tempFile), source)
if err != nil {
return
}
if err = tempFile.Close(); err != nil {
return
}
fileName := blobRef.FileName()
if err = os.Rename(tempFile.Name(), fileName); err != nil {
return
}
stat, err := os.Lstat(fileName)
if err != nil {
return
}
if !stat.IsRegular() || stat.Size != written {
return false, os.NewError("Written size didn't match.")
}
success = true
return true, nil
}
func handlePut(conn *http.Conn, req *http.Request) {
blobRef := ParsePath(req.URL.Path)
if blobRef == nil {
badRequestError(conn, "Malformed PUT URL.")
return
}
if !blobRef.IsSupported() {
badRequestError(conn, "unsupported object hash function")
return
}
_, err := receiveBlob(blobRef, req.Body)
if err != nil {
serverError(conn, err)
return
}
fmt.Fprint(conn, "OK")
}