context.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package ss
  2. import (
  3. "io"
  4. "strings"
  5. "encoding/json"
  6. "net/http"
  7. "net/url"
  8. "fmt"
  9. "surdeus.su/core/ss/contents"
  10. "surdeus.su/core/ss/urlenc"
  11. )
  12. type Context struct {
  13. R *Request
  14. RelUrl *url.URL
  15. W ResponseWriter
  16. // Custom data to store stuff.
  17. Data any
  18. scanErr error
  19. dec Decoder
  20. }
  21. func (c *Context) Method() ReqMethod {
  22. return ReqMethod(c.R.Method)
  23. }
  24. // Set the reply status code.
  25. func (c *Context) SetStatus(status Status) {
  26. c.W.WriteHeader(int(status))
  27. }
  28. // Set the reply content type.
  29. func (c *Context) SetContentType(typ contents.Type, opts ...contents.Option) {
  30. ret := string(typ)
  31. for _, opt := range opts {
  32. kv := opt.KeyValue()
  33. ret += ";"+kv[0]+"="+kv[1]
  34. }
  35. c.SetHeader("Content-Type", ret)
  36. }
  37. // Get the request content type.
  38. func (c *Context) ContentType() contents.Type {
  39. ret, ok := c.Header("Content-Type")
  40. if !ok {
  41. return ""
  42. }
  43. if len(ret) < 1 {
  44. return ""
  45. }
  46. splits := strings.SplitN(ret[0], ";", 2)
  47. if len(splits) < 0 {
  48. return ""
  49. }
  50. return contents.Type(splits[0])
  51. }
  52. func (c *Context) SetHeader(k, v string) {
  53. c.W.Header().Set(k, v)
  54. }
  55. func (c *Context) Header(name string) ([]string, bool) {
  56. ret, ok := c.R.Header[name]
  57. return ret, ok
  58. }
  59. // Closes the requests body after finishes scaning.
  60. func (c *Context) Close() {
  61. c.R.Body.Close()
  62. }
  63. // Scan the incoming value from body depending
  64. // on the content type of the request into the
  65. // structure or map[string] any.
  66. func (c *Context) Scan(v any) bool {
  67. if c.dec == nil {
  68. typ := c.ContentType()
  69. switch typ {
  70. case contents.Json:
  71. c.dec = json.NewDecoder(c.R.Body)
  72. case contents.UrlEncoded:
  73. body, _ := io.ReadAll(c.R.Body)
  74. err := urlenc.Unmarshal(body, v)
  75. if err != nil {
  76. c.scanErr = err
  77. }
  78. return false
  79. default:
  80. c.scanErr = UnknownContentTypeErr
  81. return false
  82. }
  83. }
  84. err := c.dec.Decode(v)
  85. if err != nil {
  86. if err != io.EOF {
  87. c.scanErr = err
  88. }
  89. return false
  90. }
  91. return true
  92. }
  93. func (c *Context) ScanErr() error {
  94. return c.scanErr
  95. }
  96. func (c *Context) AbsPath() string {
  97. return c.R.URL.Path
  98. }
  99. func (c *Context) PathPrefix() string {
  100. pth := c.AbsPath()
  101. rpth := c.Path()
  102. return pth[:len(pth)-len(rpth)]
  103. }
  104. func (c *Context) Path() string {
  105. return c.RelUrl.Path
  106. }
  107. func (c *Context) NotFound() {
  108. http.NotFound(c.W, c.R)
  109. }
  110. func (c *Context) InternalServerError(err error) {
  111. c.W.WriteHeader(http.StatusInternalServerError)
  112. if err != nil {
  113. c.Printf("500 Internal Server Error: %q", err)
  114. } else {
  115. }
  116. }
  117. func (c *Context) Print(v ...any) (int, error) {
  118. return fmt.Print(v...)
  119. }
  120. func (c *Context) Printf(format string, v ...any) (int, error) {
  121. return fmt.Fprintf(c.W, format, v...)
  122. }
  123. func (c *Context) Query() url.Values {
  124. return c.R.URL.Query()
  125. }
  126. func (c *Context) Redirect(u string, status Status) {
  127. pth := c.AbsPath()
  128. if len(pth) > 0 && pth[len(pth)-1] != '/' {
  129. pth += "/"
  130. }
  131. c.R.URL.Path = pth
  132. http.Redirect(c.W, c.R, u, int(status))
  133. }