Files
apinto/node/http-context/body.go
2021-11-11 20:23:52 +08:00

394 lines
7.9 KiB
Go

package http_context
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
http_service "github.com/eolinker/eosc/http-service"
"io/ioutil"
"net/http"
"mime"
"mime/multipart"
"net/url"
)
const defaultMultipartMemory = 32 << 20 // 32 MB
var (
errorNotForm = errors.New("contentType is not Form")
errorNotMultipart = errors.New("contentType is not Multipart")
errorNotAllowRaw = errors.New("contentType is not allow Raw")
)
const (
MultipartForm = "multipart/form-data"
FormData = "application/x-www-form-urlencoded"
TEXT = "text/plain"
JSON = "application/json"
JavaScript = "application/javascript"
AppLicationXML = "application/xml"
TextXML = "text/xml"
Html = "text/html"
)
//BodyRequestHandler body请求处理器
type BodyRequestHandler struct {
form url.Values
rawBody []byte
orgContentParam map[string]string
contentType string
files map[string]*http_service.FileHeader
isInit bool
isWriteRaw bool
object interface{}
}
//GetForm 获取表单参数
func (b *BodyRequestHandler) GetForm(key string) string {
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
return ""
}
b.parse()
if !b.isInit || b.form == nil {
return ""
}
return b.form.Get(key)
}
//ContentType 获取contentType
func (b *BodyRequestHandler) ContentType() string {
return b.contentType
}
//BodyForm 获取表单参数
func (b *BodyRequestHandler) BodyForm() (url.Values, error) {
err := b.parse()
if err != nil {
return nil, err
}
return b.form, nil
}
//RawBody 获取raw数据
func (b *BodyRequestHandler) RawBody() ([]byte, error) {
err := b.encode()
if err != nil {
return nil, err
}
return b.rawBody, nil
}
//Files 获取文件参数
func (b *BodyRequestHandler) Files() (map[string]*http_service.FileHeader, error) {
err := b.parse()
if err != nil {
return nil, err
}
return b.files, nil
}
func (b *BodyRequestHandler) GetFile(key string) (file *http_service.FileHeader, has bool) {
err := b.parse()
if err != nil {
return nil, false
}
file, has = b.files[key]
return file, has
}
//parse 解析
func (b *BodyRequestHandler) parse() error {
if b.isInit {
return nil
}
contentType, _, _ := mime.ParseMediaType(b.contentType)
switch contentType {
case JSON:
{
e := json.Unmarshal(b.rawBody, &b.object)
if e != nil {
return e
}
}
case AppLicationXML, TextXML:
{
e := xml.Unmarshal(b.rawBody, &b.object)
if e != nil {
return e
}
}
case MultipartForm:
{
r, err := multipartReader(b.contentType, false, b.rawBody)
if err != nil {
return err
}
form, err := r.ReadForm(defaultMultipartMemory)
if err != nil {
return err
}
if b.form == nil {
b.form = make(url.Values)
}
for k, v := range form.Value {
b.form[k] = append(b.form[k], v...)
}
b.files = make(map[string]*http_service.FileHeader)
for k, fs := range form.File {
if len(fs) > 0 {
file, err := fs[0].Open()
if err != nil {
return err
}
fileData, err := ioutil.ReadAll(file)
if err != nil {
return err
}
b.files[k] = &http_service.FileHeader{
FileName: fs[0].Filename,
Data: fileData,
Header: fs[0].Header,
}
}
}
b.object = b.form
}
case FormData:
{
form, err := url.ParseQuery(string(b.rawBody))
if err != nil {
return err
}
if b.form == nil {
b.form = form
} else {
for k, v := range form {
b.form[k] = append(b.form[k], v...)
}
}
b.object = b.form
}
}
b.isInit = true
return nil
}
//SetToForm 设置表单参数
func (b *BodyRequestHandler) SetToForm(key, value string) error {
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
return errorNotForm
}
err := b.parse()
if err != nil {
return err
}
b.isWriteRaw = false
if b.form == nil {
b.form = make(url.Values)
}
b.form.Set(key, value)
b.isWriteRaw = false
return nil
}
//AddForm 新增表单参数
func (b *BodyRequestHandler) AddForm(key, value string) error {
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
return errorNotForm
}
err := b.parse()
if err != nil {
return err
}
b.isWriteRaw = false
if b.form == nil {
b.form = make(url.Values)
}
b.form.Add(key, value)
return nil
}
//AddFile 新增文件参数
func (b *BodyRequestHandler) AddFile(key string, file *http_service.FileHeader) error {
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
return errorNotMultipart
}
err := b.parse()
if err != nil {
return err
}
b.isWriteRaw = false
if file == nil && b.files != nil {
delete(b.files, key)
return nil
}
if b.files == nil {
b.files = make(map[string]*http_service.FileHeader)
}
b.files[key] = file
return nil
}
//Clone 克隆body
func (b *BodyRequestHandler) Clone() *BodyRequestHandler {
rawBody, _ := b.RawBody()
return newBodyRequestHandler(b.contentType, rawBody)
}
//BodyInterface 获取请求体对象
func (b *BodyRequestHandler) BodyInterface() (interface{}, error) {
err := b.parse()
if err != nil {
return nil, err
}
return b.object, nil
}
//encode encode
func (b *BodyRequestHandler) encode() error {
if b.isWriteRaw {
return nil
}
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
b.isWriteRaw = true
return nil
}
if len(b.files) > 0 {
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
for name, file := range b.files {
part, err := writer.CreateFormFile(name, file.FileName)
if err != nil {
return err
}
_, err = part.Write(file.Data)
if err != nil {
return err
}
}
for key, values := range b.form {
temp := make(url.Values)
temp[key] = values
value := temp.Encode()
err := writer.WriteField(key, value)
if err != nil {
return err
}
}
err := writer.Close()
if err != nil {
return err
}
b.contentType = writer.FormDataContentType()
b.rawBody = body.Bytes()
b.isWriteRaw = true
} else {
if b.form != nil {
b.rawBody = []byte(b.form.Encode())
} else {
b.rawBody = make([]byte, 0, 0)
}
}
return nil
}
//SetForm 设置表单参数
func (b *BodyRequestHandler) SetForm(values url.Values) error {
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
return errorNotForm
}
b.parse()
b.form = values
b.isWriteRaw = false
return nil
}
//SetFile 设置文件参数
func (b *BodyRequestHandler) SetFile(files map[string]*http_service.FileHeader) error {
contentType, _, _ := mime.ParseMediaType(b.contentType)
if contentType != FormData && contentType != MultipartForm {
return errorNotForm
}
b.parse()
b.files = files
// b.form = values
b.isWriteRaw = false
return nil
}
//SetRaw 设置raw数据
func (b *BodyRequestHandler) SetRaw(contentType string, body []byte) {
b.rawBody, b.contentType, b.isInit, b.isWriteRaw = body, contentType, false, true
return
}
//newBodyRequestHandler 创建body请求处理器
func newBodyRequestHandler(contentType string, body []byte) *BodyRequestHandler {
b := new(BodyRequestHandler)
b.SetRaw(contentType, body)
return b
}
func multipartReader(contentType string, allowMixed bool, raw []byte) (*multipart.Reader, error) {
if contentType == "" {
return nil, http.ErrNotMultipart
}
d, params, err := mime.ParseMediaType(contentType)
if err != nil || !(d == "multipart/form-data" || allowMixed && d == "multipart/mixed") {
return nil, http.ErrNotMultipart
}
boundary, ok := params["boundary"]
if !ok {
return nil, http.ErrMissingBoundary
}
body := ioutil.NopCloser(bytes.NewBuffer(raw))
return multipart.NewReader(body, boundary), nil
}