refactor internal/reqdata to work with thew new config
This commit is contained in:
parent
93b31b9718
commit
b38a9a8111
|
@ -0,0 +1,30 @@
|
||||||
|
package reqdata
|
||||||
|
|
||||||
|
// Error allows you to create constant "const" error with type boxing.
|
||||||
|
type Error string
|
||||||
|
|
||||||
|
// Error implements the error builtin interface.
|
||||||
|
func (err Error) Error() string {
|
||||||
|
return string(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnknownType is returned when encountering an unknown type
|
||||||
|
const ErrUnknownType = Error("unknown type")
|
||||||
|
|
||||||
|
// ErrInvalidJSON is returned when json parse failed
|
||||||
|
const ErrInvalidJSON = Error("invalid json")
|
||||||
|
|
||||||
|
// ErrInvalidRootType is returned when json is a map
|
||||||
|
const ErrInvalidRootType = Error("invalid json root type")
|
||||||
|
|
||||||
|
// ErrInvalidParamName - parameter has an invalid
|
||||||
|
const ErrInvalidParamName = Error("invalid parameter name")
|
||||||
|
|
||||||
|
// ErrMissingRequiredParam - required param is missing
|
||||||
|
const ErrMissingRequiredParam = Error("missing required param")
|
||||||
|
|
||||||
|
// ErrInvalidType - parameter value does not satisfy its type
|
||||||
|
const ErrInvalidType = Error("invalid type")
|
||||||
|
|
||||||
|
// ErrMissingURIParameter - missing an URI parameter
|
||||||
|
const ErrMissingURIParameter = Error("missing URI parameter")
|
|
@ -4,19 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"git.xdrm.io/go/aicra/internal/cerr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrUnknownType is returned when encountering an unknown type
|
|
||||||
const ErrUnknownType = cerr.Error("unknown type")
|
|
||||||
|
|
||||||
// ErrInvalidJSON is returned when json parse failed
|
|
||||||
const ErrInvalidJSON = cerr.Error("invalid json")
|
|
||||||
|
|
||||||
// ErrInvalidRootType is returned when json is a map
|
|
||||||
const ErrInvalidRootType = cerr.Error("invalid json root type")
|
|
||||||
|
|
||||||
// Parameter represents an http request parameter
|
// Parameter represents an http request parameter
|
||||||
// that can be of type URL, GET, or FORM (multipart, json, urlencoded)
|
// that can be of type URL, GET, or FORM (multipart, json, urlencoded)
|
||||||
type Parameter struct {
|
type Parameter struct {
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
package reqdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.xdrm.io/go/aicra/internal/config"
|
||||||
|
"git.xdrm.io/go/aicra/internal/multipart"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set represents all data that can be caught:
|
||||||
|
// - URI (from the URI)
|
||||||
|
// - GET (default url data)
|
||||||
|
// - POST (from json, form-data, url-encoded)
|
||||||
|
// - '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
|
||||||
|
type Set struct {
|
||||||
|
service *config.Service
|
||||||
|
|
||||||
|
// contains URL+GET+FORM data with prefixes:
|
||||||
|
// - FORM: no prefix
|
||||||
|
// - URL: '{uri_var}'
|
||||||
|
// - GET: 'GET@' followed by the key in GET
|
||||||
|
Data map[string]*Parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new empty store.
|
||||||
|
func New(service *config.Service) *Set {
|
||||||
|
return &Set{
|
||||||
|
service: service,
|
||||||
|
Data: make(map[string]*Parameter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractURI fills 'Set' with creating pointers inside 'Url'
|
||||||
|
func (i *Set) ExtractURI(req http.Request) error {
|
||||||
|
uriparts := config.SplitURL(req.RequestURI)
|
||||||
|
|
||||||
|
for _, capture := range i.service.Captures {
|
||||||
|
// out of range
|
||||||
|
if capture.Index > len(uriparts)-1 {
|
||||||
|
return fmt.Errorf("%s: %w", capture.Name, ErrMissingURIParameter)
|
||||||
|
}
|
||||||
|
value := uriparts[capture.Index]
|
||||||
|
|
||||||
|
// should not happen
|
||||||
|
if capture.Ref == nil {
|
||||||
|
return fmt.Errorf("%s: %w", capture.Name, ErrUnknownType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check type
|
||||||
|
cast, valid := capture.Ref.Validator(value)
|
||||||
|
if !valid {
|
||||||
|
return fmt.Errorf("%s: %w", capture.Name, ErrInvalidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store cast value in 'Set'
|
||||||
|
i.Data[capture.Ref.Rename] = &Parameter{
|
||||||
|
Value: cast,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractQuery data from the url query parameters
|
||||||
|
func (i *Set) ExtractQuery(req *http.Request) error {
|
||||||
|
query := req.URL.Query()
|
||||||
|
|
||||||
|
for name, param := range i.service.Query {
|
||||||
|
value, exist := query[name]
|
||||||
|
|
||||||
|
// fail on missing required
|
||||||
|
if !exist && !param.Optional {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrMissingRequiredParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional
|
||||||
|
if !exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check type
|
||||||
|
cast, valid := param.Validator(value)
|
||||||
|
if !valid {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrInvalidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value
|
||||||
|
i.Data[param.Rename] = &Parameter{
|
||||||
|
Value: cast,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractForm data from request
|
||||||
|
//
|
||||||
|
// - parse 'form-data' if not supported for non-POST requests
|
||||||
|
// - parse 'x-www-form-urlencoded'
|
||||||
|
// - parse 'application/json'
|
||||||
|
func (i *Set) ExtractForm(req *http.Request) error {
|
||||||
|
|
||||||
|
// ignore GET method
|
||||||
|
if req.Method == http.MethodGet {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := req.Header.Get("Content-Type")
|
||||||
|
|
||||||
|
// parse json
|
||||||
|
if strings.HasPrefix(contentType, "application/json") {
|
||||||
|
return i.parseJSON(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse urlencoded
|
||||||
|
if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") {
|
||||||
|
return i.parseUrlencoded(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse multipart
|
||||||
|
if strings.HasPrefix(contentType, "multipart/form-data; boundary=") {
|
||||||
|
return i.parseMultipart(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing to parse
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseJSON parses JSON from the request body inside 'Form'
|
||||||
|
// and 'Set'
|
||||||
|
func (i *Set) parseJSON(req *http.Request) error {
|
||||||
|
|
||||||
|
parsed := make(map[string]interface{}, 0)
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(req.Body)
|
||||||
|
if err := decoder.Decode(&parsed); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, param := range i.service.Form {
|
||||||
|
value, exist := parsed[name]
|
||||||
|
|
||||||
|
// fail on missing required
|
||||||
|
if !exist && !param.Optional {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrMissingRequiredParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional
|
||||||
|
if !exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail on invalid type
|
||||||
|
cast, valid := param.Validator(value)
|
||||||
|
if !valid {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrInvalidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value
|
||||||
|
i.Data[param.Rename] = &Parameter{
|
||||||
|
Value: cast,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseUrlencoded parses urlencoded from the request body inside 'Form'
|
||||||
|
// and 'Set'
|
||||||
|
func (i *Set) parseUrlencoded(req *http.Request) error {
|
||||||
|
// use http.Request interface
|
||||||
|
if err := req.ParseForm(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, param := range i.service.Form {
|
||||||
|
value, exist := req.PostForm[name]
|
||||||
|
|
||||||
|
// fail on missing required
|
||||||
|
if !exist && !param.Optional {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrMissingRequiredParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional
|
||||||
|
if !exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check type
|
||||||
|
cast, valid := param.Validator(value)
|
||||||
|
if !valid {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrInvalidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value
|
||||||
|
i.Data[param.Rename] = &Parameter{
|
||||||
|
Value: cast,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseMultipart parses multi-part from the request body inside 'Form'
|
||||||
|
// and 'Set'
|
||||||
|
func (i *Set) parseMultipart(req *http.Request) error {
|
||||||
|
|
||||||
|
// 1. create reader
|
||||||
|
boundary := req.Header.Get("Content-Type")[len("multipart/form-data; boundary="):]
|
||||||
|
mpr, err := multipart.NewReader(req.Body, boundary)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. parse multipart
|
||||||
|
if err = mpr.Parse(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, param := range i.service.Form {
|
||||||
|
value, exist := mpr.Data[name]
|
||||||
|
|
||||||
|
// fail on missing required
|
||||||
|
if !exist && !param.Optional {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrMissingRequiredParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional
|
||||||
|
if !exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail on invalid type
|
||||||
|
cast, valid := param.Validator(value)
|
||||||
|
if !valid {
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrInvalidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store value
|
||||||
|
i.Data[param.Rename] = &Parameter{
|
||||||
|
Value: cast,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
|
@ -1,301 +0,0 @@
|
||||||
package reqdata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"git.xdrm.io/go/aicra/internal/multipart"
|
|
||||||
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Store represents all data that can be caught:
|
|
||||||
// - URI (guessed from the URI by removing the service path)
|
|
||||||
// - GET (default url data)
|
|
||||||
// - POST (from json, form-data, url-encoded)
|
|
||||||
type Store struct {
|
|
||||||
|
|
||||||
// ordered values from the URI
|
|
||||||
// catches all after the service path
|
|
||||||
//
|
|
||||||
// points to Store.Data
|
|
||||||
URI []*Parameter
|
|
||||||
|
|
||||||
// uri parameters following the QUERY format
|
|
||||||
//
|
|
||||||
// points to Store.Data
|
|
||||||
Get map[string]*Parameter
|
|
||||||
|
|
||||||
// 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 Store.Data
|
|
||||||
Form map[string]*Parameter
|
|
||||||
|
|
||||||
// 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]*Parameter
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new store from an http request.
|
|
||||||
// URI params is required because it only takes into account after service path
|
|
||||||
// we do not know in this scope.
|
|
||||||
func New(uriParams []string, req *http.Request) *Store {
|
|
||||||
ds := &Store{
|
|
||||||
URI: make([]*Parameter, 0),
|
|
||||||
Get: make(map[string]*Parameter),
|
|
||||||
Form: make(map[string]*Parameter),
|
|
||||||
Set: make(map[string]*Parameter),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. set URI parameters
|
|
||||||
ds.setURIParams(uriParams)
|
|
||||||
|
|
||||||
// ignore nil requests
|
|
||||||
if req == nil {
|
|
||||||
return ds
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. GET (query) data
|
|
||||||
ds.readQuery(req)
|
|
||||||
|
|
||||||
// 3. We are done if GET method
|
|
||||||
if req.Method == http.MethodGet {
|
|
||||||
return ds
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. POST (body) data
|
|
||||||
ds.readForm(req)
|
|
||||||
|
|
||||||
return ds
|
|
||||||
}
|
|
||||||
|
|
||||||
// setURIParameters fills 'Set' with creating pointers inside 'Url'
|
|
||||||
func (i *Store) setURIParams(orderedUParams []string) {
|
|
||||||
|
|
||||||
for index, value := range orderedUParams {
|
|
||||||
|
|
||||||
// create set index
|
|
||||||
setindex := fmt.Sprintf("URL#%d", index)
|
|
||||||
|
|
||||||
// store value in 'Set'
|
|
||||||
i.Set[setindex] = &Parameter{
|
|
||||||
Parsed: false,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
|
|
||||||
// create link in 'Url'
|
|
||||||
i.URI = append(i.URI, i.Set[setindex])
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// readQuery stores data from the QUERY (in url parameters)
|
|
||||||
func (i *Store) readQuery(req *http.Request) {
|
|
||||||
|
|
||||||
for name, value := range req.URL.Query() {
|
|
||||||
|
|
||||||
// prevent invalid names
|
|
||||||
if !isNameValid(name) {
|
|
||||||
log.Printf("invalid variable name: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent injections
|
|
||||||
if hasNameInjection(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] = &Parameter{
|
|
||||||
Parsed: false,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
|
|
||||||
// create link in 'Get'
|
|
||||||
i.Get[name] = i.Set[setindex]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// readForm stores FORM data
|
|
||||||
//
|
|
||||||
// - parse 'form-data' if not supported (not POST requests)
|
|
||||||
// - parse 'x-www-form-urlencoded'
|
|
||||||
// - parse 'application/json'
|
|
||||||
func (i *Store) readForm(req *http.Request) {
|
|
||||||
|
|
||||||
contentType := req.Header.Get("Content-Type")
|
|
||||||
|
|
||||||
// parse json
|
|
||||||
if strings.HasPrefix(contentType, "application/json") {
|
|
||||||
i.parseJSON(req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse urlencoded
|
|
||||||
if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") {
|
|
||||||
i.parseUrlencoded(req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse multipart
|
|
||||||
if strings.HasPrefix(contentType, "multipart/form-data; boundary=") {
|
|
||||||
i.parseMultipart(req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if unknown type store nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseJSON parses JSON from the request body inside 'Form'
|
|
||||||
// and 'Set'
|
|
||||||
func (i *Store) parseJSON(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 {
|
|
||||||
log.Printf("json.parse() %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// else store values 'parsed' values
|
|
||||||
for name, value := range parsed {
|
|
||||||
|
|
||||||
// prevent invalid names
|
|
||||||
if !isNameValid(name) {
|
|
||||||
log.Printf("invalid variable name: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent injections
|
|
||||||
if hasNameInjection(name) {
|
|
||||||
log.Printf("post.injection: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// store value in 'Set'
|
|
||||||
i.Set[name] = &Parameter{
|
|
||||||
Parsed: true,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
|
|
||||||
// create link in 'Form'
|
|
||||||
i.Form[name] = i.Set[name]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseUrlencoded parses urlencoded from the request body inside 'Form'
|
|
||||||
// and 'Set'
|
|
||||||
func (i *Store) parseUrlencoded(req *http.Request) {
|
|
||||||
|
|
||||||
// use http.Request interface
|
|
||||||
if err := req.ParseForm(); err != nil {
|
|
||||||
log.Printf("urlencoded.parse() %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, value := range req.PostForm {
|
|
||||||
|
|
||||||
// prevent invalid names
|
|
||||||
if !isNameValid(name) {
|
|
||||||
log.Printf("invalid variable name: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent injections
|
|
||||||
if hasNameInjection(name) {
|
|
||||||
log.Printf("post.injection: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// store value in 'Set'
|
|
||||||
i.Set[name] = &Parameter{
|
|
||||||
Parsed: false,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
|
|
||||||
// create link in 'Form'
|
|
||||||
i.Form[name] = i.Set[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseMultipart parses multi-part from the request body inside 'Form'
|
|
||||||
// and 'Set'
|
|
||||||
func (i *Store) parseMultipart(req *http.Request) {
|
|
||||||
|
|
||||||
/* (1) Create reader */
|
|
||||||
boundary := req.Header.Get("Content-Type")[len("multipart/form-data; boundary="):]
|
|
||||||
mpr, err := multipart.NewReader(req.Body, boundary)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (2) Parse multipart */
|
|
||||||
if err = mpr.Parse(); err != nil {
|
|
||||||
log.Printf("multipart.parse() %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Store data into 'Form' and 'Set */
|
|
||||||
for name, data := range mpr.Data {
|
|
||||||
|
|
||||||
// prevent invalid names
|
|
||||||
if !isNameValid(name) {
|
|
||||||
log.Printf("invalid variable name: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent injections
|
|
||||||
if hasNameInjection(name) {
|
|
||||||
log.Printf("post.injection: '%s'\n", name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// store value in 'Set'
|
|
||||||
i.Set[name] = &Parameter{
|
|
||||||
Parsed: false,
|
|
||||||
File: len(data.GetHeader("filename")) > 0,
|
|
||||||
Value: string(data.Data),
|
|
||||||
}
|
|
||||||
|
|
||||||
// create link in 'Form'
|
|
||||||
i.Form[name] = i.Set[name]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasNameInjection returns whether there is
|
|
||||||
// a parameter name injection:
|
|
||||||
// - inferred GET parameters
|
|
||||||
// - inferred URL parameters
|
|
||||||
func hasNameInjection(pName string) bool {
|
|
||||||
return strings.HasPrefix(pName, "GET@") || strings.HasPrefix(pName, "URL#")
|
|
||||||
}
|
|
||||||
|
|
||||||
// isNameValid returns whether a parameter name (without the GET@ or URL# prefix) is valid
|
|
||||||
// if fails if the name begins/ends with underscores
|
|
||||||
func isNameValid(pName string) bool {
|
|
||||||
return strings.Trim(pName, "_") == pName
|
|
||||||
}
|
|
Loading…
Reference in New Issue