package http import ( "bytes" "fmt" "git.diulo.com/mogfee/kit/encoding" "git.diulo.com/mogfee/kit/internal/httputil" "git.diulo.com/mogfee/kit/transport/http/binding" "github.com/gorilla/mux" "io" "net/http" "net/url" ) const SupportPackageIsVersion1 = true type Redirector interface { Redirect() (string, int) } type Request = http.Request type ResponseWriter = http.ResponseWriter type Flusher = http.Flusher type DecodeRequestFunc func(*http.Request, any) error type EncodeResponseFunc func(http.ResponseWriter, *http.Request, any) error type EncodeErrorFunc func(w http.ResponseWriter, r *http.Request, err error) func DefaultRequestVars(r *http.Request, v any) error { raws := mux.Vars(r) vars := make(url.Values, len(raws)) for k, v := range raws { vars[k] = []string{v} } return binding.BindQuery(vars, v) } func DefaultRequestQuery(r *http.Request, v any) error { return binding.BindQuery(r.URL.Query(), v) } func DefaultRequestDecoder(r *http.Request, v any) error { codec, ok := CodeForRequest(r, "Content-Type") if !ok { return errorx.BadRequest("CODEC", fmt.Sprintf("unregister Content-Type: %s", codec)) } data, err := io.ReadAll(r.Body) if err != nil { return errorx.BadRequest("CODEC", err.Error()) } r.Body = io.NopCloser(bytes.NewBuffer(data)) if len(data) == 0 { return nil } if err = codec.Unmarshal(data, v); err != nil { return errorx.BadRequest("CODEC", err.Error()) } return nil } func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v any) error { if v == nil { return nil } if rd, ok := v.(Redirector); ok { url, code := rd.Redirect() http.Redirect(w, r, url, code) return nil } codec, _ := CodeForRequest(r, "Accept") data, err := codec.Marshal(v) if err != nil { return err } w.Header().Set("Content-type", httputil.ContentType(codec.Name())) _, err = w.Write(data) return err } func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) { se := errorx.FromError(err) codec, _ := CodeForRequest(r, "Accept") body, err := codec.Marshal(se) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set("Content-Type", httputil.ContentType(codec.Name())) w.WriteHeader(int(se.Status.Code)) _, _ = w.Write(body) } func CodeForRequest(r *http.Request, name string) (encoding.Codec, bool) { for _, accept := range r.Header[name] { codec := encoding.GetCodec(httputil.ContentSubtype(accept)) if codec != nil { return codec, true } } return encoding.GetCodec("json"), false }