Mercurial > hg > nginx
comparison src/http/modules/ngx_http_charset_filter_module.c @ 635:18268abd340c release-0.3.39
nginx-0.3.39-RELEASE import
*) Feature: the "uninitialized_variable_warn" directive; the logging
level of the "uninitialized variable" message was lowered from
"alert" to "warn".
*) Feature: the "override_charset" directive.
*) Change: now if the unknown variable is used in the "echo" and "if
expr='$name'" SSI-commands, then the "unknown variable" message is
not logged.
*) Bugfix: the active connection counter increased on the exceeding of
the connection limit specified by the "worker_connections"
directive; the bug had appeared in 0.2.0.
*) Bugfix: the limit rate might not work on some condition; the bug had
appeared in 0.3.38.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 17 Apr 2006 19:55:41 +0000 |
parents | 9262f520ce21 |
children | 7cbef16c71a1 |
comparison
equal
deleted
inserted
replaced
634:af8e20368022 | 635:18268abd340c |
---|---|
11 | 11 |
12 #define NGX_HTTP_NO_CHARSET -2 | 12 #define NGX_HTTP_NO_CHARSET -2 |
13 | 13 |
14 | 14 |
15 typedef struct { | 15 typedef struct { |
16 char **tables; | 16 u_char **tables; |
17 ngx_str_t name; | 17 ngx_str_t name; |
18 | 18 |
19 ngx_uint_t utf8; /* unsigned utf8:1; */ | 19 ngx_uint_t utf8; /* unsigned utf8:1; */ |
20 } ngx_http_charset_t; | 20 } ngx_http_charset_t; |
21 | 21 |
22 | 22 |
23 typedef struct { | 23 typedef struct { |
24 ngx_int_t src; | 24 ngx_int_t src; |
25 ngx_int_t dst; | 25 ngx_int_t dst; |
26 } ngx_http_charset_recode_t; | 26 } ngx_http_charset_recode_t; |
27 | 27 |
28 | 28 |
29 typedef struct { | 29 typedef struct { |
30 ngx_int_t src; | 30 ngx_int_t src; |
31 ngx_int_t dst; | 31 ngx_int_t dst; |
32 char *src2dst; | 32 u_char *src2dst; |
33 char *dst2src; | 33 u_char *dst2src; |
34 } ngx_http_charset_tables_t; | 34 } ngx_http_charset_tables_t; |
35 | 35 |
36 | 36 |
37 typedef struct { | 37 typedef struct { |
38 ngx_array_t charsets; /* ngx_http_charset_t */ | 38 ngx_array_t charsets; /* ngx_http_charset_t */ |
39 ngx_array_t tables; /* ngx_http_charset_tables_t */ | 39 ngx_array_t tables; /* ngx_http_charset_tables_t */ |
40 ngx_array_t recodes; /* ngx_http_charset_recode_t */ | 40 ngx_array_t recodes; /* ngx_http_charset_recode_t */ |
41 } ngx_http_charset_main_conf_t; | 41 } ngx_http_charset_main_conf_t; |
42 | 42 |
43 | 43 |
44 typedef struct { | 44 typedef struct { |
45 ngx_int_t charset; | 45 ngx_int_t charset; |
46 ngx_int_t source_charset; | 46 ngx_int_t source_charset; |
47 ngx_flag_t override_charset; | |
47 } ngx_http_charset_loc_conf_t; | 48 } ngx_http_charset_loc_conf_t; |
48 | 49 |
49 | 50 |
50 typedef struct { | 51 typedef struct { |
51 ngx_int_t server; | 52 u_char *table; |
52 ngx_int_t client; | 53 ngx_int_t charset; |
53 } ngx_http_charset_ctx_t; | 54 } ngx_http_charset_ctx_t; |
54 | 55 |
55 | 56 |
56 static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, char *table); | 57 static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table); |
57 | 58 |
58 static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, | 59 static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, |
59 void *conf); | 60 void *conf); |
60 static char *ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); | 61 static char *ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); |
61 | 62 |
86 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF | 87 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF |
87 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, | 88 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, |
88 ngx_http_set_charset_slot, | 89 ngx_http_set_charset_slot, |
89 NGX_HTTP_LOC_CONF_OFFSET, | 90 NGX_HTTP_LOC_CONF_OFFSET, |
90 offsetof(ngx_http_charset_loc_conf_t, source_charset), | 91 offsetof(ngx_http_charset_loc_conf_t, source_charset), |
92 NULL }, | |
93 | |
94 { ngx_string("override_charset"), | |
95 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF | |
96 |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG, | |
97 ngx_conf_set_flag_slot, | |
98 NGX_HTTP_LOC_CONF_OFFSET, | |
99 offsetof(ngx_http_charset_loc_conf_t, override_charset), | |
91 NULL }, | 100 NULL }, |
92 | 101 |
93 { ngx_string("charset_map"), | 102 { ngx_string("charset_map"), |
94 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, | 103 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, |
95 ngx_charset_map_block, | 104 ngx_charset_map_block, |
137 | 146 |
138 | 147 |
139 static ngx_int_t | 148 static ngx_int_t |
140 ngx_http_charset_header_filter(ngx_http_request_t *r) | 149 ngx_http_charset_header_filter(ngx_http_request_t *r) |
141 { | 150 { |
151 size_t len; | |
152 u_char *p; | |
153 ngx_int_t charset, source_charset; | |
154 ngx_uint_t i; | |
142 ngx_http_charset_t *charsets; | 155 ngx_http_charset_t *charsets; |
143 ngx_http_charset_ctx_t *ctx; | 156 ngx_http_charset_ctx_t *ctx; |
144 ngx_http_charset_loc_conf_t *lcf; | 157 ngx_http_charset_loc_conf_t *lcf; |
145 ngx_http_charset_main_conf_t *mcf; | 158 ngx_http_charset_main_conf_t *mcf; |
146 | 159 |
147 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); | 160 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); |
148 lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); | 161 |
149 | 162 ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); |
150 if (lcf->charset == NGX_HTTP_NO_CHARSET) { | 163 |
151 return ngx_http_next_header_filter(r); | 164 if (ctx == NULL) { |
165 lcf = ngx_http_get_module_loc_conf(r->main, | |
166 ngx_http_charset_filter_module); | |
167 charset = lcf->charset; | |
168 | |
169 if (charset == NGX_HTTP_NO_CHARSET) { | |
170 return ngx_http_next_header_filter(r); | |
171 } | |
172 | |
173 } else { | |
174 charset = ctx->charset; | |
152 } | 175 } |
153 | 176 |
154 if (r->headers_out.content_type.len == 0) { | 177 if (r->headers_out.content_type.len == 0) { |
155 return ngx_http_next_header_filter(r); | 178 return ngx_http_next_header_filter(r); |
156 } | 179 } |
160 "application/x-javascript", 24) != 0) | 183 "application/x-javascript", 24) != 0) |
161 { | 184 { |
162 return ngx_http_next_header_filter(r); | 185 return ngx_http_next_header_filter(r); |
163 } | 186 } |
164 | 187 |
165 if (r == r->main | 188 charsets = mcf->charsets.elts; |
166 && ngx_strstr(r->headers_out.content_type.data, "charset") != NULL) | 189 |
167 { | 190 lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); |
191 | |
192 len = 0; | |
193 | |
194 for (p = r->headers_out.content_type.data; *p; p++) { | |
195 if (*p == ';') { | |
196 len = p - r->headers_out.content_type.data; | |
197 } | |
198 | |
199 if (ngx_strncasecmp(p, "charset=", 8) != 0) { | |
200 continue; | |
201 } | |
202 | |
203 p += 8; | |
204 | |
205 for (i = 0; i < mcf->charsets.nelts; i++) { | |
206 | |
207 if (ngx_strcasecmp(p, charsets[i].name.data) == 0) { | |
208 | |
209 if (r == r->main && lcf->override_charset == 0) { | |
210 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); | |
211 if (ctx == NULL) { | |
212 return NGX_ERROR; | |
213 } | |
214 | |
215 ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module); | |
216 | |
217 ctx->charset = i; | |
218 | |
219 return ngx_http_next_header_filter(r); | |
220 } | |
221 | |
222 if (i != (ngx_uint_t) charset | |
223 && (charsets[i].tables == NULL | |
224 || charsets[i].tables[charset] == NULL)) | |
225 { | |
226 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
227 "no \"charset_map\" between the charsets " | |
228 "\"%V\" and \"%V\"", | |
229 &charsets[i].name, &charsets[charset].name); | |
230 | |
231 return ngx_http_next_header_filter(r); | |
232 } | |
233 | |
234 r->headers_out.content_type.len = len; | |
235 | |
236 if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY | |
237 || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) | |
238 { | |
239 /* | |
240 * do not set charset for the redirect because NN 4.x | |
241 * uses this charset instead of the next page charset | |
242 */ | |
243 | |
244 r->headers_out.charset.len = 0; | |
245 return ngx_http_next_header_filter(r); | |
246 } | |
247 | |
248 source_charset = i; | |
249 | |
250 goto found; | |
251 } | |
252 } | |
253 | |
168 return ngx_http_next_header_filter(r); | 254 return ngx_http_next_header_filter(r); |
169 } | 255 } |
170 | 256 |
171 if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY | 257 if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY |
172 || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) | 258 || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) |
173 { | 259 { |
174 /* | 260 /* |
175 * do not set charset for the redirect because NN 4.x uses this | 261 * do not set charset for the redirect because NN 4.x |
176 * charset instead of the next page charset | 262 * use this charset instead of the next page charset |
177 */ | 263 */ |
178 | 264 |
179 r->headers_out.charset.len = 0; | 265 r->headers_out.charset.len = 0; |
180 return ngx_http_next_header_filter(r); | 266 return ngx_http_next_header_filter(r); |
181 } | 267 } |
182 | 268 |
183 if (r->headers_out.charset.len) { | 269 if (r->headers_out.charset.len) { |
184 return ngx_http_next_header_filter(r); | 270 return ngx_http_next_header_filter(r); |
185 } | 271 } |
186 | 272 |
187 charsets = mcf->charsets.elts; | 273 source_charset = lcf->source_charset; |
188 r->headers_out.charset = charsets[lcf->charset].name; | 274 |
189 r->utf8 = charsets[lcf->charset].utf8; | 275 found: |
190 | 276 |
191 if (lcf->source_charset == NGX_CONF_UNSET | 277 r->headers_out.charset = charsets[charset].name; |
192 || lcf->source_charset == lcf->charset) | 278 r->utf8 = charsets[charset].utf8; |
193 { | 279 |
280 if (source_charset == NGX_CONF_UNSET || source_charset == charset) { | |
194 return ngx_http_next_header_filter(r); | 281 return ngx_http_next_header_filter(r); |
195 } | 282 } |
196 | |
197 | 283 |
198 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); | 284 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); |
199 if (ctx == NULL) { | 285 if (ctx == NULL) { |
200 return NGX_ERROR; | 286 return NGX_ERROR; |
201 } | 287 } |
202 | 288 |
203 ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module); | 289 ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module); |
204 | 290 |
291 ctx->table = charsets[source_charset].tables[charset]; | |
292 ctx->charset = charset; | |
205 | 293 |
206 r->filter_need_in_memory = 1; | 294 r->filter_need_in_memory = 1; |
207 | 295 |
208 return ngx_http_next_header_filter(r); | 296 return ngx_http_next_header_filter(r); |
209 } | 297 } |
210 | 298 |
211 | 299 |
212 static ngx_int_t | 300 static ngx_int_t |
213 ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | 301 ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in) |
214 { | 302 { |
215 char *table; | 303 ngx_chain_t *cl; |
216 ngx_chain_t *cl; | 304 ngx_http_charset_ctx_t *ctx; |
217 ngx_http_charset_t *charsets; | |
218 ngx_http_charset_ctx_t *ctx; | |
219 ngx_http_charset_loc_conf_t *lcf; | |
220 ngx_http_charset_main_conf_t *mcf; | |
221 | 305 |
222 ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module); | 306 ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module); |
223 | 307 |
224 if (ctx == NULL) { | 308 if (ctx == NULL || ctx->table == NULL) { |
225 return ngx_http_next_body_filter(r, in); | 309 return ngx_http_next_body_filter(r, in); |
226 } | 310 } |
227 | 311 |
228 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); | |
229 lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); | |
230 | |
231 charsets = mcf->charsets.elts; | |
232 table = charsets[lcf->source_charset].tables[lcf->charset]; | |
233 | |
234 for (cl = in; cl; cl = cl->next) { | 312 for (cl = in; cl; cl = cl->next) { |
235 ngx_http_charset_recode(cl->buf, table); | 313 (void) ngx_http_charset_recode(cl->buf, ctx->table); |
236 } | 314 } |
237 | 315 |
238 return ngx_http_next_body_filter(r, in); | 316 return ngx_http_next_body_filter(r, in); |
239 } | 317 } |
240 | 318 |
241 | 319 |
242 static ngx_uint_t | 320 static ngx_uint_t |
243 ngx_http_charset_recode(ngx_buf_t *b, char *table) | 321 ngx_http_charset_recode(ngx_buf_t *b, u_char *table) |
244 { | 322 { |
245 u_char *p; | 323 u_char *p; |
246 ngx_uint_t change; | |
247 | |
248 change = 0; | |
249 | 324 |
250 for (p = b->pos; p < b->last; p++) { | 325 for (p = b->pos; p < b->last; p++) { |
251 if (*p != table[*p]) { | 326 |
252 change = 1; | 327 if (*p == table[*p]) { |
253 break; | 328 continue; |
254 } | 329 } |
255 } | |
256 | |
257 if (change) { | |
258 | 330 |
259 while (p < b->last) { | 331 while (p < b->last) { |
260 *p = table[*p]; | 332 *p = table[*p]; |
261 p++; | 333 p++; |
262 } | 334 } |
263 | 335 |
264 b->in_file = 0; | 336 b->in_file = 0; |
265 } | 337 |
266 | 338 return 1; |
267 return change; | 339 } |
340 | |
341 return 0; | |
268 } | 342 } |
269 | 343 |
270 | 344 |
271 static char * | 345 static char * |
272 ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 346 ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
328 if (table->dst2src == NULL) { | 402 if (table->dst2src == NULL) { |
329 return NGX_CONF_ERROR; | 403 return NGX_CONF_ERROR; |
330 } | 404 } |
331 | 405 |
332 for (i = 0; i < 128; i++) { | 406 for (i = 0; i < 128; i++) { |
333 table->src2dst[i] = (char) i; | 407 table->src2dst[i] = (u_char) i; |
334 table->dst2src[i] = (char) i; | 408 table->dst2src[i] = (u_char) i; |
335 } | 409 } |
336 | 410 |
337 for (/* void */; i < 256; i++) { | 411 for (/* void */; i < 256; i++) { |
338 table->src2dst[i] = '?'; | 412 table->src2dst[i] = '?'; |
339 table->dst2src[i] = '?'; | 413 table->dst2src[i] = '?'; |
380 return NGX_CONF_ERROR; | 454 return NGX_CONF_ERROR; |
381 } | 455 } |
382 | 456 |
383 table = cf->ctx; | 457 table = cf->ctx; |
384 | 458 |
385 table->src2dst[src] = (char) dst; | 459 table->src2dst[src] = (u_char) dst; |
386 table->dst2src[dst] = (char) src; | 460 table->dst2src[dst] = (u_char) src; |
387 | 461 |
388 return NGX_CONF_OK; | 462 return NGX_CONF_OK; |
389 } | 463 } |
390 | 464 |
391 | 465 |
517 return NGX_CONF_ERROR; | 591 return NGX_CONF_ERROR; |
518 } | 592 } |
519 | 593 |
520 lcf->charset = NGX_CONF_UNSET; | 594 lcf->charset = NGX_CONF_UNSET; |
521 lcf->source_charset = NGX_CONF_UNSET; | 595 lcf->source_charset = NGX_CONF_UNSET; |
596 lcf->override_charset = NGX_CONF_UNSET; | |
522 | 597 |
523 return lcf; | 598 return lcf; |
524 } | 599 } |
525 | 600 |
526 | 601 |
532 | 607 |
533 ngx_uint_t i; | 608 ngx_uint_t i; |
534 ngx_http_charset_recode_t *recode; | 609 ngx_http_charset_recode_t *recode; |
535 ngx_http_charset_main_conf_t *mcf; | 610 ngx_http_charset_main_conf_t *mcf; |
536 | 611 |
612 ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0); | |
537 ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET); | 613 ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET); |
538 | 614 |
539 if (conf->source_charset == NGX_CONF_UNSET) { | 615 if (conf->source_charset == NGX_CONF_UNSET) { |
540 conf->source_charset = prev->source_charset; | 616 conf->source_charset = prev->source_charset; |
541 } | 617 } |
571 | 647 |
572 | 648 |
573 static ngx_int_t | 649 static ngx_int_t |
574 ngx_http_charset_postconfiguration(ngx_conf_t *cf) | 650 ngx_http_charset_postconfiguration(ngx_conf_t *cf) |
575 { | 651 { |
652 u_char **src, **dst; | |
576 ngx_int_t c; | 653 ngx_int_t c; |
577 ngx_uint_t i, t; | 654 ngx_uint_t i, t; |
578 ngx_http_charset_t *charset; | 655 ngx_http_charset_t *charset; |
579 ngx_http_charset_recode_t *recode; | 656 ngx_http_charset_recode_t *recode; |
580 ngx_http_charset_tables_t *tables; | 657 ngx_http_charset_tables_t *tables; |
589 | 666 |
590 for (i = 0; i < mcf->recodes.nelts; i++) { | 667 for (i = 0; i < mcf->recodes.nelts; i++) { |
591 | 668 |
592 c = recode[i].src; | 669 c = recode[i].src; |
593 | 670 |
594 charset[c].tables = ngx_pcalloc(cf->pool, | |
595 sizeof(char *) * mcf->charsets.nelts); | |
596 if (charset[c].tables == NULL) { | |
597 return NGX_ERROR; | |
598 } | |
599 | |
600 for (t = 0; t < mcf->tables.nelts; t++) { | 671 for (t = 0; t < mcf->tables.nelts; t++) { |
601 | 672 |
602 if (c == tables[t].src && recode[i].dst == tables[t].dst) { | 673 if (c == tables[t].src && recode[i].dst == tables[t].dst) { |
603 charset[c].tables[tables[t].dst] = tables[t].src2dst; | |
604 goto next; | 674 goto next; |
605 } | 675 } |
606 | 676 |
607 if (c == tables[t].dst && recode[i].dst == tables[t].src) { | 677 if (c == tables[t].dst && recode[i].dst == tables[t].src) { |
608 charset[c].tables[tables[t].src] = tables[t].dst2src; | |
609 goto next; | 678 goto next; |
610 } | 679 } |
611 } | 680 } |
612 | 681 |
613 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | 682 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, |
618 | 687 |
619 next: | 688 next: |
620 continue; | 689 continue; |
621 } | 690 } |
622 | 691 |
692 | |
693 for (t = 0; t < mcf->tables.nelts; t++) { | |
694 | |
695 src = charset[tables[t].src].tables; | |
696 | |
697 if (src == NULL) { | |
698 src = ngx_pcalloc(cf->pool, sizeof(u_char *) * mcf->charsets.nelts); | |
699 if (src == NULL) { | |
700 return NGX_ERROR; | |
701 } | |
702 | |
703 charset[tables[t].src].tables = src; | |
704 } | |
705 | |
706 dst = charset[tables[t].dst].tables; | |
707 | |
708 if (dst == NULL) { | |
709 dst = ngx_pcalloc(cf->pool, sizeof(u_char *) * mcf->charsets.nelts); | |
710 if (dst == NULL) { | |
711 return NGX_ERROR; | |
712 } | |
713 | |
714 charset[tables[t].dst].tables = dst; | |
715 } | |
716 | |
717 src[tables[t].dst] = tables[t].src2dst; | |
718 dst[tables[t].src] = tables[t].dst2src; | |
719 } | |
720 | |
623 return NGX_OK; | 721 return NGX_OK; |
624 } | 722 } |