-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/http 2 http param mapping #57
Changes from 3 commits
b2e0f27
a678ce7
aa8f29d
1024b7b
fb6d366
7952ad8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ import ( | |
"bytes" | ||
"encoding/json" | ||
"io/ioutil" | ||
"net/url" | ||
"reflect" | ||
"strconv" | ||
) | ||
|
@@ -35,14 +36,25 @@ import ( | |
"github.com/dubbogo/dubbo-go-proxy/pkg/config" | ||
) | ||
|
||
var mappers = map[string]client.ParamMapper{ | ||
constant.QueryStrings: queryStringsMapper{}, | ||
constant.Headers: headerMapper{}, | ||
constant.RequestBody: bodyMapper{}, | ||
constant.RequestURI: uriMapper{}, | ||
} | ||
|
||
type queryStringsMapper struct{} | ||
|
||
// nolint | ||
func (qm queryStringsMapper) Map(mp config.MappingParam, c client.Request, target interface{}) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why isn't the caller pointer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. originally, I don't hope to modify anything inside the client.Request, but since I have to add back the body after mapping the request body, I think pointer might be better now. |
||
rv, err := validateTarget(target) | ||
if err != nil { | ||
return err | ||
} | ||
c.IngressRequest.ParseForm() | ||
queryValues, err := url.ParseQuery(c.IngressRequest.URL.RawQuery) | ||
if err != nil { | ||
return errors.Wrap(err, "Error happened when parsing the query paramters") | ||
} | ||
_, key, err := client.ParseMapSource(mp.Name) | ||
if err != nil { | ||
return err | ||
|
@@ -51,18 +63,19 @@ func (qm queryStringsMapper) Map(mp config.MappingParam, c client.Request, targe | |
if err != nil { | ||
return errors.Errorf("Parameter mapping %v incorrect", mp) | ||
} | ||
formValue := c.IngressRequest.Form.Get(key[0]) | ||
if len(formValue) == 0 { | ||
qValue := queryValues.Get(key[0]) | ||
if len(qValue) == 0 { | ||
return errors.Errorf("Query parameter %s does not exist", key) | ||
} | ||
|
||
setTarget(rv, pos, formValue) | ||
setTarget(rv, pos, qValue) | ||
|
||
return nil | ||
} | ||
|
||
type headerMapper struct{} | ||
|
||
// nolint | ||
func (hm headerMapper) Map(mp config.MappingParam, c client.Request, target interface{}) error { | ||
rv, err := validateTarget(target) | ||
if err != nil { | ||
|
@@ -83,7 +96,9 @@ func (hm headerMapper) Map(mp config.MappingParam, c client.Request, target inte | |
|
||
type bodyMapper struct{} | ||
|
||
// nolint | ||
func (bm bodyMapper) Map(mp config.MappingParam, c client.Request, target interface{}) error { | ||
// TO-DO: add support for content-type other than application/json | ||
rv, err := validateTarget(target) | ||
if err != nil { | ||
return err | ||
|
@@ -98,36 +113,67 @@ func (bm bodyMapper) Map(mp config.MappingParam, c client.Request, target interf | |
} | ||
|
||
rawBody, err := ioutil.ReadAll(c.IngressRequest.Body) | ||
defer func() { | ||
c.IngressRequest.Body = ioutil.NopCloser(bytes.NewReader(rawBody)) | ||
}() | ||
if err != nil { | ||
return err | ||
} | ||
mapBody := map[string]interface{}{} | ||
err = json.Unmarshal(rawBody, &mapBody) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
val, err := getMapValue(mapBody, keys) | ||
json.Unmarshal(rawBody, &mapBody) | ||
val, err := client.GetMapValue(mapBody, keys) | ||
|
||
setTarget(rv, pos, val) | ||
c.IngressRequest.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody)) | ||
return nil | ||
} | ||
|
||
func getMapValue(sourceMap map[string]interface{}, keys []string) (interface{}, error) { | ||
if len(keys) == 1 && keys[0] == constant.DefaultBodyAll { | ||
return sourceMap, nil | ||
} | ||
for i, key := range keys { | ||
_, ok := sourceMap[key] | ||
if !ok { | ||
return nil, errors.Errorf("%s does not exist in request body", key) | ||
} | ||
rvalue := reflect.ValueOf(sourceMap[key]) | ||
if rvalue.Type().Kind() != reflect.Map { | ||
return rvalue.Interface(), nil | ||
} | ||
return getMapValue(sourceMap[key].(map[string]interface{}), keys[i+1:]) | ||
} | ||
return nil, nil | ||
type uriMapper struct{} | ||
|
||
// nolint | ||
func (um uriMapper) Map(mp config.MappingParam, c client.Request, target interface{}) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Map is public, add |
||
rv, err := validateTarget(target) | ||
if err != nil { | ||
return err | ||
} | ||
_, keys, err := client.ParseMapSource(mp.Name) | ||
if err != nil { | ||
return err | ||
} | ||
pos, err := strconv.Atoi(mp.MapTo) | ||
if err != nil { | ||
return errors.Errorf("Parameter mapping %v incorrect", mp) | ||
} | ||
uriValues := c.API.GetURIParams(*c.IngressRequest.URL) | ||
setTarget(rv, pos, uriValues.Get(keys[0])) | ||
return nil | ||
} | ||
|
||
// validateTarget verify if the incoming target for the Map function | ||
// can be processed as expected. | ||
func validateTarget(target interface{}) (reflect.Value, error) { | ||
rv := reflect.ValueOf(target) | ||
if rv.Kind() != reflect.Ptr || rv.IsNil() { | ||
return rv, errors.New("Target params must be a non-nil pointer") | ||
} | ||
if _, ok := target.(*[]interface{}); !ok { | ||
return rv, errors.New("Target params for dubbo backend must be *[]interface{}") | ||
} | ||
return rv, nil | ||
} | ||
|
||
func setTarget(rv reflect.Value, pos int, value interface{}) { | ||
if rv.Kind() != reflect.Ptr && rv.Type().Name() != "" && rv.CanAddr() { | ||
rv = rv.Addr() | ||
} else { | ||
rv = rv.Elem() | ||
} | ||
|
||
tempValue := rv.Interface().([]interface{}) | ||
if len(tempValue) <= pos { | ||
list := make([]interface{}, pos+1-len(tempValue)) | ||
tempValue = append(tempValue, list...) | ||
} | ||
tempValue[pos] = value | ||
rv.Set(reflect.ValueOf(tempValue)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
“s” is lost