-
Notifications
You must be signed in to change notification settings - Fork 180
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
feat: enable --header flag to specify headers with requests #794
Conversation
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.
generally looks good to me, couple comments
cmd/oras/internal/option/remote.go
Outdated
before, after, found := strings.Cut(h, ":") | ||
if found && after != "" { | ||
if headers[before] == nil { | ||
headers[before] = strings.Split(after, ",") |
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 hadn't noticed this syntax before in other commands. It looks convenient, but not sure people will think 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.
Did you mean the argument of the -H
command? I designed it according to the behavior of curl
-H flag. @TerryHowe
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.
No, I was talking about the way you can provide multiple header values with the comma separation.
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.
@TerryHowe Are you suggesting we shouldn't unbox the input value and just forward what is provided?
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 have a strong opinion about it, but it seemed a bit odd. I don't think curl uses that comma separated format. I think you just have to specify the same header with multiple -H
flags
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.
curl don't use comma to separate header values because:
- value parsing can be done on server side. This also implies that oras don't need to split any header value.
- the header key can be duplicated for curl. This is different here, because in golang, the underlying data struct http.Header is a map, and thus header key cannot be duplicated. So we might need to concatenate duplicated header with comma explicitly.
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.
Update: removed comma unboxing.
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.
Made some comments on implementation and UX. Thanks again for contributing!
cmd/oras/internal/option/remote.go
Outdated
if len(opts.headers) != 0 { | ||
headers := map[string][]string{} | ||
for _, h := range opts.headers { | ||
before, after, found := strings.Cut(h, ":") |
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.
UX: should return an error if a flag is not formatted as <name>:<comma-separated-values>
, so users can be aware of the potential errors in their input.
cc @FeynmanZhou
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.
Returned error currently, need further discussion and confirmation.
We can just forward the value with trailing space. By design it should be ignored. I didn't find the RFC for this but there are some MDN docs mentioning it.
Shouldn't |
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more @@ Coverage Diff @@
## main #794 +/- ##
==========================================
+ Coverage 55.50% 56.03% +0.52%
==========================================
Files 23 23
Lines 935 953 +18
==========================================
+ Hits 519 534 +15
- Misses 374 376 +2
- Partials 42 43 +1
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
cmd/oras/internal/option/remote.go
Outdated
name, csv, found := strings.Cut(h, ":") | ||
if !found || strings.TrimSpace(csv) == "" { | ||
return fmt.Errorf("cannot parse headers: %q", h) | ||
} | ||
headers[name] = append(headers[name], strings.Split(csv, ",")...) |
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.
No need to unbox the value, just add it to the http headers.
name, csv, found := strings.Cut(h, ":") | |
if !found || strings.TrimSpace(csv) == "" { | |
return fmt.Errorf("cannot parse headers: %q", h) | |
} | |
headers[name] = append(headers[name], strings.Split(csv, ",")...) | |
name, value, found := strings.Cut(h, ":") | |
if !found || strings.TrimSpace(name) == "" || strings.TrimSpace(value) == "" { | |
return fmt.Errorf("invalid header: %q", h) | |
} | |
headers[name] = append(headers[name], value) |
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.
removed the unboxing. Behavior changed according to the RFC 2616 spec.
cmd/oras/internal/option/remote.go
Outdated
@@ -51,6 +51,9 @@ type Remote struct { | |||
resolveDialContext func(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) | |||
applyDistributionSpec bool | |||
distributionSpec distributionSpec | |||
|
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.
nit: remove empty line
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.
removed.
cmd/oras/internal/option/remote.go
Outdated
if !found || strings.TrimSpace(csv) == "" { | ||
return fmt.Errorf("cannot parse headers: %q", h) | ||
} | ||
headers[name] = append(headers[name], strings.Split(csv, ",")...) |
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.
We should consume the value as it is without splitting.
You can try -H "foo: a" -H "foo: b,c"
with curl
. It will generate
> foo: a
> foo: b,c
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.
Changed according to Billy's comment above. Splitting is removed.
cmd/oras/internal/option/remote.go
Outdated
for _, h := range opts.headerFlags { | ||
name, value, found := strings.Cut(h, ":") | ||
if !found || strings.TrimSpace(value) == "" { | ||
return fmt.Errorf("cannot parse headers: %q", h) |
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.
nit:
return fmt.Errorf("cannot parse headers: %q", h) | |
return fmt.Errorf("invalid header: %q", h) |
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.
changed accordingly.
cmd/oras/internal/option/remote.go
Outdated
headers := map[string][]string{} | ||
for _, h := range opts.headerFlags { | ||
name, value, found := strings.Cut(h, ":") | ||
if !found || strings.TrimSpace(value) == "" { |
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.
According to RFC 2616 Section 4.2, the name must not be empty and the value can be empty.
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.
Note:
package main
import (
"net/http"
"os"
)
func main() {
headers := make(http.Header)
headers[""] = []string{"abc"}
headers[" "] = []string{"efg"}
headers["empty"] = []string{""}
headers["space"] = []string{" "}
headers["foo"] = []string{"bar"}
headers["foo2"] = []string{" bar2"}
headers.Write(os.Stdout)
}
outputs
empty:
foo: bar
foo2: bar2
space:
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.
According to RFC 2616 Section 4.2, the name must not be empty and the value can be empty.
curl's behavior is the other way around. Which should I follow, curl or the RFC spec?
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.
Always follow the spec since the spec is the standard.
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.
Changed the behavior of parsing to be conformant to the spec.
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
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.
LGTM
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.
LGTM with suggestions
cmd/oras/internal/option/remote.go
Outdated
@@ -62,6 +64,7 @@ func (opts *Remote) EnableDistributionSpecFlag() { | |||
func (opts *Remote) ApplyFlags(fs *pflag.FlagSet) { | |||
opts.ApplyFlagsWithPrefix(fs, "", "") | |||
fs.BoolVarP(&opts.PasswordFromStdin, "password-stdin", "", false, "read password or identity token from stdin") | |||
fs.StringArrayVarP(&opts.headerFlags, "header", "H", []string{}, "add custom headers to requests") |
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.
nit: in golang, nil slice is still a valid slice.
fs.StringArrayVarP(&opts.headerFlags, "header", "H", []string{}, "add custom headers to requests") | |
fs.StringArrayVarP(&opts.headerFlags, "header", "H", nil, "add custom headers to requests") |
Signed-off-by: wangxiaoxuan273 <wangxiaoxuan119@gmail.com>
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.
LGTM
Resolves #521
Designed in accordance to the behavior(as exact spec can't be found) of
curl
-H flag. Can be used multiple times.Terminal output:
Some minor issues/questions:
map[string][]string
of golang, the spaces before and after the commas are not stripped. i.e. the values are"d",
" e"
," f"
.(update: splitting is removed, the argument is kept as what is after the colon.)
-H "a:b" -H "a:b"
to two repeated headers "a:b", and-H "a:b" -H "a:c"
to headers "a:b", "a:c". In this pr these behaviors are maintained.