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
NE-1141: Adds logic for setting and deleting headers via Ingress Operator CR and Route Object. #438
Conversation
fca6a85
to
54f0b6e
Compare
efc4f2a
to
c312c22
Compare
/test verify |
ba2ad10
to
4c7e751
Compare
9ade113
to
066daad
Compare
0a44eec
to
975a0d9
Compare
7e2ad7a
to
65b288d
Compare
pkg/cmd/infra/router/template.go
Outdated
// RFC 2616, section 4.2, states that the header name | ||
// must be a valid token. | ||
if !validTokenRE.MatchString(headerName) { | ||
return fmt.Errorf("invalid HTTP header name: %v", headerName) |
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("invalid HTTP header name: %v", headerName) | |
return fmt.Errorf("invalid HTTP header name: %s", headerName) |
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.
ok
t.Errorf(" expected %s, got %s", tc.expectedValue, actualValue) | ||
case tc.expectErrorMessage == "" && actualErrorMessage != nil && actualErrorMessage.Error() != "": | ||
t.Fatalf("unexpected error: %v", actualErrorMessage) | ||
case tc.expectErrorMessage != "" && actualErrorMessage != nil && actualErrorMessage.Error() == "": |
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.
Here you should be looking for the case where actualErrorMessage is nil or blank:
case tc.expectErrorMessage != "" && actualErrorMessage != nil && actualErrorMessage.Error() == "": | |
case tc.expectErrorMessage != "" && (actualErrorMessage == nil || actualErrorMessage.Error() == ""): |
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.
if actualErrorMessage == nil
then actualErrorMessage.Error() i.e nil.Error() will crash
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 will stop processing the ||
conjunction if actualErrorMessage == nil.
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.
ok done
30f3fa2
to
fbe3330
Compare
if err != nil { | ||
return captureHeaders, fmt.Errorf("failed to decode percent encoding: %v", parts[1]) | ||
} | ||
sanitizedHeaderValue := templateplugin.SanitizeHeaderValue(headerValue) |
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.
Why does the header value have to be sanitized? If it has a valid reason, why isn't the header name or action sanitized?
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.
Header name goes through a regex check so a user can't provide an invalid value.
Header action also only 2 values are allowed via api so this check happens at api level.
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.
The SanitizeHeaderValue is escaping single quotes, which we allow in the header name per the regex. Why don't we allow single quotes in the header 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.
SanitizeHeaderValue
doesn't actually sanitize, but rather it quotes the string (for this reason, I've suggested changing "sanitize" to "quote" a few times). I agree, it certainly seems like the header name can contain '
and therefore needs to be quoted in the configuration file, just as the value needs to be quoted.
pkg/cmd/infra/router/template.go
Outdated
func checkValidHeaderName(headerName string) error { | ||
// RFC 2616, section 4.2, states that the header name | ||
// must be a valid token. | ||
if !validTokenRE.MatchString(headerName) { |
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.
The validTokenRE is the same now as the regex for header name in https://github.com/openshift/library-go/pull/1449/files#diff-bfc6ba95cbc94986901ce1d0e3b74ee966499eab85a96e1d1ff763d2d74a7eeeR64
How are you going to make sure changes between these get propagated? I think you probably need to choose one or the other.
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.
This point is valid. Both check the same chars. However I can add a regex check here to maintain consistency.
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 will put a comment here.
pkg/cmd/infra/router/template.go
Outdated
|
||
func checkValidAction(action string) error { | ||
if action != string(routev1.Set) && action != string(routev1.Delete) { | ||
return fmt.Errorf("invalid action %s", action) |
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.
Add a semi-colon between the error message and the error value, as customary. Unit tests will need to be updated too.
return fmt.Errorf("invalid action %s", action) | |
return fmt.Errorf("invalid action: %s", action) |
pkg/cmd/infra/router/template.go
Outdated
var capture templateplugin.HTTPHeader | ||
var err error | ||
if len(in) == 0 { | ||
return captureHeaders, fmt.Errorf("encoded header string not present.") |
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.
This is the only error message with a period at the end. Please remove.
return captureHeaders, fmt.Errorf("encoded header string not present.") | |
return captureHeaders, fmt.Errorf("encoded header string not present") |
gomfmt -w pkg/router/template/certmanager_test.go
…nd Route Object. `images/router/haproxy/conf/haproxy-config.template` Sets the http-response and http-request stanzas to set or delete custom HTTP Response/Request headers. `pkg/cmd/infra/router/template.go` This consists the logic to get the value from the env var from router deployment and use it for setting/deleting HTTP response/request headers. `pkg/router/template/plugin.go` Adds new fields in the TemplatePluginConfig struct to set or delete HTTP request/reponse headers. These are needed to set the values we get from router deployment env var. `pkg/router/template/router.go` This consists of the logic extracting header values from the route object and then set/delete HTTP request/reponse headers. `pkg/router/template/router_test.go` This consists of units test cases to the logic to extract headers from route object and set/delete HTTP request/reponse headers. `pkg/router/template/types.go` This adds two fields HTTPResponseHeaders and HTTPRequestHeaders of type []HTTPHeader in the ServiceAliasConfig which is used in the haproxy-config.template to add the set/delete http-reponse and http-request stanzas for the header values fetched from the route object. This also add a struct called HTTPHeader which helps setting the HTTP response/request values in the http-reponse/http-request stanzas in the haproxy-config.template.
* pkg/router/router_test.go (TestConfigTemplate): Use Fatal, not Fatalf, to print the error message from expectation.Match, which is not expected to be a formatted string.
* pkg/router/router_test.go (TestConfigTemplate): Print the HAProxy config file if the test case fails.
* pkg/router/router_test.go (TestMain): Define some global HTTP request and response headers. (TestConfigTemplate): Add test cases for global and route HTTP request and response headers to verify that the template plugin properly quotes values. (mustCreate): Add godoc comments, and add an httpHeaders field for specifying spec.httpHeaders on the route. (mustCreate): If the route name is empty, don't create a route. Copy httpHeaders from mustCreate to the route's spec.httpHeaders field. (insecureBackendName): New helper, used by TestConfigTemplate.
* pkg/router/template/router.go (configsAreEqual): Add a comment explaining why this function does not check the ServiceUnitNames, ActiveServiceUnits, or ActiveEndpoints fields. * pkg/router/template/router_test.go (Test_configsAreEqual): New test. Verify that configsAreEqual behaves correctly.
/label qe-approved |
/retest |
OK. If you can add them in a google doc and share us the link then that will be great. |
pkg/cmd/infra/router/template.go
Outdated
func checkValidHeaderName(headerName string) error { | ||
// RFC 2616, section 4.2, states that the header name | ||
// must be a valid token. | ||
// Any changes made to regex of header name in route type in openshift/api and `validation.go` file in library-go shall be reflected here and | ||
// vice-versa | ||
permittedHeaderNameRE := regexp.MustCompile("^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$") |
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.
Don't recompile the regexp every time the function is called. Don't use the word "shall". End your sentences with a period. Remember to add godoc.
func checkValidHeaderName(headerName string) error { | |
// RFC 2616, section 4.2, states that the header name | |
// must be a valid token. | |
// Any changes made to regex of header name in route type in openshift/api and `validation.go` file in library-go shall be reflected here and | |
// vice-versa | |
permittedHeaderNameRE := regexp.MustCompile("^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$") | |
// permittedHeaderNameRE is a compiled regexp to match an HTTP header name | |
// as specified in RFC 2616, section 4.2. | |
// Any changes made to regex of header name in route type in openshift/api and `validation.go` file in library-go must be reflected here and | |
// vice versa. | |
var permittedHeaderNameRE = regexp.MustCompile("^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$") | |
// checkValidHeaderName verifies that the given HTTP header name is valid. | |
func checkValidHeaderName(headerName string) error { |
The header name needs to be sanitized as a single quote(') can be provided by a user for a header name which is allowed. However, passing a single quote in the http-request or http-reponse stanza in the haproxy-config causes haproxy to fail with: [ALERT] (78703) : config : Error(s) found in configuration file : ./haproxy.cfg [ALERT] (78703) : config : Fatal errors found in configuration. That is why escape and quote single quote present in a header value. For example: X'-Forwarded-For will get sanitized to 'X'\''-Forwarded-For' using escaping and quoting.
@miheer: all tests passed! Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: candita The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
images/router/haproxy/conf/haproxy-config.template
Sets thehttp-response and http-request stanzas to set or delete custom HTTP
Response/Request headers.
pkg/cmd/infra/router/template.go
This consists the logic to get thevalue from the env var from router deployment and use it for
setting/deleting HTTP response/request headers.
pkg/router/template/plugin.go
Adds new fields in theTemplatePluginConfig struct to set or delete HTTP request/reponse
headers. These are needed to set the values we get from router
deployment env var.
pkg/router/template/router.go
This consists of the logic extractingheader values from the route object and then set/delete
HTTP request/reponse headers.
pkg/router/template/router_test.go
This consists of units test casesto the logic to extract headers from route object and set/delete HTTP
request/reponse headers.
pkg/router/template/types.go
This adds two fields HTTPResponseHeadersand HTTPRequestHeaders of type []HTTPHeader in the ServiceAliasConfig
which is used in the haproxy-config.template to add the set/delete
http-reponse and http-request stanzas for the header values fetched from
the route object.
This also add a struct called HTTPHeader which helps setting the HTTP
response/request values in the http-reponse/http-request stanzas in the
haproxy-config.template.
Jira Number https://issues.redhat.com/browse/NE-982