in src/go/configinfo/service_info.go [417:505]
func (s *ServiceInfo) processHttpRule() error {
// An temporary map to record added route match with Options set,
// to avoid duplication.
addedRouteMatchWithOptionsSet := make(map[string]bool)
for _, rule := range s.ServiceConfig().GetHttp().GetRules() {
selector := rule.GetSelector()
if s.shouldSkipDiscoveryAPI(selector) {
glog.Warningf("Skip http rule %q because discovery API is not supported.", selector)
continue
}
method := s.Methods[selector]
if method == nil {
continue
}
if err := s.addHttpRule(method, rule, addedRouteMatchWithOptionsSet, s.Options.DisallowColonInWildcardPathSegment); err != nil {
return err
}
// additional_bindings cannot be nested inside themselves according to
// https://aip.dev/127. Service Management will enforce this restriction
// when interpret the httprules from the descriptor. Therefore, no need to
// check for nested additional_bindings.
for _, additionalRule := range rule.AdditionalBindings {
if err := s.addHttpRule(method, additionalRule, addedRouteMatchWithOptionsSet, s.Options.DisallowColonInWildcardPathSegment); err != nil {
return err
}
}
}
// In order to support CORS. HTTP method OPTIONS needs to be added to all
// urls except the ones already with options.
if s.AllowCors {
for _, r := range s.ServiceConfig().GetHttp().GetRules() {
method := s.Methods[r.GetSelector()]
if method == nil {
continue
}
for _, httpRule := range method.HttpRule {
if httpRule.HttpMethod != util.OPTIONS {
uriTemplate, err := httppattern.ParseUriTemplate(httpRule.UriTemplate.Origin)
if err != nil {
return fmt.Errorf("error parsing URI template for http rule for operation (%v): %v", r.Selector, err)
}
newHttpRule := &httppattern.Pattern{
HttpMethod: util.OPTIONS,
UriTemplate: uriTemplate,
}
routeMatch := httpRule.UriTemplate.Regex(s.Options.DisallowColonInWildcardPathSegment)
if _, exist := addedRouteMatchWithOptionsSet[routeMatch]; !exist {
if err := s.addOptionMethod(method, newHttpRule); err != nil {
return fmt.Errorf("error adding auto-generated CORS http rule for operation (%v): %v", r.Selector, err)
}
addedRouteMatchWithOptionsSet[routeMatch] = true
}
}
}
}
}
// Add HttpRule for HealthCheck method
if s.Options.Healthz != "" {
methodName := fmt.Sprintf("%s.%s_HealthCheck", s.Options.HealthCheckOperation, s.Options.HealthCheckAutogeneratedOperationPrefix)
hcMethod, err := s.getOrCreateMethod(methodName)
if err != nil {
return fmt.Errorf("error creating auto-generated HealthCheck http rule for operation (%v): %v", methodName, err)
}
if !strings.HasPrefix(s.Options.Healthz, "/") {
s.Options.Healthz = fmt.Sprintf("/%s", s.Options.Healthz)
}
uriTemplate, _ := httppattern.ParseUriTemplate(s.Options.Healthz)
hcMethod.HttpRule = append(hcMethod.HttpRule, &httppattern.Pattern{
UriTemplate: uriTemplate,
HttpMethod: util.GET,
})
hcMethod.SkipServiceControl = true
hcMethod.IsGenerated = true
}
return nil
}