rename ngin to rest

This commit is contained in:
kevin
2020-07-31 11:14:48 +08:00
parent e133ffd820
commit 0897f60c5d
78 changed files with 118 additions and 111 deletions

19
rest/httpx/constants.go Normal file
View File

@@ -0,0 +1,19 @@
package httpx
const (
ApplicationJson = "application/json"
ContentEncoding = "Content-Encoding"
ContentSecurity = "X-Content-Security"
ContentType = "Content-Type"
KeyField = "key"
SecretField = "secret"
TypeField = "type"
CryptionType = 1
)
const (
CodeSignaturePass = iota
CodeSignatureInvalidHeader
CodeSignatureWrongTime
CodeSignatureInvalidToken
)

111
rest/httpx/requests.go Normal file
View File

@@ -0,0 +1,111 @@
package httpx
import (
"io"
"net/http"
"strings"
"zero/core/mapping"
"zero/rest/internal/context"
)
const (
multipartFormData = "multipart/form-data"
formKey = "form"
pathKey = "path"
emptyJson = "{}"
maxMemory = 32 << 20 // 32MB
maxBodyLen = 8 << 20 // 8MB
separator = ";"
tokensInAttribute = 2
)
var (
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
)
func Parse(r *http.Request, v interface{}) error {
if err := ParsePath(r, v); err != nil {
return err
}
if err := ParseForm(r, v); err != nil {
return err
}
return ParseJsonBody(r, v)
}
// Parses the form request.
func ParseForm(r *http.Request, v interface{}) error {
if strings.Index(r.Header.Get(ContentType), multipartFormData) != -1 {
if err := r.ParseMultipartForm(maxMemory); err != nil {
return err
}
} else {
if err := r.ParseForm(); err != nil {
return err
}
}
params := make(map[string]interface{}, len(r.Form))
for name := range r.Form {
formValue := r.Form.Get(name)
if len(formValue) > 0 {
params[name] = formValue
}
}
return formUnmarshaler.Unmarshal(params, v)
}
func ParseHeader(headerValue string) map[string]string {
ret := make(map[string]string)
fields := strings.Split(headerValue, separator)
for _, field := range fields {
field = strings.TrimSpace(field)
if len(field) == 0 {
continue
}
kv := strings.SplitN(field, "=", tokensInAttribute)
if len(kv) != tokensInAttribute {
continue
}
ret[kv[0]] = kv[1]
}
return ret
}
// Parses the post request which contains json in body.
func ParseJsonBody(r *http.Request, v interface{}) error {
var reader io.Reader
if withJsonBody(r) {
reader = io.LimitReader(r.Body, maxBodyLen)
} else {
reader = strings.NewReader(emptyJson)
}
return mapping.UnmarshalJsonReader(reader, v)
}
// Parses the symbols reside in url path.
// Like http://localhost/bag/:name
func ParsePath(r *http.Request, v interface{}) error {
vars := context.Vars(r)
m := make(map[string]interface{}, len(vars))
for k, v := range vars {
m[k] = v
}
return pathUnmarshaler.Unmarshal(m, v)
}
func withJsonBody(r *http.Request) bool {
return r.ContentLength > 0 && strings.Index(r.Header.Get(ContentType), ApplicationJson) != -1
}

1023
rest/httpx/requests_test.go Normal file

File diff suppressed because it is too large Load Diff

29
rest/httpx/responses.go Normal file
View File

@@ -0,0 +1,29 @@
package httpx
import (
"encoding/json"
"net/http"
"zero/core/logx"
)
func OkJson(w http.ResponseWriter, v interface{}) {
WriteJson(w, http.StatusOK, v)
}
func WriteJson(w http.ResponseWriter, code int, v interface{}) {
w.Header().Set(ContentType, ApplicationJson)
w.WriteHeader(code)
if bs, err := json.Marshal(v); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
} else if n, err := w.Write(bs); err != nil {
// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
// so it's ignored here.
if err != http.ErrHandlerTimeout {
logx.Errorf("write response failed, error: %s", err)
}
} else if n < len(bs) {
logx.Errorf("actual bytes: %d, written bytes: %d", len(bs), n)
}
}

View File

@@ -0,0 +1,78 @@
package httpx
import (
"net/http"
"strings"
"testing"
"zero/core/logx"
"github.com/stretchr/testify/assert"
)
type message struct {
Name string `json:"name"`
}
func init() {
logx.Disable()
}
func TestOkJson(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
msg := message{Name: "anyone"}
OkJson(&w, msg)
assert.Equal(t, http.StatusOK, w.code)
assert.Equal(t, "{\"name\":\"anyone\"}", w.builder.String())
}
func TestWriteJsonTimeout(t *testing.T) {
// only log it and ignore
w := tracedResponseWriter{
headers: make(map[string][]string),
timeout: true,
}
msg := message{Name: "anyone"}
WriteJson(&w, http.StatusOK, msg)
assert.Equal(t, http.StatusOK, w.code)
}
func TestWriteJsonLessWritten(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
lessWritten: true,
}
msg := message{Name: "anyone"}
WriteJson(&w, http.StatusOK, msg)
assert.Equal(t, http.StatusOK, w.code)
}
type tracedResponseWriter struct {
headers map[string][]string
builder strings.Builder
code int
lessWritten bool
timeout bool
}
func (w *tracedResponseWriter) Header() http.Header {
return w.headers
}
func (w *tracedResponseWriter) Write(bytes []byte) (n int, err error) {
if w.timeout {
return 0, http.ErrHandlerTimeout
}
n, err = w.builder.Write(bytes)
if w.lessWritten {
n -= 1
}
return
}
func (w *tracedResponseWriter) WriteHeader(code int) {
w.code = code
}