64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
// Package storagefixture supplies a bounded protocol fixture, not a cloud service.
|
|
package storagefixture
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type value struct {
|
|
data []byte
|
|
contentType string
|
|
etag string
|
|
}
|
|
|
|
func Handler() http.Handler {
|
|
var mu sync.Mutex
|
|
values := map[string]value{}
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if r.Header.Get("Authorization") == "" && r.URL.Query().Get("X-Amz-Signature") == "" && r.URL.Query().Get("x-oss-signature") == "" {
|
|
http.Error(w, "signature required", 403)
|
|
return
|
|
}
|
|
key := r.URL.Path
|
|
switch r.Method {
|
|
case "PUT":
|
|
data, err := io.ReadAll(io.LimitReader(r.Body, 1025))
|
|
if err != nil || len(data) > 1024 {
|
|
http.Error(w, "too large", 413)
|
|
return
|
|
}
|
|
v := value{data: data, contentType: r.Header.Get("Content-Type"), etag: fmt.Sprintf("%x", md5.Sum(data))}
|
|
values[key] = v
|
|
w.Header().Set("ETag", `"`+v.etag+`"`)
|
|
w.WriteHeader(200)
|
|
case "DELETE":
|
|
delete(values, key)
|
|
w.WriteHeader(204)
|
|
case "GET", "HEAD":
|
|
v, ok := values[key]
|
|
if !ok {
|
|
w.Header().Set("Content-Type", "application/xml")
|
|
w.WriteHeader(404)
|
|
fmt.Fprint(w, `<Error><Code>NoSuchKey</Code><Message>not found</Message></Error>`)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Length", fmt.Sprint(len(v.data)))
|
|
w.Header().Set("Content-Type", v.contentType)
|
|
w.Header().Set("ETag", `"`+v.etag+`"`)
|
|
w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
|
|
if r.Method == "GET" {
|
|
w.Write(v.data)
|
|
}
|
|
default:
|
|
http.Error(w, "unsupported", 405)
|
|
}
|
|
})
|
|
}
|