func patchHTTPRoutes()

in pilot/pkg/networking/core/v1alpha3/envoyfilter/rc_patch.go [150:240]


func patchHTTPRoutes(patchContext networking.EnvoyFilter_PatchContext,
	patches map[networking.EnvoyFilter_ApplyTo][]*model.EnvoyFilterConfigPatchWrapper,
	routeConfiguration *route.RouteConfiguration, virtualHost *route.VirtualHost, portMap model.GatewayPortMap) {
	routesRemoved := false
	// Apply the route level removes/merges if any.
	for index := range virtualHost.Routes {
		patchHTTPRoute(patchContext, patches, routeConfiguration, virtualHost, index, &routesRemoved, portMap)
	}

	// now for the adds
	for _, rp := range patches[networking.EnvoyFilter_HTTP_ROUTE] {
		applied := false
		if !commonConditionMatch(patchContext, rp) ||
			!routeConfigurationMatch(patchContext, routeConfiguration, rp, portMap) ||
			!virtualHostMatch(virtualHost, rp) {
			IncrementEnvoyFilterMetric(rp.Key(), Route, applied)
			continue
		}
		if rp.Operation == networking.EnvoyFilter_Patch_ADD {
			virtualHost.Routes = append(virtualHost.Routes, proto.Clone(rp.Value).(*route.Route))
			applied = true
		} else if rp.Operation == networking.EnvoyFilter_Patch_INSERT_AFTER {
			// Insert after without a route match is same as ADD in the end
			if !hasRouteMatch(rp) {
				virtualHost.Routes = append(virtualHost.Routes, proto.Clone(rp.Value).(*route.Route))
				continue
			}
			// find the matching route first
			insertPosition := -1
			for i := 0; i < len(virtualHost.Routes); i++ {
				if routeMatch(virtualHost.Routes[i], rp) {
					insertPosition = i + 1
					break
				}
			}

			if insertPosition == -1 {
				continue
			}
			applied = true
			clonedVal := proto.Clone(rp.Value).(*route.Route)
			virtualHost.Routes = append(virtualHost.Routes, clonedVal)
			if insertPosition < len(virtualHost.Routes)-1 {
				copy(virtualHost.Routes[insertPosition+1:], virtualHost.Routes[insertPosition:])
				virtualHost.Routes[insertPosition] = clonedVal
			}
		} else if rp.Operation == networking.EnvoyFilter_Patch_INSERT_BEFORE || rp.Operation == networking.EnvoyFilter_Patch_INSERT_FIRST {
			// insert before/first without a route match is same as insert in the beginning
			if !hasRouteMatch(rp) {
				virtualHost.Routes = append([]*route.Route{proto.Clone(rp.Value).(*route.Route)}, virtualHost.Routes...)
				continue
			}
			// find the matching route first
			insertPosition := -1
			for i := 0; i < len(virtualHost.Routes); i++ {
				if routeMatch(virtualHost.Routes[i], rp) {
					insertPosition = i
					break
				}
			}

			// If matching route is not found, then don't insert and continue.
			if insertPosition == -1 {
				continue
			}

			applied = true

			// In case of INSERT_FIRST, if a match is found, still insert it at the top of the routes.
			if rp.Operation == networking.EnvoyFilter_Patch_INSERT_FIRST {
				insertPosition = 0
			}

			clonedVal := proto.Clone(rp.Value).(*route.Route)
			virtualHost.Routes = append(virtualHost.Routes, clonedVal)
			copy(virtualHost.Routes[insertPosition+1:], virtualHost.Routes[insertPosition:])
			virtualHost.Routes[insertPosition] = clonedVal
		}
		IncrementEnvoyFilterMetric(rp.Key(), Route, applied)
	}
	if routesRemoved {
		trimmedRoutes := make([]*route.Route, 0, len(virtualHost.Routes))
		for i := range virtualHost.Routes {
			if virtualHost.Routes[i] == nil {
				continue
			}
			trimmedRoutes = append(trimmedRoutes, virtualHost.Routes[i])
		}
		virtualHost.Routes = trimmedRoutes
	}
}