1
1
package nginx
2
2
3
3
import (
4
+ "fmt"
4
5
"os"
5
6
"regexp"
6
7
"strings"
@@ -97,26 +98,114 @@ func updateDynamicModulesStatus() {
97
98
return
98
99
}
99
100
100
- // Regular expression to find loaded dynamic modules in nginx -T output
101
- // Look for lines like "load_module modules/ngx_http_image_filter_module.so;"
102
- loadModuleRe := regexp .MustCompile (`load_module\s+(?:modules/|/.*/)([a-zA-Z0-9_-]+)\.so;` )
101
+ // Use the shared regex function to find loaded dynamic modules
102
+ loadModuleRe := GetLoadModuleRegex ()
103
103
matches := loadModuleRe .FindAllStringSubmatch (out , - 1 )
104
104
105
105
for _ , match := range matches {
106
106
if len (match ) > 1 {
107
- // Extract the module name without path and suffix
108
- moduleName := match [1 ]
109
- // Some normalization to match format in GetModules
110
- moduleName = strings . TrimPrefix ( moduleName , "ngx_" )
111
- moduleName = strings . TrimSuffix ( moduleName , "_module" )
112
- module , ok := modulesCache .Get (moduleName )
107
+ // Extract the module name from load_module statement and normalize it
108
+ loadModuleName := match [1 ]
109
+ normalizedName := normalizeModuleNameFromLoadModule ( loadModuleName )
110
+
111
+ // Try to find the module in our cache using the normalized name
112
+ module , ok := modulesCache .Get (normalizedName )
113
113
if ok {
114
114
module .Loaded = true
115
115
}
116
116
}
117
117
}
118
118
}
119
119
120
+ // GetLoadModuleRegex returns a compiled regular expression to match nginx load_module statements.
121
+ // It matches both quoted and unquoted module paths:
122
+ // - load_module "/usr/local/nginx/modules/ngx_stream_module.so";
123
+ // - load_module modules/ngx_http_upstream_fair_module.so;
124
+ //
125
+ // The regex captures the module name (without path and extension).
126
+ func GetLoadModuleRegex () * regexp.Regexp {
127
+ // Pattern explanation:
128
+ // load_module\s+ - matches "load_module" followed by whitespace
129
+ // "? - optional opening quote
130
+ // (?:[^"\s]+/)? - non-capturing group for optional path (any non-quote, non-space chars ending with /)
131
+ // ([a-zA-Z0-9_-]+) - capturing group for module name
132
+ // \.so - matches ".so" extension
133
+ // "? - optional closing quote
134
+ // \s*; - optional whitespace followed by semicolon
135
+ return regexp .MustCompile (`load_module\s+"?(?:[^"\s]+/)?([a-zA-Z0-9_-]+)\.so"?\s*;` )
136
+ }
137
+
138
+ // normalizeModuleNameFromLoadModule converts a module name from load_module statement
139
+ // to match the format used in configure arguments.
140
+ // Examples:
141
+ // - "ngx_stream_module" -> "stream"
142
+ // - "ngx_http_geoip_module" -> "http_geoip"
143
+ // - "ngx_stream_geoip_module" -> "stream_geoip"
144
+ // - "ngx_http_image_filter_module" -> "http_image_filter"
145
+ func normalizeModuleNameFromLoadModule (moduleName string ) string {
146
+ // Remove "ngx_" prefix if present
147
+ normalized := strings .TrimPrefix (moduleName , "ngx_" )
148
+
149
+ // Remove "_module" suffix if present
150
+ normalized = strings .TrimSuffix (normalized , "_module" )
151
+
152
+ return normalized
153
+ }
154
+
155
+ // normalizeModuleNameFromConfigure converts a module name from configure arguments
156
+ // to a consistent format for internal use.
157
+ // Examples:
158
+ // - "stream" -> "stream"
159
+ // - "http_geoip_module" -> "http_geoip"
160
+ // - "http_image_filter_module" -> "http_image_filter"
161
+ func normalizeModuleNameFromConfigure (moduleName string ) string {
162
+ // Remove "_module" suffix if present to keep consistent format
163
+ normalized := strings .TrimSuffix (moduleName , "_module" )
164
+
165
+ return normalized
166
+ }
167
+
168
+ // getExpectedLoadModuleName converts a configure argument module name
169
+ // to the expected load_module statement module name.
170
+ // Examples:
171
+ // - "stream" -> "ngx_stream_module"
172
+ // - "http_geoip" -> "ngx_http_geoip_module"
173
+ // - "stream_geoip" -> "ngx_stream_geoip_module"
174
+ func getExpectedLoadModuleName (configureModuleName string ) string {
175
+ normalized := normalizeModuleNameFromConfigure (configureModuleName )
176
+ return "ngx_" + normalized + "_module"
177
+ }
178
+
179
+ // GetModuleMapping returns a map showing the relationship between different module name formats.
180
+ // This is useful for debugging and understanding how module names are processed.
181
+ // Returns a map with normalized names as keys and mapping info as values.
182
+ func GetModuleMapping () map [string ]map [string ]string {
183
+ modules := GetModules ()
184
+ mapping := make (map [string ]map [string ]string )
185
+
186
+ modulesCacheLock .RLock ()
187
+ defer modulesCacheLock .RUnlock ()
188
+
189
+ // Use AllFromFront() to iterate through the ordered map
190
+ for normalizedName , module := range modules .AllFromFront () {
191
+ if module == nil {
192
+ continue
193
+ }
194
+
195
+ expectedLoadName := getExpectedLoadModuleName (normalizedName )
196
+
197
+ mapping [normalizedName ] = map [string ]string {
198
+ "normalized" : normalizedName ,
199
+ "expected_load_module" : expectedLoadName ,
200
+ "dynamic" : fmt .Sprintf ("%t" , module .Dynamic ),
201
+ "loaded" : fmt .Sprintf ("%t" , module .Loaded ),
202
+ "params" : module .Params ,
203
+ }
204
+ }
205
+
206
+ return mapping
207
+ }
208
+
120
209
func GetModules () * orderedmap.OrderedMap [string , * Module ] {
121
210
modulesCacheLock .RLock ()
122
211
cachedModules := modulesCache
@@ -165,6 +254,9 @@ func GetModules() *orderedmap.OrderedMap[string, *Module] {
165
254
continue
166
255
}
167
256
257
+ // Normalize the module name for consistent internal representation
258
+ normalizedModuleName := normalizeModuleNameFromConfigure (module )
259
+
168
260
// Determine if the module is dynamic
169
261
isDynamic := false
170
262
if strings .Contains (out , "--with-" + module + "=dynamic" ) ||
@@ -176,8 +268,8 @@ func GetModules() *orderedmap.OrderedMap[string, *Module] {
176
268
params = ""
177
269
}
178
270
179
- modulesCache .Set (module , & Module {
180
- Name : module ,
271
+ modulesCache .Set (normalizedModuleName , & Module {
272
+ Name : normalizedModuleName ,
181
273
Params : params ,
182
274
Dynamic : isDynamic ,
183
275
Loaded : ! isDynamic , // Static modules are always loaded
0 commit comments