11package config
22
33import (
4- "encoding/json"
54 "fmt"
5+ "regexp"
6+ "strconv"
67 "strings"
78 gotemplate "text/template"
89
@@ -38,58 +39,82 @@ var baseHeaders = []http.Header{
3839 },
3940}
4041
41- func executeServers (conf dataplane.Configuration ) [] byte {
42- servers := createServers (conf .HTTPServers , conf .SSLServers )
42+ func executeServers (conf dataplane.Configuration ) ([]http. Server , map [ string ][]http. RouteMatch ) {
43+ servers , httpMatchPairs := createServers (conf .HTTPServers , conf .SSLServers )
4344
44- return execute ( serversTemplate , servers )
45+ return servers , httpMatchPairs
4546}
4647
47- func createServers (httpServers , sslServers []dataplane.VirtualServer ) []http.Server {
48+ func createServers (httpServers , sslServers []dataplane.VirtualServer ) (
49+ []http.Server ,
50+ map [string ][]http.RouteMatch ,
51+ ) {
4852 servers := make ([]http.Server , 0 , len (httpServers )+ len (sslServers ))
53+ finalMatchPairs := make (map [string ][]http.RouteMatch )
4954
5055 for _ , s := range httpServers {
51- servers = append (servers , createServer (s ))
56+ httpServer , matchPair := createServer (s )
57+ servers = append (servers , httpServer )
58+
59+ for key , val := range matchPair {
60+ finalMatchPairs [key ] = val
61+ }
5262 }
5363
5464 for _ , s := range sslServers {
55- servers = append (servers , createSSLServer (s ))
65+ sslServer , matchPair := createSSLServer (s )
66+ servers = append (servers , sslServer )
67+
68+ for key , val := range matchPair {
69+ finalMatchPairs [key ] = val
70+ }
5671 }
5772
58- return servers
73+ return servers , finalMatchPairs
5974}
6075
61- func createSSLServer (virtualServer dataplane.VirtualServer ) http.Server {
76+ func createSSLServer (virtualServer dataplane.VirtualServer ) (
77+ http.Server ,
78+ map [string ][]http.RouteMatch ,
79+ ) {
6280 if virtualServer .IsDefault {
6381 return http.Server {
6482 IsDefaultSSL : true ,
6583 Port : virtualServer .Port ,
66- }
84+ }, nil
6785 }
6886
87+ locs , matchPairs := createLocations (virtualServer )
88+
6989 return http.Server {
7090 ServerName : virtualServer .Hostname ,
7191 SSL : & http.SSL {
7292 Certificate : generatePEMFileName (virtualServer .SSL .KeyPairID ),
7393 CertificateKey : generatePEMFileName (virtualServer .SSL .KeyPairID ),
7494 },
75- Locations : createLocations ( virtualServer . PathRules , virtualServer . Port ) ,
95+ Locations : locs ,
7696 Port : virtualServer .Port ,
77- }
97+ }, matchPairs
7898}
7999
80- func createServer (virtualServer dataplane.VirtualServer ) http.Server {
100+ func createServer (virtualServer dataplane.VirtualServer ) (
101+ http.Server ,
102+ map [string ][]http.RouteMatch ,
103+ ) {
81104 if virtualServer .IsDefault {
82105 return http.Server {
83106 IsDefaultHTTP : true ,
84107 Port : virtualServer .Port ,
85- }
108+ }, nil
86109 }
87110
111+ locs , matchPairs := createLocations (virtualServer )
112+
88113 return http.Server {
89114 ServerName : virtualServer .Hostname ,
90- Locations : createLocations ( virtualServer . PathRules , virtualServer . Port ) ,
115+ Locations : locs ,
91116 Port : virtualServer .Port ,
92- }
117+ }, matchPairs
93118}
94119
95120// rewriteConfig contains the configuration for a location to rewrite paths,
@@ -99,13 +124,19 @@ type rewriteConfig struct {
99124 Rewrite string
100125}
101126
102- func createLocations (pathRules []dataplane.PathRule , listenerPort int32 ) []http.Location {
103- maxLocs , pathsAndTypes := getMaxLocationCountAndPathMap (pathRules )
127+ type httpMatchPairs map [string ][]http.RouteMatch
128+
129+ func createLocations (server dataplane.VirtualServer ) (
130+ []http.Location ,
131+ map [string ][]http.RouteMatch ,
132+ ) {
133+ maxLocs , pathsAndTypes := getMaxLocationCountAndPathMap (server .PathRules )
104134 locs := make ([]http.Location , 0 , maxLocs )
135+ matchPairs := make (httpMatchPairs )
105136 var rootPathExists bool
106137
107- for pathRuleIdx , rule := range pathRules {
108- matches := make ([]httpMatch , 0 , len (rule .MatchRules ))
138+ for pathRuleIdx , rule := range server . PathRules {
139+ matches := make ([]http. RouteMatch , 0 , len (rule .MatchRules ))
109140
110141 if rule .Path == rootPath {
111142 rootPathExists = true
@@ -121,14 +152,15 @@ func createLocations(pathRules []dataplane.PathRule, listenerPort int32) []http.
121152 matches = append (matches , match )
122153 }
123154
124- buildLocations = updateLocationsForFilters (r .Filters , buildLocations , r , listenerPort , rule .Path )
155+ buildLocations = updateLocationsForFilters (r .Filters , buildLocations , r , server . Port , rule .Path )
125156 locs = append (locs , buildLocations ... )
126157 }
127158
128159 if len (matches ) > 0 {
129- matchesStr := convertMatchesToString (matches )
130160 for i := range extLocations {
131- extLocations [i ].HTTPMatchVar = matchesStr
161+ key := server .Hostname + extLocations [i ].Path + strconv .Itoa (int (server .Port ))
162+ extLocations [i ].HTTPMatchKey = sanitizeKey (key )
163+ matchPairs [extLocations [i ].HTTPMatchKey ] = matches
132164 }
133165 locs = append (locs , extLocations ... )
134166 }
@@ -138,7 +170,15 @@ func createLocations(pathRules []dataplane.PathRule, listenerPort int32) []http.
138170 locs = append (locs , createDefaultRootLocation ())
139171 }
140172
141- return locs
173+ return locs , matchPairs
174+ }
175+
176+ // removeSpecialCharacters removes / and . from key to
177+ // avoid compilation issues with NJS.
178+ func sanitizeKey (input string ) string {
179+ pattern := "[./]"
180+ regex := regexp .MustCompile (pattern )
181+ return regex .ReplaceAllString (input , "" )
142182}
143183
144184// pathAndTypeMap contains a map of paths and any path types defined for that path
@@ -217,9 +257,9 @@ func initializeInternalLocation(
217257 pathruleIdx ,
218258 matchRuleIdx int ,
219259 match dataplane.Match ,
220- ) (http.Location , httpMatch ) {
260+ ) (http.Location , http. RouteMatch ) {
221261 path := fmt .Sprintf ("@rule%d-route%d" , pathruleIdx , matchRuleIdx )
222- return createMatchLocation (path ), createHTTPMatch (match , path )
262+ return createMatchLocation (path ), createRouteMatch (match , path )
223263}
224264
225265// updateLocationsForFilters updates the existing locations with any relevant filters.
@@ -392,26 +432,8 @@ func createRewritesValForRewriteFilter(filter *dataplane.HTTPURLRewriteFilter, p
392432 return rewrites
393433}
394434
395- // httpMatch is an internal representation of an HTTPRouteMatch.
396- // This struct is marshaled into a string and stored as a variable in the nginx location block for the route's path.
397- // The NJS httpmatches module will look up this variable on the request object and compare the request against the
398- // Method, Headers, and QueryParams contained in httpMatch.
399- // If the request satisfies the httpMatch, NGINX will redirect the request to the location RedirectPath.
400- type httpMatch struct {
401- // Method is the HTTPMethod of the HTTPRouteMatch.
402- Method string `json:"method,omitempty"`
403- // RedirectPath is the path to redirect the request to if the request satisfies the match conditions.
404- RedirectPath string `json:"redirectPath,omitempty"`
405- // Headers is a list of HTTPHeaders name value pairs with the format "{name}:{value}".
406- Headers []string `json:"headers,omitempty"`
407- // QueryParams is a list of HTTPQueryParams name value pairs with the format "{name}={value}".
408- QueryParams []string `json:"params,omitempty"`
409- // Any represents a match with no match conditions.
410- Any bool `json:"any,omitempty"`
411- }
412-
413- func createHTTPMatch (match dataplane.Match , redirectPath string ) httpMatch {
414- hm := httpMatch {
435+ func createRouteMatch (match dataplane.Match , redirectPath string ) http.RouteMatch {
436+ hm := http.RouteMatch {
415437 RedirectPath : redirectPath ,
416438 }
417439
@@ -558,19 +580,6 @@ func convertSetHeaders(headers []dataplane.HTTPHeader) []http.Header {
558580 return locHeaders
559581}
560582
561- func convertMatchesToString (matches []httpMatch ) string {
562- // FIXME(sberman): De-dupe matches and associated locations
563- // so we don't need nginx/njs to perform unnecessary matching.
564- // https://github.com/nginxinc/nginx-gateway-fabric/issues/662
565- b , err := json .Marshal (matches )
566- if err != nil {
567- // panic is safe here because we should never fail to marshal the match unless we constructed it incorrectly.
568- panic (fmt .Errorf ("could not marshal http match: %w" , err ))
569- }
570-
571- return string (b )
572- }
573-
574583func exactPath (path string ) string {
575584 return fmt .Sprintf ("= %s" , path )
576585}
0 commit comments