1// Copyright 2020 Istio Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package validation 16 17import ( 18 "errors" 19 "fmt" 20 21 networking "istio.io/api/networking/v1alpha3" 22) 23 24func validateRootHTTPRoute(http *networking.HTTPRoute) (errs error) { 25 if http.Delegate == nil { 26 errs = appendErrors(errs, fmt.Errorf("root HTTP route %s must specify delegate", http.Name)) 27 } 28 // only delegate can be specified 29 if http.Redirect != nil { 30 errs = appendErrors(errs, fmt.Errorf("root HTTP route %s must not specify rewrite", http.Name)) 31 } 32 if http.Route != nil { 33 errs = appendErrors(errs, fmt.Errorf("root HTTP route %s must not specify route", http.Name)) 34 } 35 36 errs = appendErrors(errs, validateChainingHTTPRoute(http)) 37 return 38} 39 40func validateDelegateHTTPRoute(http *networking.HTTPRoute) (errs error) { 41 if http.Delegate != nil { 42 errs = appendErrors(errs, errors.New("delegate HTTP route cannot contain delegate")) 43 } 44 // check for conflicts 45 if http.Redirect != nil { 46 if len(http.Route) > 0 { 47 errs = appendErrors(errs, errors.New("HTTP route cannot contain both route and redirect")) 48 } 49 } else if len(http.Route) == 0 { 50 errs = appendErrors(errs, errors.New("HTTP route or redirect is required")) 51 } 52 errs = appendErrors(errs, validateChainingHTTPRoute(http)) 53 return 54} 55 56// TODO(@hzxuzhonghu): deduplicate with validateHTTPRoute 57func validateChainingHTTPRoute(http *networking.HTTPRoute) (errs error) { 58 // check for conflicts 59 if http.Redirect != nil { 60 if http.Fault != nil { 61 errs = appendErrors(errs, errors.New("HTTP route cannot contain both fault and redirect")) 62 } 63 64 if http.Rewrite != nil { 65 errs = appendErrors(errs, errors.New("HTTP route rule cannot contain both rewrite and redirect")) 66 } 67 } 68 // header manipulation 69 for name := range http.Headers.GetRequest().GetAdd() { 70 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 71 } 72 for name := range http.Headers.GetRequest().GetSet() { 73 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 74 } 75 for _, name := range http.Headers.GetRequest().GetRemove() { 76 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 77 } 78 for name := range http.Headers.GetResponse().GetAdd() { 79 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 80 } 81 for name := range http.Headers.GetResponse().GetSet() { 82 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 83 } 84 for _, name := range http.Headers.GetResponse().GetRemove() { 85 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 86 } 87 88 errs = appendErrors(errs, validateCORSPolicy(http.CorsPolicy)) 89 errs = appendErrors(errs, validateHTTPFaultInjection(http.Fault)) 90 91 for _, match := range http.Match { 92 if match != nil { 93 if containRegexMatch(match.Uri) { 94 errs = appendErrors(errs, errors.New("url match does not support regex match for delegating")) 95 } 96 if containRegexMatch(match.Scheme) { 97 errs = appendErrors(errs, errors.New("scheme match does not support regex match for delegating")) 98 } 99 if containRegexMatch(match.Method) { 100 errs = appendErrors(errs, errors.New("method match does not support regex match for delegating")) 101 } 102 if containRegexMatch(match.Authority) { 103 errs = appendErrors(errs, errors.New("authority match does not support regex match for delegating")) 104 } 105 106 for name, header := range match.Headers { 107 if header == nil { 108 errs = appendErrors(errs, fmt.Errorf("header match %v cannot be null", name)) 109 } 110 if containRegexMatch(header) { 111 errs = appendErrors(errs, fmt.Errorf("header match %v does not support regex match for delegating", name)) 112 } 113 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 114 } 115 for name, param := range match.QueryParams { 116 if param == nil { 117 errs = appendErrors(errs, fmt.Errorf("query param match %v cannot be null", name)) 118 } 119 if containRegexMatch(param) { 120 errs = appendErrors(errs, fmt.Errorf("query param match %v does not support regex match for delegating", name)) 121 } 122 } 123 for name, header := range match.WithoutHeaders { 124 if header == nil { 125 errs = appendErrors(errs, fmt.Errorf("withoutHeaders match %v cannot be null", name)) 126 } 127 if containRegexMatch(header) { 128 errs = appendErrors(errs, fmt.Errorf("withoutHeaders match %v does not support regex match for delegating", name)) 129 } 130 errs = appendErrors(errs, ValidateHTTPHeaderName(name)) 131 } 132 133 if match.Port != 0 { 134 errs = appendErrors(errs, ValidatePort(int(match.Port))) 135 } 136 137 // delegate only applies to gateway, so sourceLabels or sourceNamespace does not apply. 138 if len(match.SourceLabels) != 0 { 139 errs = appendErrors(errs, fmt.Errorf("sourceLabels match can not specify on delegate")) 140 } 141 if match.SourceNamespace != "" { 142 errs = appendErrors(errs, fmt.Errorf("sourceNamespace match can not specify on delegate")) 143 } 144 if len(match.Gateways) != 0 { 145 errs = appendErrors(errs, fmt.Errorf("gateways match can not specify on delegate")) 146 } 147 } 148 } 149 150 if http.MirrorPercent != nil { 151 if value := http.MirrorPercent.GetValue(); value > 100 { 152 errs = appendErrors(errs, fmt.Errorf("mirror_percent must have a max value of 100 (it has %d)", value)) 153 } 154 } 155 156 if http.MirrorPercentage != nil { 157 if value := http.MirrorPercentage.GetValue(); value > 100 { 158 errs = appendErrors(errs, fmt.Errorf("mirror_percentage must have a max value of 100 (it has %f)", value)) 159 } 160 } 161 162 errs = appendErrors(errs, validateDestination(http.Mirror)) 163 errs = appendErrors(errs, validateHTTPRedirect(http.Redirect)) 164 errs = appendErrors(errs, validateHTTPRetry(http.Retries)) 165 errs = appendErrors(errs, validateHTTPRewrite(http.Rewrite)) 166 errs = appendErrors(errs, validateHTTPRouteDestinations(http.Route)) 167 if http.Timeout != nil { 168 errs = appendErrors(errs, ValidateDurationGogo(http.Timeout)) 169 } 170 171 return 172} 173 174func containRegexMatch(config *networking.StringMatch) bool { 175 if config == nil { 176 return false 177 } 178 if config.GetRegex() != "" { 179 return true 180 } 181 return false 182} 183