mirror of
https://github.com/eolinker/apinto
synced 2025-10-05 08:47:04 +08:00
394 lines
7.9 KiB
Go
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
|
|
}
|