mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2025-09-23 01:23:36 +08:00
add s3 upload, and removing mono and multi part upload analyzer
removing mono and multi part upload analyzer, which were used just to determine the file name
This commit is contained in:
@@ -31,8 +31,9 @@ const (
|
||||
ErrBucketNotEmpty
|
||||
ErrBucketAlreadyExists
|
||||
ErrBucketAlreadyOwnedByYou
|
||||
ErrInvalidBucketName
|
||||
ErrNoSuchBucket
|
||||
ErrInvalidBucketName
|
||||
ErrInvalidDigest
|
||||
ErrInternalError
|
||||
)
|
||||
|
||||
@@ -64,6 +65,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
|
||||
Description: "The specified bucket is not valid.",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
ErrInvalidDigest: {
|
||||
Code: "InvalidDigest",
|
||||
Description: "The Content-Md5 you specified is not valid.",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
ErrNoSuchBucket: {
|
||||
Code: "NoSuchBucket",
|
||||
Description: "The specified bucket does not exist",
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/chrislusf/seaweedfs/weed/util"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
type mimeType string
|
||||
@@ -93,3 +94,14 @@ func writeSuccessResponseXML(w http.ResponseWriter, response []byte) {
|
||||
func writeSuccessResponseEmpty(w http.ResponseWriter) {
|
||||
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||
}
|
||||
|
||||
func validateContentMd5(h http.Header) ([]byte, error) {
|
||||
md5B64, ok := h["Content-Md5"]
|
||||
if ok {
|
||||
if md5B64[0] == "" {
|
||||
return nil, fmt.Errorf("Content-Md5 header set to empty value")
|
||||
}
|
||||
return base64.StdEncoding.DecodeString(md5B64[0])
|
||||
}
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
90
weed/s3api/s3api_object_handlers.go
Normal file
90
weed/s3api/s3api_object_handlers.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var (
|
||||
client *http.Client
|
||||
)
|
||||
|
||||
func init() {
|
||||
client = &http.Client{Transport: &http.Transport{
|
||||
MaxIdleConnsPerHost: 1024,
|
||||
}}
|
||||
}
|
||||
|
||||
type UploadResult struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Size uint32 `json:"size,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/UploadingObjects.html
|
||||
|
||||
vars := mux.Vars(r)
|
||||
bucket := vars["bucket"]
|
||||
object := vars["object"]
|
||||
|
||||
_, err := validateContentMd5(r.Header)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInvalidDigest, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
uploadUrl := fmt.Sprintf("http://%s%s/%s/%s?collection=%s",
|
||||
s3a.option.Filer, s3a.option.BucketsPath, bucket, object, bucket)
|
||||
proxyReq, err := http.NewRequest("PUT", uploadUrl, r.Body)
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("NewRequest %s: %v", uploadUrl, err)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
proxyReq.Header.Set("Host", s3a.option.Filer)
|
||||
proxyReq.Header.Set("X-Forwarded-For", r.RemoteAddr)
|
||||
|
||||
for header, values := range r.Header {
|
||||
for _, value := range values {
|
||||
proxyReq.Header.Add(header, value)
|
||||
}
|
||||
}
|
||||
|
||||
resp, postErr := client.Do(proxyReq)
|
||||
|
||||
if postErr != nil {
|
||||
glog.Errorf("post to filer: %v", postErr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
resp_body, ra_err := ioutil.ReadAll(resp.Body)
|
||||
if ra_err != nil {
|
||||
glog.Errorf("upload to filer response read: %v", ra_err)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
var ret UploadResult
|
||||
unmarshal_err := json.Unmarshal(resp_body, &ret)
|
||||
if unmarshal_err != nil {
|
||||
glog.Errorf("failing to read upload to %s : %v", uploadUrl, string(resp_body))
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
if ret.Error != "" {
|
||||
glog.Errorf("upload to filer error: %v", ret.Error)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
writeSuccessResponseEmpty(w)
|
||||
}
|
@@ -42,6 +42,10 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
|
||||
routers = append(routers, apiRouter.PathPrefix("/{bucket}").Subrouter())
|
||||
|
||||
for _, bucket := range routers {
|
||||
|
||||
// PutObject
|
||||
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(s3a.PutObjectHandler)
|
||||
|
||||
// PutBucket
|
||||
bucket.Methods("PUT").HandlerFunc(s3a.PutBucketHandler)
|
||||
// DeleteBucket
|
||||
|
Reference in New Issue
Block a user