1
1
package config
2
2
3
3
import (
4
- "encoding/json"
5
4
"fmt"
5
+ "regexp"
6
+ "strconv"
6
7
"strings"
7
8
gotemplate "text/template"
8
9
@@ -38,58 +39,82 @@ var baseHeaders = []http.Header{
38
39
},
39
40
}
40
41
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 )
43
44
44
- return execute ( serversTemplate , servers )
45
+ return servers , httpMatchPairs
45
46
}
46
47
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
+ ) {
48
52
servers := make ([]http.Server , 0 , len (httpServers )+ len (sslServers ))
53
+ finalMatchPairs := make (map [string ][]http.RouteMatch )
49
54
50
55
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
+ }
52
62
}
53
63
54
64
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
+ }
56
71
}
57
72
58
- return servers
73
+ return servers , finalMatchPairs
59
74
}
60
75
61
- func createSSLServer (virtualServer dataplane.VirtualServer ) http.Server {
76
+ func createSSLServer (virtualServer dataplane.VirtualServer ) (
77
+ http.Server ,
78
+ map [string ][]http.RouteMatch ,
79
+ ) {
62
80
if virtualServer .IsDefault {
63
81
return http.Server {
64
82
IsDefaultSSL : true ,
65
83
Port : virtualServer .Port ,
66
- }
84
+ }, nil
67
85
}
68
86
87
+ locs , matchPairs := createLocations (virtualServer )
88
+
69
89
return http.Server {
70
90
ServerName : virtualServer .Hostname ,
71
91
SSL : & http.SSL {
72
92
Certificate : generatePEMFileName (virtualServer .SSL .KeyPairID ),
73
93
CertificateKey : generatePEMFileName (virtualServer .SSL .KeyPairID ),
74
94
},
75
- Locations : createLocations ( virtualServer . PathRules , virtualServer . Port ) ,
95
+ Locations : locs ,
76
96
Port : virtualServer .Port ,
77
- }
97
+ }, matchPairs
78
98
}
79
99
80
- func createServer (virtualServer dataplane.VirtualServer ) http.Server {
100
+ func createServer (virtualServer dataplane.VirtualServer ) (
101
+ http.Server ,
102
+ map [string ][]http.RouteMatch ,
103
+ ) {
81
104
if virtualServer .IsDefault {
82
105
return http.Server {
83
106
IsDefaultHTTP : true ,
84
107
Port : virtualServer .Port ,
85
- }
108
+ }, nil
86
109
}
87
110
111
+ locs , matchPairs := createLocations (virtualServer )
112
+
88
113
return http.Server {
89
114
ServerName : virtualServer .Hostname ,
90
- Locations : createLocations ( virtualServer . PathRules , virtualServer . Port ) ,
115
+ Locations : locs ,
91
116
Port : virtualServer .Port ,
92
- }
117
+ }, matchPairs
93
118
}
94
119
95
120
// rewriteConfig contains the configuration for a location to rewrite paths,
@@ -99,13 +124,19 @@ type rewriteConfig struct {
99
124
Rewrite string
100
125
}
101
126
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 )
104
134
locs := make ([]http.Location , 0 , maxLocs )
135
+ matchPairs := make (httpMatchPairs )
105
136
var rootPathExists bool
106
137
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 ))
109
140
110
141
if rule .Path == rootPath {
111
142
rootPathExists = true
@@ -121,14 +152,15 @@ func createLocations(pathRules []dataplane.PathRule, listenerPort int32) []http.
121
152
matches = append (matches , match )
122
153
}
123
154
124
- buildLocations = updateLocationsForFilters (r .Filters , buildLocations , r , listenerPort , rule .Path )
155
+ buildLocations = updateLocationsForFilters (r .Filters , buildLocations , r , server . Port , rule .Path )
125
156
locs = append (locs , buildLocations ... )
126
157
}
127
158
128
159
if len (matches ) > 0 {
129
- matchesStr := convertMatchesToString (matches )
130
160
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
132
164
}
133
165
locs = append (locs , extLocations ... )
134
166
}
@@ -138,7 +170,14 @@ func createLocations(pathRules []dataplane.PathRule, listenerPort int32) []http.
138
170
locs = append (locs , createDefaultRootLocation ())
139
171
}
140
172
141
- return locs
173
+ return locs , matchPairs
174
+ }
175
+
176
+ // removeSpecialCharacters removes '/', '.' from key and replaces '= ' with 'EXACT',
177
+ // to avoid compilation issues with NJS and NGINX Conf.
178
+ func sanitizeKey (input string ) string {
179
+ s := regexp .MustCompile ("[./]" ).ReplaceAllString (input , "" )
180
+ return regexp .MustCompile ("= " ).ReplaceAllString (s , "EXACT" )
142
181
}
143
182
144
183
// pathAndTypeMap contains a map of paths and any path types defined for that path
@@ -217,9 +256,9 @@ func initializeInternalLocation(
217
256
pathruleIdx ,
218
257
matchRuleIdx int ,
219
258
match dataplane.Match ,
220
- ) (http.Location , httpMatch ) {
259
+ ) (http.Location , http. RouteMatch ) {
221
260
path := fmt .Sprintf ("@rule%d-route%d" , pathruleIdx , matchRuleIdx )
222
- return createMatchLocation (path ), createHTTPMatch (match , path )
261
+ return createMatchLocation (path ), createRouteMatch (match , path )
223
262
}
224
263
225
264
// updateLocationsForFilters updates the existing locations with any relevant filters.
@@ -392,26 +431,8 @@ func createRewritesValForRewriteFilter(filter *dataplane.HTTPURLRewriteFilter, p
392
431
return rewrites
393
432
}
394
433
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 {
434
+ func createRouteMatch (match dataplane.Match , redirectPath string ) http.RouteMatch {
435
+ hm := http.RouteMatch {
415
436
RedirectPath : redirectPath ,
416
437
}
417
438
@@ -558,19 +579,6 @@ func convertSetHeaders(headers []dataplane.HTTPHeader) []http.Header {
558
579
return locHeaders
559
580
}
560
581
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
-
574
582
func exactPath (path string ) string {
575
583
return fmt .Sprintf ("= %s" , path )
576
584
}
0 commit comments