123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- package ss
- import (
- "io"
- "strings"
- "encoding/json"
- "net/http"
- "net/url"
- "fmt"
- "surdeus.su/core/ss/contents"
- "surdeus.su/core/ss/urlenc"
- )
- type Context struct {
- R *Request
- RelUrl *url.URL
- W ResponseWriter
- // Custom data to store stuff.
- Data any
- scanErr error
- dec Decoder
- }
- func (c *Context) Method() ReqMethod {
- return ReqMethod(c.R.Method)
- }
- // Set the reply status code.
- func (c *Context) SetStatus(status Status) {
- c.W.WriteHeader(int(status))
- }
- // Set the reply content type.
- func (c *Context) SetContentType(typ contents.Type, opts ...contents.Option) {
- ret := string(typ)
- for _, opt := range opts {
- kv := opt.KeyValue()
- ret += ";"+kv[0]+"="+kv[1]
- }
- c.SetHeader("Content-Type", ret)
- }
- // Get the request content type.
- func (c *Context) ContentType() contents.Type {
- ret, ok := c.Header("Content-Type")
- if !ok {
- return ""
- }
- if len(ret) < 1 {
- return ""
- }
- splits := strings.SplitN(ret[0], ";", 2)
- if len(splits) < 0 {
- return ""
- }
- return contents.Type(splits[0])
- }
- func (c *Context) SetHeader(k, v string) {
- c.W.Header().Set(k, v)
- }
- func (c *Context) Header(name string) ([]string, bool) {
- ret, ok := c.R.Header[name]
- return ret, ok
- }
- // Closes the requests body after finishes scaning.
- func (c *Context) Close() {
- c.R.Body.Close()
- }
- // Scan the incoming value from body depending
- // on the content type of the request into the
- // structure or map[string] any.
- func (c *Context) Scan(v any) bool {
- if c.dec == nil {
- typ := c.ContentType()
- switch typ {
- case contents.Json:
- c.dec = json.NewDecoder(c.R.Body)
- case contents.UrlEncoded:
- body, _ := io.ReadAll(c.R.Body)
- err := urlenc.Unmarshal(body, v)
- if err != nil {
- c.scanErr = err
- }
- return false
- default:
- c.scanErr = UnknownContentTypeErr
- return false
- }
- }
- err := c.dec.Decode(v)
- if err != nil {
- if err != io.EOF {
- c.scanErr = err
- }
- return false
- }
- return true
- }
- func (c *Context) ScanErr() error {
- return c.scanErr
- }
- func (c *Context) AbsPath() string {
- return c.R.URL.Path
- }
- func (c *Context) PathPrefix() string {
- pth := c.AbsPath()
- rpth := c.Path()
- return pth[:len(pth)-len(rpth)]
- }
- func (c *Context) Path() string {
- return c.RelUrl.Path
- }
- func (c *Context) NotFound() {
- http.NotFound(c.W, c.R)
- }
- func (c *Context) InternalServerError(err error) {
- c.W.WriteHeader(http.StatusInternalServerError)
- if err != nil {
- c.Printf("500 Internal Server Error: %q", err)
- } else {
- }
- }
- func (c *Context) Print(v ...any) (int, error) {
- return fmt.Print(v...)
- }
- func (c *Context) Printf(format string, v ...any) (int, error) {
- return fmt.Fprintf(c.W, format, v...)
- }
- func (c *Context) Query() url.Values {
- return c.R.URL.Query()
- }
- func (c *Context) Redirect(u string, status Status) {
- pth := c.AbsPath()
- if len(pth) > 0 && pth[len(pth)-1] != '/' {
- pth += "/"
- }
- c.R.URL.Path = pth
- http.Redirect(c.W, c.R, u, int(status))
- }
|