@@ -48,6 +48,8 @@ static void *ngx_http_security_headers_create_loc_conf(ngx_conf_t *cf);
4848static char * ngx_http_security_headers_merge_loc_conf (ngx_conf_t * cf ,
4949 void * parent , void * child );
5050static ngx_int_t ngx_http_security_headers_init (ngx_conf_t * cf );
51+ static ngx_int_t ngx_set_headers_out_by_search (ngx_http_request_t * r ,
52+ ngx_str_t * key , ngx_str_t * value );
5153
5254ngx_str_t ngx_http_security_headers_default_nosniff_types [] = {
5355 ngx_string ("text/css" ),
@@ -125,17 +127,16 @@ ngx_module_t ngx_http_security_headers_module = {
125127
126128static ngx_http_output_header_filter_pt ngx_http_next_header_filter ;
127129
128-
129130/* header filter handler */
130131
131132static ngx_int_t
132133ngx_http_security_headers_filter (ngx_http_request_t * r )
133134{
134- ngx_table_elt_t * h_x_cto ;
135- ngx_table_elt_t * h_x_xss ;
136- ngx_table_elt_t * h_x_fo ;
137135 ngx_http_security_headers_loc_conf_t * slcf ;
138- ngx_uint_t i ;
136+
137+ ngx_str_t key ;
138+ ngx_str_t val ;
139+
139140
140141 slcf = ngx_http_get_module_loc_conf (r , ngx_http_security_headers_module );
141142
@@ -147,54 +148,46 @@ ngx_http_security_headers_filter(ngx_http_request_t *r)
147148 if (r -> headers_out .status == NGX_HTTP_OK
148149 && ngx_http_test_content_type (r , & slcf -> nosniff_types ) != NULL )
149150 {
150- h_x_cto = ngx_list_push (& r -> headers_out .headers );
151- if (h_x_cto == NULL ) {
152- return NGX_ERROR ;
153- }
151+ ngx_str_set (& key , "X-Content-Type-Options" );
152+ ngx_str_set (& val , "nosniff" );
154153
155- h_x_cto -> hash = 1 ;
156- ngx_str_set (& h_x_cto -> key , "X-Content-Type-Options" );
157- ngx_str_set (& h_x_cto -> value , "nosniff" );
154+ ngx_set_headers_out_by_search (r , & key , & val );
158155 }
159156
160157 /* Add X-XSS-Protection */
161158 if (r -> headers_out .status != NGX_HTTP_NOT_MODIFIED
162159 && NGX_HTTP_SECURITY_HEADER_OMIT != slcf -> xss )
163160 {
164- h_x_xss = ngx_list_push (& r -> headers_out .headers );
165- if (h_x_xss == NULL ) {
166- return NGX_ERROR ;
167- }
168-
169- h_x_xss -> hash = 1 ;
170- ngx_str_set (& h_x_xss -> key , "X-XSS-Protection" );
161+ ngx_str_set (& key , "X-XSS-Protection" );
171162 if (NGX_HTTP_XSS_HEADER_ON == slcf -> xss ) {
172- ngx_str_set (& h_x_xss -> value , "1" );
163+ ngx_str_set (& val , "1" );
173164 } else if (NGX_HTTP_XSS_HEADER_BLOCK == slcf -> xss ) {
174- ngx_str_set (& h_x_xss -> value , "1; mode=block" );
165+ ngx_str_set (& val , "1; mode=block" );
175166 } else if (NGX_HTTP_XSS_HEADER_OFF == slcf -> xss ) {
176- ngx_str_set (& h_x_xss -> value , "0" );
167+ ngx_str_set (& val , "0" );
177168 }
169+ ngx_set_headers_out_by_search (r , & key , & val );
178170 }
179171
180- /* Add X-Frame-Options */
172+ /* Add X-Frame-Options */
181173 if (r -> headers_out .status != NGX_HTTP_NOT_MODIFIED
182174 && NGX_HTTP_SECURITY_HEADER_OMIT != slcf -> fo )
183175 {
184- h_x_fo = ngx_list_push (& r -> headers_out .headers );
185- if (h_x_fo == NULL ) {
186- return NGX_ERROR ;
187- }
188-
189- h_x_fo -> hash = 1 ;
190- ngx_str_set (& h_x_fo -> key , "X-Frame-Options" );
176+ ngx_str_set (& key , "X-Frame-Options" );
191177 if (NGX_HTTP_FO_HEADER_SAME == slcf -> fo ) {
192- ngx_str_set (& h_x_fo -> value , "SAMEORIGIN" );
178+ ngx_str_set (& val , "SAMEORIGIN" );
193179 } else if (NGX_HTTP_FO_HEADER_DENY == slcf -> fo ) {
194- ngx_str_set (& h_x_fo -> value , "DENY" );
180+ ngx_str_set (& val , "DENY" );
195181 }
182+ ngx_set_headers_out_by_search (r , & key , & val );
196183 }
197184
185+ /* Find X-Powered-By header */
186+ ngx_str_set (& key , "x-powered-by" );
187+ ngx_str_set (& val , "" );
188+ ngx_set_headers_out_by_search (r , & key , & val );
189+
190+
198191 /* Deal with Server header */
199192 ngx_table_elt_t * h_server ;
200193 h_server = r -> headers_out .server ;
@@ -203,43 +196,11 @@ ngx_http_security_headers_filter(ngx_http_request_t *r)
203196 if (h_server == NULL ) {
204197 return NGX_ERROR ;
205198 }
206- /*
207- * h->key.data = (u_char *) "Server";
208- * h->key.len = sizeof("Server") - 1;
209- * h->value.data = (u_char *) "";
210- * h->value.len = sizeof("") - 1;
211- */
212-
199+ h_server -> value .len = 0 ;
200+ h_server -> value .data = (u_char * ) "" ;
201+ h_server -> hash = 0 ;
213202 r -> headers_out .server = h_server ;
214203 }
215- h_server -> hash = 0 ;
216-
217- /* Find X-Powered-By header */
218- ngx_list_part_t * part = NULL ;
219- ngx_table_elt_t * header = NULL ;
220-
221- part = & r -> headers_out .headers .part ;
222- header = part -> elts ;
223- for ( i = 0 ; ; i ++ ) {
224- if (i >= part -> nelts ) {
225- if (part -> next == NULL ) {
226- break ;
227- }
228-
229- part = part -> next ;
230- header = part -> elts ;
231- i = 0 ;
232- }
233- if (header [i ].hash == 0 ) {
234- continue ;
235- }
236- if (ngx_strcasecmp (header [i ].key .data ,
237- (u_char * )"x-powered-by" ) == 0 )
238- {
239- header [i ].hash = 0 ;
240- break ;
241- }
242- }
243204
244205 /* proceed to the next handler in chain */
245206
@@ -259,7 +220,7 @@ ngx_http_security_headers_create_loc_conf(ngx_conf_t *cf)
259220
260221 conf -> xss = NGX_CONF_UNSET_UINT ;
261222 conf -> fo = NGX_CONF_UNSET_UINT ;
262- conf -> enable = NGX_CONF_UNSET_UINT ;
223+ conf -> enable = NGX_CONF_UNSET ;
263224
264225 return conf ;
265226}
@@ -300,4 +261,76 @@ ngx_http_security_headers_init(ngx_conf_t *cf)
300261 ngx_http_top_header_filter = ngx_http_security_headers_filter ;
301262
302263 return NGX_OK ;
303- }
264+ }
265+
266+ static ngx_int_t
267+ ngx_set_headers_out_by_search (ngx_http_request_t * r ,
268+ ngx_str_t * key , ngx_str_t * value )
269+ {
270+ ngx_list_part_t * part ;
271+ ngx_table_elt_t * hi ;
272+ ngx_uint_t i ;
273+ ngx_table_elt_t * h = NULL ;
274+
275+ /*
276+ Get the first part of the list. There is usual only one part.
277+ */
278+ part = & r -> headers_out .headers .part ;
279+ hi = part -> elts ;
280+
281+ /*
282+ Headers list array may consist of more than one part,
283+ so loop through all of it
284+ */
285+ for (i = 0 ; /* void */ ; i ++ ) {
286+ if (i >= part -> nelts ) {
287+ if (part -> next == NULL ) {
288+ /* The last part, search is done. */
289+ break ;
290+ }
291+
292+ part = part -> next ;
293+ hi = part -> elts ;
294+ i = 0 ;
295+ }
296+
297+ if (hi [i ].hash == 0 ) {
298+ continue ;
299+ }
300+
301+ /*
302+ Just compare the lengths and then the names case insensitively.
303+ */
304+ if (key -> len != hi [i ].key .len
305+ || ngx_strcasecmp (key -> data , hi [i ].key .data ) != 0 )
306+ {
307+ /* This header doesn't match. */
308+ continue ;
309+ }
310+
311+ h = hi ;
312+ break ;
313+ }
314+ if (h == NULL ) {
315+ h = ngx_list_push (& r -> headers_out .headers );
316+ }
317+ if (h == NULL ) {
318+ return NGX_ERROR ;
319+ }
320+ h -> key = * key ;
321+ h -> value = * value ;
322+ if (value -> len == 0 ) {
323+ h -> hash = 0 ;
324+ } else {
325+ h -> hash = 1 ;
326+ }
327+
328+ h -> lowcase_key = ngx_pnalloc (r -> pool , h -> key .len );
329+ if (h -> lowcase_key == NULL ) {
330+ return NGX_ERROR ;
331+ }
332+
333+ ngx_strlow (h -> lowcase_key , h -> key .data , h -> key .len );
334+
335+ return NGX_OK ;
336+ }
0 commit comments