143 lines
3.1 KiB
Go
143 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)))
|
||
|
}
|
||
|
}
|