rename ngin to rest
This commit is contained in:
19
rest/httpx/constants.go
Normal file
19
rest/httpx/constants.go
Normal 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
111
rest/httpx/requests.go
Normal 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
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
29
rest/httpx/responses.go
Normal 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)
|
||||
}
|
||||
}
|
||||
78
rest/httpx/responses_test.go
Normal file
78
rest/httpx/responses_test.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user