-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Add a header type field #4993
Add a header type field #4993
Changes from 2 commits
7b86f41
fdbb32a
7ad2511
bc18aa0
a3a7cb3
a3286a9
ef89439
d4fb65f
f0443e0
b190a4e
b1cd520
ab5a906
f486653
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 |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package framework | ||
|
||
import ( | ||
"net/http" | ||
"reflect" | ||
"testing" | ||
) | ||
|
@@ -467,6 +468,55 @@ func TestFieldDataGet(t *testing.T) { | |
}, | ||
}, | ||
|
||
"type header, keypair string array": { | ||
map[string]*FieldSchema{ | ||
"foo": {Type: TypeHeader}, | ||
}, | ||
map[string]interface{}{ | ||
"foo": []interface{}{"key1:value1", "key2:value2", "key3:1"}, | ||
}, | ||
"foo", | ||
http.Header{ | ||
"Key1": []string{"value1"}, | ||
"Key2": []string{"value2"}, | ||
"Key3": []string{"1"}, | ||
}, | ||
}, | ||
|
||
"type header, keypair string array with dupe key": { | ||
map[string]*FieldSchema{ | ||
"foo": {Type: TypeHeader}, | ||
}, | ||
map[string]interface{}{ | ||
"foo": []interface{}{"key1:value1", "key2:value2", "key3:1", "key3:true"}, | ||
}, | ||
"foo", | ||
http.Header{ | ||
"Key1": []string{"value1"}, | ||
"Key2": []string{"value2"}, | ||
"Key3": []string{"1", "true"}, | ||
}, | ||
}, | ||
|
||
"type header, map string slice": { | ||
map[string]*FieldSchema{ | ||
"foo": {Type: TypeHeader}, | ||
}, | ||
map[string]interface{}{ | ||
"foo": map[string][]string{ | ||
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. I think the JSON Unmarshaller will return this as a 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. Will do. 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. It was a good test! I ran Vault in dev mode and made a little path that took
And it actually parsed both the faux bool and the faux int field with no error, and they came in as strings, which is what I would want for a header. |
||
"key1": {"value1"}, | ||
"key2": {"value2"}, | ||
"key3": {"1"}, | ||
}, | ||
}, | ||
"foo", | ||
http.Header{ | ||
"Key1": []string{"value1"}, | ||
"Key2": []string{"value2"}, | ||
"Key3": []string{"1"}, | ||
}, | ||
}, | ||
|
||
"name string type, not supplied": { | ||
map[string]*FieldSchema{ | ||
"foo": {Type: TypeNameString}, | ||
|
@@ -556,6 +606,15 @@ func TestFieldDataGet(t *testing.T) { | |
"foo", | ||
map[string]string{}, | ||
}, | ||
|
||
"type header, not supplied": { | ||
map[string]*FieldSchema{ | ||
"foo": {Type: TypeHeader}, | ||
}, | ||
map[string]interface{}{}, | ||
"foo", | ||
http.Header{}, | ||
}, | ||
} | ||
|
||
for name, tc := range cases { | ||
|
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.
Do you need to do this step? It seems to me you would want to preserve formatting and any comparisons you would retrieve the header using the
Get
function and do any normalized text compares there.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.
It's definitely weird.
The reason I do it is because if you send in a header of
"hello:world"
and then later doheader.Get("hello")
, it doesn't find"world"
. That's because under the hood, theGet
method first converts"hello"
to"Hello"
and then looks for it in the map.I thought this was a really weird behavior, and tried to think through how to best achieve what someone would expect. I thought about, instead of using an
http.Header
, maybe I should just use a straight-out map. But then, people are sending in headers so maybe they would expect that kind of behavior.In the end, I did this because I thought from a usability perspective it might be the best option. But I'm open to other approaches because it's a tough call.
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.
I am relatively certain that colons are illegal in header key values, which would explain this behavior.
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.
I don't know if I explained that well LOL. In the example of
"hello:world"
I was thinking of"hello"
as the key and"world"
as the value. Probably would have been a better example if I'd done JSON or something.I was trying to say that if you give it a lower-case key of hello, then later try to pull out a lower-case hello, it finds nothing. And it's because under the hood, it converts it to Title Case before searching for it in the map, so it's looking for
"Hello"
while it's sitting in the map as"hello"
, and thus misses it. It converts it to Title Case using that canonical method.So by also calling that canonical method on keys on the way in, it also Title Cases the keys in the map so they'll have hits. This is definitely a trade-off because, while you'll now have case-insensitive hits using the
header.Get("hello")
method, if you need to pull headers out like this:header["hello"]
it won't work anymore. You'd use theGet
method for headers that you know only have one value, and the map-key-accessing method for headers that may have multiple values.Ultimately, I'm honestly not super in love with the magic the
http.Header
type is doing because I think it's actually pretty weird. This is why I'm tempted to just turn it into amap[string][]string
, and to do away with the canonical stuff, so it's way more evident and straight-forward how to use it.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.
I too struggled with this type for whatever reason, it is challenging to use. Maybe you're doing a little too much sanitation and you just need to pass through what they give you and serialize it directly to disk when necessary. Here is the code I came up with dealing with headers, config, and output. https://github.com/hashicorp/vault/blob/master/vault/ui.go
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.
Probably you shouldn't do any sanitization at all -- you should get it to the correct type and just copy it over verbatim. There's no need for you to do any textproto stuff when Header is doing it anyways.