chi-s3-vhs/s3.go
Alex Vanin bedb008081 Initial commit
Signed-off-by: Alex Vanin <a.vanin@yadro.com>
2024-07-10 14:15:59 +03:00

142 lines
3.1 KiB
Go

package main
import (
"context"
"fmt"
"log"
"net/http"
"net/url"
"github.com/go-chi/chi/v5"
)
type (
Func func(h http.Handler) http.Handler
ReqInfo struct {
BucketName string
ObjectName string
}
)
const ctxRequestInfo = "FrostFS-S3-GW"
func GetReqInfo(ctx context.Context) *ReqInfo {
if ctx == nil {
return &ReqInfo{}
} else if r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo); ok {
return r
}
return &ReqInfo{}
}
func SetReqInfo(ctx context.Context, req *ReqInfo) context.Context {
if ctx == nil {
return nil
}
return context.WithValue(ctx, ctxRequestInfo, req)
}
func AddBucketName() Func {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
reqInfo := GetReqInfo(ctx)
reqInfo.BucketName = chi.URLParam(r, "bucket")
h.ServeHTTP(w, r)
})
}
}
// AddObjectName adds objects name to ReqInfo from context.
func AddObjectName() Func {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
reqInfo := GetReqInfo(ctx)
rctx := chi.RouteContext(ctx)
// trim leading slash (always present)
reqInfo.ObjectName = rctx.RoutePath[1:]
if r.URL.RawPath != "" {
// we have to do this because of
// https://github.com/go-chi/chi/issues/641
// https://github.com/go-chi/chi/issues/642
if obj, err := url.PathUnescape(reqInfo.ObjectName); err != nil {
// log error
} else {
reqInfo.ObjectName = obj
}
}
h.ServeHTTP(w, r)
})
}
}
func Request() Func {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reqInfo := &ReqInfo{}
r = r.WithContext(SetReqInfo(r.Context(), reqInfo))
h.ServeHTTP(w, r)
})
}
}
func BucketRouter(objRouter chi.Router) chi.Router {
bktRouter := chi.NewRouter()
bktRouter.Use(AddBucketName())
bktRouter.Mount("/", objRouter)
bktRouter.Group(func(r chi.Router) {
r.MethodFunc(http.MethodGet, "/", BucketHandler())
})
return bktRouter
}
func ObjectRouter() chi.Router {
objRouter := chi.NewRouter()
objRouter.Use(AddObjectName())
objRouter.Group(func(r chi.Router) {
r.MethodFunc(http.MethodGet, "/*", ObjectHandler())
})
return objRouter
}
func ObjectHandler() http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
log.Println("object handler is triggered")
ri := GetReqInfo(r.Context())
if ri == nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(fmt.Sprintf("bucket:[%s] object:[%s]\n", ri.BucketName, ri.ObjectName)))
}
}
func BucketHandler() http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
log.Printf("bucket handler is triggered")
ri := GetReqInfo(r.Context())
if ri == nil {
log.Println("can't find request info")
rw.WriteHeader(http.StatusInternalServerError)
return
}
log.Printf("bucket:[%s]", ri.BucketName)
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(fmt.Sprintf("bucket:[%s]\n", ri.BucketName)))
}
}