moved data parser into 'request_data' + created internal lib to parse multipart inside 'internal/multipart' + added default type 'any' + more things...
This commit is contained in:
parent
0641bb9131
commit
8f9c86c391
|
@ -0,0 +1,9 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
func Match(name string) bool {
|
||||||
|
return name == "any"
|
||||||
|
}
|
||||||
|
|
||||||
|
func Check(value interface{}) bool {
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package multipart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read all until the next boundary is found
|
||||||
|
func (i *MultipartReader) readComponent() ([]string, error) {
|
||||||
|
|
||||||
|
component := make([]string, 0)
|
||||||
|
|
||||||
|
for { // Read until boundary or error
|
||||||
|
|
||||||
|
line, _, err := i.reader.ReadLine()
|
||||||
|
|
||||||
|
/* (1) Stop on error */
|
||||||
|
if err != nil {
|
||||||
|
return component, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Stop at boundary */
|
||||||
|
if strings.HasPrefix(string(line), i.boundary) {
|
||||||
|
return component, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Ignore empty lines */
|
||||||
|
if len(line) > 0 {
|
||||||
|
component = append(component, string(line))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a single component from its raw lines
|
||||||
|
func (i *MultipartReader) parseComponent(line []string) error {
|
||||||
|
|
||||||
|
// next line index to use
|
||||||
|
cursor := 1
|
||||||
|
|
||||||
|
/* (1) Fail if invalid line count */
|
||||||
|
if len(line) < 2 {
|
||||||
|
return fmt.Errorf("Missing data to parse component")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Split meta data */
|
||||||
|
meta := strings.Split(line[0], "; ")
|
||||||
|
|
||||||
|
if len(meta) < 2 {
|
||||||
|
return fmt.Errorf("Missing component meta data")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Extract name */
|
||||||
|
if !strings.HasPrefix(meta[1], `name="`) {
|
||||||
|
return fmt.Errorf("Cannot extract component name")
|
||||||
|
}
|
||||||
|
name := meta[1][len(`name="`) : len(meta[1])-1]
|
||||||
|
|
||||||
|
/* (4) Check if it is a file */
|
||||||
|
isFile := len(meta) > 2 && strings.HasPrefix(meta[2], `filename="`)
|
||||||
|
|
||||||
|
// skip next line (Content-Type) if file
|
||||||
|
if isFile {
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Create index if name not already used */
|
||||||
|
already, isset := i.Components[name]
|
||||||
|
if !isset {
|
||||||
|
|
||||||
|
i.Components[name] = &MultipartComponent{
|
||||||
|
File: isFile,
|
||||||
|
Data: make([]string, 0),
|
||||||
|
}
|
||||||
|
already = i.Components[name]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (6) Store new value */
|
||||||
|
already.Data = append(already.Data, strings.Join(line[cursor:], "\n"))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package multipart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Creates a new multipart reader from an http.Request
|
||||||
|
func CreateReader(req *http.Request) *MultipartReader {
|
||||||
|
|
||||||
|
/* (1) extract boundary */
|
||||||
|
boundary := req.Header.Get("Content-Type")[len("multipart/form-data; boundary="):]
|
||||||
|
boundary = fmt.Sprintf("--%s", boundary)
|
||||||
|
|
||||||
|
/* (2) init reader */
|
||||||
|
i := &MultipartReader{
|
||||||
|
reader: bufio.NewReader(req.Body),
|
||||||
|
boundary: boundary,
|
||||||
|
Components: make(map[string]*MultipartComponent),
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Place reader cursor after first boundary */
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
line []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
for err == nil && string(line) != boundary {
|
||||||
|
line, _, err = i.reader.ReadLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
return i
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses the multipart components from the request
|
||||||
|
func (i *MultipartReader) Parse() error {
|
||||||
|
|
||||||
|
/* (1) For each component (until boundary) */
|
||||||
|
for {
|
||||||
|
|
||||||
|
// 1. Read component
|
||||||
|
component, err := i.readComponent()
|
||||||
|
|
||||||
|
// 2. Stop at EOF
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Dispatch error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. parse component
|
||||||
|
err = i.parseComponent(component)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package multipart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MultipartReader struct {
|
||||||
|
// reader used for http.Request.Body reading
|
||||||
|
reader *bufio.Reader
|
||||||
|
|
||||||
|
// boundary used to separate multipart components
|
||||||
|
boundary string
|
||||||
|
|
||||||
|
// result will be inside this field
|
||||||
|
Components map[string]*MultipartComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents a multipart component
|
||||||
|
type MultipartComponent struct {
|
||||||
|
// whether this component is a file
|
||||||
|
// if not, it is a simple variable data
|
||||||
|
File bool
|
||||||
|
|
||||||
|
// actual data
|
||||||
|
Data []string
|
||||||
|
}
|
|
@ -14,61 +14,15 @@ import (
|
||||||
// from a http.Request
|
// from a http.Request
|
||||||
func buildRequest(req *http.Request) (*Request, error) {
|
func buildRequest(req *http.Request) (*Request, error) {
|
||||||
|
|
||||||
/* (1) Init request */
|
/* (1) Get useful data */
|
||||||
uri := NormaliseUri(req.URL.Path)
|
uri := NormaliseUri(req.URL.Path)
|
||||||
rawpost := FetchFormData(req)
|
uriparts := strings.Split(uri, "/")
|
||||||
rawget := FetchGetData(req)
|
|
||||||
|
/* (2) Init request */
|
||||||
inst := &Request{
|
inst := &Request{
|
||||||
Uri: strings.Split(uri, "/"),
|
Uri: uriparts,
|
||||||
GetData: make(map[string]interface{}, 0),
|
ControllerUri: make([]string, 0, len(uriparts)),
|
||||||
FormData: make(map[string]interface{}, 0),
|
Data: buildRequestDataFromRequest(req),
|
||||||
UrlData: make([]interface{}, 0),
|
|
||||||
Data: make(map[string]interface{}, 0),
|
|
||||||
}
|
|
||||||
inst.ControllerUri = make([]string, 0, len(inst.Uri))
|
|
||||||
|
|
||||||
/* (2) Fill 'Data' with GET data */
|
|
||||||
for name, rawdata := range rawget {
|
|
||||||
|
|
||||||
// 1. Parse arguments
|
|
||||||
data := parseHttpData(rawdata)
|
|
||||||
|
|
||||||
if data == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. prevent injections
|
|
||||||
if isParameterNameInjection(name) {
|
|
||||||
log.Printf("get.name_injection: '%s'\n", name)
|
|
||||||
delete(inst.GetData, name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. add into data
|
|
||||||
inst.GetData[name] = data
|
|
||||||
inst.Data[fmt.Sprintf("GET@%s", name)] = data
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Fill 'Data' with POST data */
|
|
||||||
for name, rawdata := range rawpost {
|
|
||||||
|
|
||||||
// 1. Parse arguments
|
|
||||||
data := parseHttpData(rawdata)
|
|
||||||
|
|
||||||
if data == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. prevent injections
|
|
||||||
if isParameterNameInjection(name) {
|
|
||||||
log.Printf("post.name_injection: '%s'\n", name)
|
|
||||||
delete(inst.FormData, name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. add into data
|
|
||||||
inst.Data[name] = data
|
|
||||||
inst.FormData[name] = data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return inst, nil
|
return inst, nil
|
||||||
|
@ -93,20 +47,6 @@ func NormaliseUri(uri string) string {
|
||||||
return uri
|
return uri
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchGetData extracts the GET data
|
|
||||||
// from an HTTP request
|
|
||||||
func FetchGetData(req *http.Request) map[string]interface{} {
|
|
||||||
|
|
||||||
res := make(map[string]interface{})
|
|
||||||
|
|
||||||
for name, value := range req.URL.Query() {
|
|
||||||
res[name] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchFormData extracts FORM data
|
// FetchFormData extracts FORM data
|
||||||
//
|
//
|
||||||
// - parse 'form-data' if not supported (not POST requests)
|
// - parse 'form-data' if not supported (not POST requests)
|
||||||
|
@ -167,16 +107,10 @@ func FetchFormData(req *http.Request) map[string]interface{} {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// isParameterNameInjection returns whether there is
|
|
||||||
// a parameter name injection:
|
|
||||||
// - inferred GET parameters
|
|
||||||
// - inferred URL parameters
|
|
||||||
func isParameterNameInjection(pName string) bool {
|
|
||||||
return strings.HasPrefix(pName, "GET@") || strings.HasPrefix(pName, "URL#")
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseHttpData parses http GET/POST data
|
// parseHttpData parses http GET/POST data
|
||||||
// - []string of 1 element : return json of element 0
|
// - []string
|
||||||
|
// - size = 1 : return json of first element
|
||||||
|
// - size > 1 : return array of json elements
|
||||||
// - string : return json if valid, else return raw string
|
// - string : return json if valid, else return raw string
|
||||||
func parseHttpData(data interface{}) interface{} {
|
func parseHttpData(data interface{}) interface{} {
|
||||||
dtype := reflect.TypeOf(data)
|
dtype := reflect.TypeOf(data)
|
||||||
|
@ -252,6 +186,6 @@ func parseHttpData(data interface{}) interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) NIL if unknown type */
|
/* (3) NIL if unknown type */
|
||||||
return nil
|
return dvalue
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
package gfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"git.xdrm.io/gfw/internal/multipart"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// buildRequestDataFromRequest builds a 'RequestData'
|
||||||
|
// from an http request
|
||||||
|
func buildRequestDataFromRequest(req *http.Request) *RequestData {
|
||||||
|
|
||||||
|
i := &RequestData{
|
||||||
|
Url: make([]*RequestParameter, 0),
|
||||||
|
Get: make(map[string]*RequestParameter),
|
||||||
|
Form: make(map[string]*RequestParameter),
|
||||||
|
Set: make(map[string]*RequestParameter),
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET (query) data
|
||||||
|
i.fetchGet(req)
|
||||||
|
|
||||||
|
// no Form if GET
|
||||||
|
if req.Method == "GET" {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST (body) data
|
||||||
|
i.fetchForm(req)
|
||||||
|
|
||||||
|
return i
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindUrl stores URL data and fills 'Set'
|
||||||
|
// with creating pointers inside 'Url'
|
||||||
|
func (i *RequestData) fillUrl(data []string) {
|
||||||
|
|
||||||
|
for index, value := range data {
|
||||||
|
|
||||||
|
// create set index
|
||||||
|
setindex := fmt.Sprintf("URL#%d", index)
|
||||||
|
|
||||||
|
// store value in 'Set'
|
||||||
|
i.Set[setindex] = &RequestParameter{
|
||||||
|
Parsed: false,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// create link in 'Url'
|
||||||
|
i.Url = append(i.Url, i.Set[setindex])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchGet stores data from the QUERY (in url parameters)
|
||||||
|
func (i *RequestData) fetchGet(req *http.Request) {
|
||||||
|
|
||||||
|
for name, value := range req.URL.Query() {
|
||||||
|
|
||||||
|
// prevent injections
|
||||||
|
if isParameterNameInjection(name) {
|
||||||
|
log.Printf("get.injection: '%s'\n", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// create set index
|
||||||
|
setindex := fmt.Sprintf("GET@%s", name)
|
||||||
|
|
||||||
|
// store value in 'Set'
|
||||||
|
i.Set[setindex] = &RequestParameter{
|
||||||
|
Parsed: false,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// create link in 'Get'
|
||||||
|
i.Get[name] = i.Set[setindex]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchForm stores FORM data
|
||||||
|
//
|
||||||
|
// - parse 'form-data' if not supported (not POST requests)
|
||||||
|
// - parse 'x-www-form-urlencoded'
|
||||||
|
// - parse 'application/json'
|
||||||
|
func (i *RequestData) fetchForm(req *http.Request) {
|
||||||
|
|
||||||
|
contentType := req.Header.Get("Content-Type")
|
||||||
|
|
||||||
|
// parse json
|
||||||
|
if strings.HasPrefix(contentType, "application/json") {
|
||||||
|
i.parseJsonForm(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse urlencoded
|
||||||
|
if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") {
|
||||||
|
i.parseUrlencodedForm(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse multipart
|
||||||
|
if strings.HasPrefix(contentType, "multipart/form-data; boundary=") {
|
||||||
|
i.parseMultipartForm(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if unknown type store nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseJsonForm parses JSON from the request body inside 'Form'
|
||||||
|
// and 'Set'
|
||||||
|
func (i *RequestData) parseJsonForm(req *http.Request) {
|
||||||
|
|
||||||
|
parsed := make(map[string]interface{}, 0)
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(req.Body)
|
||||||
|
|
||||||
|
// if parse error: do nothing
|
||||||
|
if err := decoder.Decode(&parsed); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// else store values 'parsed' values
|
||||||
|
for name, value := range parsed {
|
||||||
|
|
||||||
|
// prevent injections
|
||||||
|
if isParameterNameInjection(name) {
|
||||||
|
log.Printf("post.injection: '%s'\n", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value in 'Set'
|
||||||
|
i.Set[name] = &RequestParameter{
|
||||||
|
Parsed: true,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// create link in 'Form'
|
||||||
|
i.Form[name] = i.Set[name]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseUrlencodedForm parses urlencoded from the request body inside 'Form'
|
||||||
|
// and 'Set'
|
||||||
|
func (i *RequestData) parseUrlencodedForm(req *http.Request) {
|
||||||
|
|
||||||
|
// use http.Request interface
|
||||||
|
req.ParseForm()
|
||||||
|
|
||||||
|
for name, value := range req.PostForm {
|
||||||
|
|
||||||
|
// prevent injections
|
||||||
|
if isParameterNameInjection(name) {
|
||||||
|
log.Printf("post.injection: '%s'\n", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value in 'Set'
|
||||||
|
i.Set[name] = &RequestParameter{
|
||||||
|
Parsed: false,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// create link in 'Form'
|
||||||
|
i.Form[name] = i.Set[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseMultipartForm parses multi-part from the request body inside 'Form'
|
||||||
|
// and 'Set'
|
||||||
|
func (i *RequestData) parseMultipartForm(req *http.Request) {
|
||||||
|
|
||||||
|
/* (1) Create reader */
|
||||||
|
mpr := multipart.CreateReader(req)
|
||||||
|
|
||||||
|
/* (2) Parse multipart */
|
||||||
|
mpr.Parse()
|
||||||
|
|
||||||
|
/* (3) Store data into 'Form' and 'Set */
|
||||||
|
for name, component := range mpr.Components {
|
||||||
|
|
||||||
|
// prevent injections
|
||||||
|
if isParameterNameInjection(name) {
|
||||||
|
log.Printf("post.injection: '%s'\n", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value in 'Set'
|
||||||
|
i.Set[name] = &RequestParameter{
|
||||||
|
Parsed: false,
|
||||||
|
File: component.File,
|
||||||
|
Value: component.Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
// create link in 'Form'
|
||||||
|
i.Form[name] = i.Set[name]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// isParameterNameInjection returns whether there is
|
||||||
|
// a parameter name injection:
|
||||||
|
// - inferred GET parameters
|
||||||
|
// - inferred URL parameters
|
||||||
|
func isParameterNameInjection(pName string) bool {
|
||||||
|
return strings.HasPrefix(pName, "GET@") || strings.HasPrefix(pName, "URL#")
|
||||||
|
}
|
23
router.go
23
router.go
|
@ -41,14 +41,8 @@ func (s *Server) route(res http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) Extract URI params */
|
/* (3) Extract & store URI params */
|
||||||
uriParams := request.Uri[uriIndex:]
|
request.Data.fillUrl(request.Uri[uriIndex:])
|
||||||
|
|
||||||
/* (4) Store them as Data */
|
|
||||||
for i, data := range uriParams {
|
|
||||||
request.UrlData = append(request.UrlData, data)
|
|
||||||
request.Data[fmt.Sprintf("URL#%d", i)] = data
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Check method
|
/* (3) Check method
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
|
@ -82,7 +76,7 @@ func (s *Server) route(res http.ResponseWriter, req *http.Request) {
|
||||||
fmt.Printf("- %s: %v | '%v'\n", name, *param.Optional, *param.Rename)
|
fmt.Printf("- %s: %v | '%v'\n", name, *param.Optional, *param.Rename)
|
||||||
|
|
||||||
/* (1) Extract value */
|
/* (1) Extract value */
|
||||||
value, isset := request.Data[name]
|
p, isset := request.Data.Set[name]
|
||||||
|
|
||||||
/* (2) OPTIONAL ? */
|
/* (2) OPTIONAL ? */
|
||||||
if !isset {
|
if !isset {
|
||||||
|
@ -99,20 +93,23 @@ func (s *Server) route(res http.ResponseWriter, req *http.Request) {
|
||||||
paramError.BindArgument(name)
|
paramError.BindArgument(name)
|
||||||
break
|
break
|
||||||
|
|
||||||
// set default value if optional
|
// set default p if optional
|
||||||
} else {
|
} else {
|
||||||
value = *param.Default
|
p = &RequestParameter{
|
||||||
|
Parsed: true,
|
||||||
|
Value: *param.Default,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) Check type */
|
/* (3) Check type */
|
||||||
isValid := s.Checker.Run(param.Type, value)
|
isValid := s.Checker.Run(param.Type, p.Value)
|
||||||
if isValid != nil {
|
if isValid != nil {
|
||||||
paramError = ErrInvalidParam
|
paramError = ErrInvalidParam
|
||||||
paramError.BindArgument(name)
|
paramError.BindArgument(name)
|
||||||
paramError.BindArgument(param.Type)
|
paramError.BindArgument(param.Type)
|
||||||
paramError.BindArgument(value)
|
paramError.BindArgument(p.Value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
54
types.go
54
types.go
|
@ -13,10 +13,56 @@ type Server struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
// corresponds to the list of uri components
|
||||||
|
// featuring in the request URI
|
||||||
Uri []string
|
Uri []string
|
||||||
|
|
||||||
|
// portion of the URI that corresponds to the controllerpath
|
||||||
ControllerUri []string
|
ControllerUri []string
|
||||||
FormData map[string]interface{}
|
|
||||||
GetData map[string]interface{}
|
// contains all data from URL, GET, and FORM
|
||||||
UrlData []interface{}
|
Data *RequestData
|
||||||
Data map[string]interface{}
|
}
|
||||||
|
|
||||||
|
type RequestData struct {
|
||||||
|
|
||||||
|
// ordered values from the URI
|
||||||
|
// catches all after the controller path
|
||||||
|
//
|
||||||
|
// points to Request.Data
|
||||||
|
Url []*RequestParameter
|
||||||
|
|
||||||
|
// uri parameters following the QUERY format
|
||||||
|
//
|
||||||
|
// points to Request.Data
|
||||||
|
Get map[string]*RequestParameter
|
||||||
|
|
||||||
|
// form data depending on the Content-Type:
|
||||||
|
// 'application/json' => key-value pair is parsed as json into the map
|
||||||
|
// 'application/x-www-form-urlencoded' => standard parameters as QUERY parameters
|
||||||
|
// 'multipart/form-data' => parse form-data format
|
||||||
|
//
|
||||||
|
// points to Request.Data
|
||||||
|
Form map[string]*RequestParameter
|
||||||
|
|
||||||
|
// contains URL+GET+FORM data with prefixes:
|
||||||
|
// - FORM: no prefix
|
||||||
|
// - URL: 'URL#' followed by the index in Uri
|
||||||
|
// - GET: 'GET@' followed by the key in GET
|
||||||
|
Set map[string]*RequestParameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestParameter represents an http request parameter
|
||||||
|
// that can be of type URL, GET, or FORM (multipart, json, urlencoded)
|
||||||
|
type RequestParameter struct {
|
||||||
|
// whether the value has been json-parsed
|
||||||
|
// for optimisation purpose, parameters are only parsed
|
||||||
|
// if they are required by the current controller
|
||||||
|
Parsed bool
|
||||||
|
|
||||||
|
// whether the value is a file
|
||||||
|
File bool
|
||||||
|
|
||||||
|
// the actual parameter value
|
||||||
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue