comparison src/http/modules/ngx_http_charset_filter_module.c @ 184:71ff1e2b484a NGINX_0_3_39

nginx 0.3.39 *) 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; bug appeared in 0.2.0. *) Bugfix: the limit rate might not work on some condition; bug appeared in 0.3.38.
author Igor Sysoev <http://sysoev.ru>
date Mon, 17 Apr 2006 00:00:00 +0400
parents 36af50a5582d
children ca5f86d94316
comparison
equal deleted inserted replaced
183:f4b38f37ca5b 184:71ff1e2b484a
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 }