1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11
12
13 #define NGX_HTTP_CHARSET_OFF -2
14 #define NGX_HTTP_NO_CHARSET -3
15 #define NGX_HTTP_CHARSET_VAR 0x10000
16
17 /* 1 byte length and up to 3 bytes for the UTF-8 encoding of the UCS-2 */
18 #define NGX_UTF_LEN 4
19
20 #define NGX_HTML_ENTITY_LEN (sizeof("") - 1)
21
22
23 typedef struct {
24 u_char **tables;
25 ngx_str_t name;
26
27 unsigned length:16;
28 unsigned utf8:1;
29 } ngx_http_charset_t;
30
31
32 typedef struct {
33 ngx_int_t src;
34 ngx_int_t dst;
35 } ngx_http_charset_recode_t;
36
37
38 typedef struct {
39 ngx_int_t src;
40 ngx_int_t dst;
41 u_char *src2dst;
42 u_char *dst2src;
43 } ngx_http_charset_tables_t;
44
45
46 typedef struct {
47 ngx_array_t charsets; /* ngx_http_charset_t */
48 ngx_array_t tables; /* ngx_http_charset_tables_t */
49 ngx_array_t recodes; /* ngx_http_charset_recode_t */
50 } ngx_http_charset_main_conf_t;
51
52
53 typedef struct {
54 ngx_int_t charset;
55 ngx_int_t source_charset;
56 ngx_flag_t override_charset;
57
58 ngx_hash_t types;
59 ngx_array_t *types_keys;
60 } ngx_http_charset_loc_conf_t;
61
62
63 typedef struct {
64 u_char *table;
65 ngx_int_t charset;
66 ngx_str_t charset_name;
67
68 ngx_chain_t *busy;
69 ngx_chain_t *free_bufs;
70 ngx_chain_t *free_buffers;
71
72 size_t saved_len;
73 u_char saved[NGX_UTF_LEN];
74
75 unsigned length:16;
76 unsigned from_utf8:1;
77 unsigned to_utf8:1;
78 } ngx_http_charset_ctx_t;
79
80
81 typedef struct {
82 ngx_http_charset_tables_t *table;
83 ngx_http_charset_t *charset;
84 ngx_uint_t characters;
85 } ngx_http_charset_conf_ctx_t;
86
87
88 static ngx_int_t ngx_http_destination_charset(ngx_http_request_t *r,
89 ngx_str_t *name);
90 static ngx_int_t ngx_http_main_request_charset(ngx_http_request_t *r,
91 ngx_str_t *name);
92 static ngx_int_t ngx_http_source_charset(ngx_http_request_t *r,
93 ngx_str_t *name);
94 static ngx_int_t ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name);
95 static ngx_inline void ngx_http_set_charset(ngx_http_request_t *r,
96 ngx_str_t *charset);
97 static ngx_int_t ngx_http_charset_ctx(ngx_http_request_t *r,
98 ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset);
99 static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table);
100 static ngx_chain_t *ngx_http_charset_recode_from_utf8(ngx_pool_t *pool,
101 ngx_buf_t *buf, ngx_http_charset_ctx_t *ctx);
102 static ngx_chain_t *ngx_http_charset_recode_to_utf8(ngx_pool_t *pool,
103 ngx_buf_t *buf, ngx_http_charset_ctx_t *ctx);
104
105 static ngx_chain_t *ngx_http_charset_get_buf(ngx_pool_t *pool,
106 ngx_http_charset_ctx_t *ctx);
107 static ngx_chain_t *ngx_http_charset_get_buffer(ngx_pool_t *pool,
108 ngx_http_charset_ctx_t *ctx, size_t size);
109
110 static char *ngx_http_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd,
111 void *conf);
112 static char *ngx_http_charset_map(ngx_conf_t *cf, ngx_command_t *dummy,
113 void *conf);
114
115 static char *ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd,
116 void *conf);
117 static ngx_int_t ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name);
118
119 static void *ngx_http_charset_create_main_conf(ngx_conf_t *cf);
120 static void *ngx_http_charset_create_loc_conf(ngx_conf_t *cf);
121 static char *ngx_http_charset_merge_loc_conf(ngx_conf_t *cf,
122 void *parent, void *child);
123 static ngx_int_t ngx_http_charset_postconfiguration(ngx_conf_t *cf);
124
125
126 ngx_str_t ngx_http_charset_default_types[] = {
127 ngx_string("text/html"),
128 ngx_string("text/xml"),
129 ngx_string("text/plain"),
130 ngx_string("text/vnd.wap.wml"),
131 ngx_string("application/x-javascript"),
132 ngx_string("application/rss+xml"),
133 ngx_null_string
134 };
135
136
137 static ngx_command_t ngx_http_charset_filter_commands[] = {
138
139 { ngx_string("charset"),
140 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
141 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
142 ngx_http_set_charset_slot,
143 NGX_HTTP_LOC_CONF_OFFSET,
144 offsetof(ngx_http_charset_loc_conf_t, charset),
145 NULL },
146
147 { ngx_string("source_charset"),
148 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
149 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
150 ngx_http_set_charset_slot,
151 NGX_HTTP_LOC_CONF_OFFSET,
152 offsetof(ngx_http_charset_loc_conf_t, source_charset),
153 NULL },
154
155 { ngx_string("override_charset"),
156 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
157 |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
158 ngx_conf_set_flag_slot,
159 NGX_HTTP_LOC_CONF_OFFSET,
160 offsetof(ngx_http_charset_loc_conf_t, override_charset),
161 NULL },
162
163 { ngx_string("charset_types"),
164 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
165 ngx_http_types_slot,
166 NGX_HTTP_LOC_CONF_OFFSET,
167 offsetof(ngx_http_charset_loc_conf_t, types_keys),
168 &ngx_http_charset_default_types[0] },
169
170 { ngx_string("charset_map"),
171 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
172 ngx_http_charset_map_block,
173 NGX_HTTP_MAIN_CONF_OFFSET,
174 0,
175 NULL },
176
177 ngx_null_command
178 };
179
180
181 static ngx_http_module_t ngx_http_charset_filter_module_ctx = {
182 NULL, /* preconfiguration */
183 ngx_http_charset_postconfiguration, /* postconfiguration */
184
185 ngx_http_charset_create_main_conf, /* create main configuration */
186 NULL, /* init main configuration */
187
188 NULL, /* create server configuration */
189 NULL, /* merge server configuration */
190
191 ngx_http_charset_create_loc_conf, /* create location configuration */
192 ngx_http_charset_merge_loc_conf /* merge location configuration */
193 };
194
195
196 ngx_module_t ngx_http_charset_filter_module = {
197 NGX_MODULE_V1,
198 &ngx_http_charset_filter_module_ctx, /* module context */
199 ngx_http_charset_filter_commands, /* module directives */
200 NGX_HTTP_MODULE, /* module type */
201 NULL, /* init master */
202 NULL, /* init module */
203 NULL, /* init process */
204 NULL, /* init thread */
205 NULL, /* exit thread */
206 NULL, /* exit process */
207 NULL, /* exit master */
208 NGX_MODULE_V1_PADDING
209 };
210
211
212 static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
213 static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
214
215
216 static ngx_int_t
217 ngx_http_charset_header_filter(ngx_http_request_t *r)
218 {
219 ngx_int_t charset, source_charset;
220 ngx_str_t dst, src;
221 ngx_http_charset_t *charsets;
222 ngx_http_charset_main_conf_t *mcf;
223
224 if (r == r->main) {
225 charset = ngx_http_destination_charset(r, &dst);
226
227 } else {
228 charset = ngx_http_main_request_charset(r, &dst);
229 }
230
231 if (charset == NGX_ERROR) {
232 return NGX_ERROR;
233 }
234
235 if (charset == NGX_DECLINED) {
236 return ngx_http_next_header_filter(r);
237 }
238
239 /* charset: charset index or NGX_HTTP_NO_CHARSET */
240
241 source_charset = ngx_http_source_charset(r, &src);
242
243 if (source_charset == NGX_ERROR) {
244 return NGX_ERROR;
245 }
246
247 /*
248 * source_charset: charset index, NGX_HTTP_NO_CHARSET,
249 * or NGX_HTTP_CHARSET_OFF
250 */
251
252 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
253 "charset: \"%V\" > \"%V\"", &src, &dst);
254
255 if (source_charset == NGX_HTTP_CHARSET_OFF) {
256 ngx_http_set_charset(r, &dst);
257
258 return ngx_http_next_header_filter(r);
259 }
260
261 if (charset == NGX_HTTP_NO_CHARSET
262 || source_charset == NGX_HTTP_NO_CHARSET)
263 {
264 if (source_charset != charset
265 || ngx_strncasecmp(dst.data, src.data, dst.len) != 0)
266 {
267 goto no_charset_map;
268 }
269
270 ngx_http_set_charset(r, &dst);
271
272 return ngx_http_next_header_filter(r);
273 }
274
275 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
276 charsets = mcf->charsets.elts;
277
278 if (source_charset != charset
279 && (charsets[source_charset].tables == NULL
280 || charsets[source_charset].tables[charset] == NULL))
281 {
282 goto no_charset_map;
283 }
284
285 r->headers_out.content_type.len = r->headers_out.content_type_len;
286
287 ngx_http_set_charset(r, &dst);
288
289 if (source_charset != charset) {
290 return ngx_http_charset_ctx(r, charsets, charset, source_charset);
291 }
292
293 return ngx_http_next_header_filter(r);
294
295 no_charset_map:
296
297 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
298 "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
299 &src, &dst);
300
301 return ngx_http_next_header_filter(r);
302 }
303
304
305 static ngx_int_t
306 ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name)
307 {
308 ngx_int_t charset;
309 ngx_http_charset_t *charsets;
310 ngx_http_variable_value_t *vv;
311 ngx_http_charset_loc_conf_t *mlcf;
312 ngx_http_charset_main_conf_t *mcf;
313
314 if (!r->ignore_content_encoding
315 && r->headers_out.content_encoding
316 && r->headers_out.content_encoding->value.len)
317 {
318 return NGX_DECLINED;
319 }
320
321 if (r->headers_out.content_type.len == 0) {
322 return NGX_DECLINED;
323 }
324
325 if (r->headers_out.override_charset
326 && r->headers_out.override_charset->len)
327 {
328 *name = *r->headers_out.override_charset;
329
330 charset = ngx_http_get_charset(r, name);
331
332 if (charset != NGX_HTTP_NO_CHARSET) {
333 return charset;
334 }
335
336 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
337 "unknown charset \"%V\" to override", name);
338
339 return NGX_DECLINED;
340 }
341
342 mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
343 charset = mlcf->charset;
344
345 if (charset == NGX_HTTP_CHARSET_OFF) {
346 return NGX_DECLINED;
347 }
348
349 if (r->headers_out.charset.len) {
350 if (mlcf->override_charset == 0) {
351 return NGX_DECLINED;
352 }
353
354 } else {
355 if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
356 return NGX_DECLINED;
357 }
358 }
359
360 if (charset < NGX_HTTP_CHARSET_VAR) {
361 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
362 charsets = mcf->charsets.elts;
363 *name = charsets[charset].name;
364 return charset;
365 }
366
367 vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR);
368
369 if (vv == NULL || vv->not_found) {
370 return NGX_ERROR;
371 }
372
373 name->len = vv->len;
374 name->data = vv->data;
375
376 return ngx_http_get_charset(r, name);
377 }
378
379
380 static ngx_int_t
381 ngx_http_main_request_charset(ngx_http_request_t *r, ngx_str_t *src)
382 {
383 ngx_int_t charset;
384 ngx_str_t *main_charset;
385 ngx_http_charset_ctx_t *ctx;
386
387 ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);
388
389 if (ctx) {
390 *src = ctx->charset_name;
391 return ctx->charset;
392 }
393
394 main_charset = &r->main->headers_out.charset;
395
396 if (main_charset->len == 0) {
397 return NGX_DECLINED;
398 }
399
400 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
401 if (ctx == NULL) {
402 return NGX_ERROR;
403 }
404
405 ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module);
406
407 charset = ngx_http_get_charset(r, main_charset);
408
409 ctx->charset = charset;
410 ctx->charset_name = *main_charset;
411 *src = *main_charset;
412
413 return charset;
414 }
415
416
417 static ngx_int_t
418 ngx_http_source_charset(ngx_http_request_t *r, ngx_str_t *name)
419 {
420 ngx_int_t charset;
421 ngx_http_charset_t *charsets;
422 ngx_http_variable_value_t *vv;
423 ngx_http_charset_loc_conf_t *lcf;
424 ngx_http_charset_main_conf_t *mcf;
425
426 if (r->headers_out.charset.len) {
427 *name = r->headers_out.charset;
428 return ngx_http_get_charset(r, name);
429 }
430
431 lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
432
433 charset = lcf->source_charset;
434
435 if (charset == NGX_HTTP_CHARSET_OFF) {
436 name->len = 0;
437 return charset;
438 }
439
440 if (charset < NGX_HTTP_CHARSET_VAR) {
441 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
442 charsets = mcf->charsets.elts;
443 *name = charsets[charset].name;
444 return charset;
445 }
446
447 vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR);
448
449 if (vv == NULL || vv->not_found) {
450 return NGX_ERROR;
451 }
452
453 name->len = vv->len;
454 name->data = vv->data;
455
456 return ngx_http_get_charset(r, name);
457 }
458
459
460 static ngx_int_t
461 ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name)
462 {
463 ngx_uint_t i, n;
464 ngx_http_charset_t *charset;
465 ngx_http_charset_main_conf_t *mcf;
466
467 mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
468
469 charset = mcf->charsets.elts;
470 n = mcf->charsets.nelts;
471
472 for (i = 0; i < n; i++) {
473 if (charset[i].name.len != name->len) {
474 continue;
475 }
476
477 if (ngx_strncasecmp(charset[i].name.data, name->data, name->len) == 0) {
478 return i;
479 }
480 }
481
482 return NGX_HTTP_NO_CHARSET;
483 }
484
485
486 static ngx_inline void
487 ngx_http_set_charset(ngx_http_request_t *r, ngx_str_t *charset)
488 {
489 if (r != r->main) {
490 return;
491 }
492
493 if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY
494 || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY)
495 {
496 /*
497 * do not set charset for the redirect because NN 4.x
498 * use this charset instead of the next page charset
499 */
500
501 r->headers_out.charset.len = 0;
502 return;
503 }
504
505 r->headers_out.charset = *charset;
506 }
507
508
509 static ngx_int_t
510 ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets,
511 ngx_int_t charset, ngx_int_t source_charset)
512 {
513 ngx_http_charset_ctx_t *ctx;
514
515 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
516 if (ctx == NULL) {
517 return NGX_ERROR;
518 }
519
520 ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module);
521
522 ctx->table = charsets[source_charset].tables[charset];
523 ctx->charset = charset;
524 ctx->charset_name = charsets[charset].name;
525 ctx->length = charsets[charset].length;
526 ctx->from_utf8 = charsets[source_charset].utf8;
527 ctx->to_utf8 = charsets[charset].utf8;
528
529 r->filter_need_in_memory = 1;
530
531 if ((ctx->to_utf8 || ctx->from_utf8) && r == r->main) {
532 ngx_http_clear_content_length(r);
533
534 } else {
535 r->filter_need_temporary = 1;
536 }
537
538 return ngx_http_next_header_filter(r);
539 }
540
541
542 static ngx_int_t
543 ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
544 {
545 ngx_int_t rc;
546 ngx_buf_t *b;
547 ngx_chain_t *cl, *out, **ll;
548 ngx_http_charset_ctx_t *ctx;
549
550 ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module);
551
552 if (ctx == NULL || ctx->table == NULL) {
553 return ngx_http_next_body_filter(r, in);
554 }
555
556 if ((ctx->to_utf8 || ctx->from_utf8) || ctx->busy) {
557
558 out = NULL;
559 ll = &out;
560
561 for (cl = in; cl; cl = cl->next) {
562 b = cl->buf;
563
564 if (ngx_buf_size(b) == 0) {
565
566 *ll = ngx_alloc_chain_link(r->pool);
567 if (*ll == NULL) {
568 return NGX_ERROR;
569 }
570
571 (*ll)->buf = b;
572 (*ll)->next = NULL;
573
574 ll = &(*ll)->next;
575
576 continue;
577 }
578
579 if (ctx->to_utf8) {
580 *ll = ngx_http_charset_recode_to_utf8(r->pool, b, ctx);
581
582 } else {
583 *ll = ngx_http_charset_recode_from_utf8(r->pool, b, ctx);
584 }
585
586 if (*ll == NULL) {
587 return NGX_ERROR;
588 }
589
590 while (*ll) {
591 ll = &(*ll)->next;
592 }
593 }
594
595 rc = ngx_http_next_body_filter(r, out);
596
597 if (out) {
598 if (ctx->busy == NULL) {
599 ctx->busy = out;
600
601 } else {
602 for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ }
603 cl->next = out;
604 }
605 }
606
607 while (ctx->busy) {
608
609 cl = ctx->busy;
610 b = cl->buf;
611
612 if (ngx_buf_size(b) != 0) {
613 break;
614 }
615
616 ctx->busy = cl->next;
617
618 if (b->tag != (ngx_buf_tag_t) &ngx_http_charset_filter_module) {
619 continue;
620 }
621
622 if (b->shadow) {
623 b->shadow->pos = b->shadow->last;
624 }
625
626 if (b->pos) {
627 cl->next = ctx->free_buffers;
628 ctx->free_buffers = cl;
629 continue;
630 }
631
632 cl->next = ctx->free_bufs;
633 ctx->free_bufs = cl;
634 }
635
636 return rc;
637 }
638
639 for (cl = in; cl; cl = cl->next) {
640 (void) ngx_http_charset_recode(cl->buf, ctx->table);
641 }
642
643 return ngx_http_next_body_filter(r, in);
644 }
645
646
647 static ngx_uint_t
648 ngx_http_charset_recode(ngx_buf_t *b, u_char *table)
649 {
650 u_char *p, *last;
651
652 last = b->last;
653
654 for (p = b->pos; p < last; p++) {
655
656 if (*p != table[*p]) {
657 goto recode;
658 }
659 }
660
661 return 0;
662
663 recode:
664
665 do {
666 if (*p != table[*p]) {
667 *p = table[*p];
668 }
669
670 p++;
671
672 } while (p < last);
673
674 b->in_file = 0;
675
676 return 1;
677 }
678
679
680 static ngx_chain_t *
681 ngx_http_charset_recode_from_utf8(ngx_pool_t *pool, ngx_buf_t *buf,
682 ngx_http_charset_ctx_t *ctx)
683 {
684 size_t len, size;
685 u_char c, *p, *src, *dst, *saved, **table;
686 uint32_t n;
687 ngx_buf_t *b;
688 ngx_uint_t i;
689 ngx_chain_t *out, *cl, **ll;
690
691 src = buf->pos;
692
693 if (ctx->saved_len == 0) {
694
695 for ( /* void */ ; src < buf->last; src++) {
696
697 if (*src < 0x80) {
698 continue;
699 }
700
701 len = src - buf->pos;
702
703 if (len > 512) {
704 out = ngx_http_charset_get_buf(pool, ctx);
705 if (out == NULL) {
706 return NULL;
707 }
708
709 b = out->buf;
710
711 b->temporary = buf->temporary;
712 b->memory = buf->memory;
713 b->mmap = buf->mmap;
714 b->flush = buf->flush;
715
716 b->pos = buf->pos;
717 b->last = src;
718
719 out->buf = b;
720 out->next = NULL;
721
722 size = buf->last - src;
723
724 saved = src;
725 n = ngx_utf8_decode(&saved, size);
726
727 if (n == 0xfffffffe) {
728 /* incomplete UTF-8 symbol */
729
730 ngx_memcpy(ctx->saved, src, size);
731 ctx->saved_len = size;
732
733 b->shadow = buf;
734
735 return out;
736 }
737
738 } else {
739 out = NULL;
740 size = len + buf->last - src;
741 src = buf->pos;
742 }
743
744 if (size < NGX_HTML_ENTITY_LEN) {
745 size += NGX_HTML_ENTITY_LEN;
746 }
747
748 cl = ngx_http_charset_get_buffer(pool, ctx, size);
749 if (cl == NULL) {
750 return NULL;
751 }
752
753 if (out) {
754 out->next = cl;
755
756 } else {
757 out = cl;
758 }
759
760 b = cl->buf;
761 dst = b->pos;
762
763 goto recode;
764 }
765
766 out = ngx_alloc_chain_link(pool);
767 if (out == NULL) {
768 return NULL;
769 }
770
771 out->buf = buf;
772 out->next = NULL;
773
774 return out;
775 }
776
777 /* process incomplete UTF sequence from previous buffer */
778
779 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0,
780 "http charset utf saved: %z", ctx->saved_len);
781
782 p = src;
783
784 for (i = ctx->saved_len; i < NGX_UTF_LEN; i++) {
785 ctx->saved[i] = *p++;
786
787 if (p == buf->last) {
788 break;
789 }
790 }
791
792 saved = ctx->saved;
793 n = ngx_utf8_decode(&saved, i);
794
795 c = '\0';
796
797 if (n < 0x10000) {
798 table = (u_char **) ctx->table;
799 p = table[n >> 8];
800
801 if (p) {
802 c = p[n & 0xff];
803 }
804
805 } else if (n == 0xfffffffe) {
806
807 /* incomplete UTF-8 symbol */
808
809 if (i < NGX_UTF_LEN) {
810 out = ngx_http_charset_get_buf(pool, ctx);
811 if (out == NULL) {
812 return NULL;
813 }
814
815 b = out->buf;
816
817 b->pos = buf->pos;
818 b->last = buf->last;
819 b->sync = 1;
820 b->shadow = buf;
821
822 ngx_memcpy(&ctx->saved[ctx->saved_len], src, i);
823 ctx->saved_len += i;
824
825 return out;
826 }
827 }
828
829 size = buf->last - buf->pos;
830
831 if (size < NGX_HTML_ENTITY_LEN) {
832 size += NGX_HTML_ENTITY_LEN;
833 }
834
835 cl = ngx_http_charset_get_buffer(pool, ctx, size);
836 if (cl == NULL) {
837 return NULL;
838 }
839
840 out = cl;
841
842 b = cl->buf;
843 dst = b->pos;
844
845 if (c) {
846 *dst++ = c;
847
848 } else if (n == 0xfffffffe) {
849 *dst++ = '?';
850
851 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0,
852 "http charset invalid utf 0");
853
854 saved = &ctx->saved[NGX_UTF_LEN];
855
856 } else if (n > 0x10ffff) {
857 *dst++ = '?';
858
859 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0,
860 "http charset invalid utf 1");
861
862 } else {
863 dst = ngx_sprintf(dst, "&#%uD;", n);
864 }
865
866 src += (saved - ctx->saved) - ctx->saved_len;
867 ctx->saved_len = 0;
868
869 recode:
870
871 ll = &cl->next;
872
873 table = (u_char **) ctx->table;
874
875 while (src < buf->last) {
876
877 if ((size_t) (b->end - dst) < NGX_HTML_ENTITY_LEN) {
878 b->last = dst;
879
880 size = buf->last - src + NGX_HTML_ENTITY_LEN;
881
882 cl = ngx_http_charset_get_buffer(pool, ctx, size);
883 if (cl == NULL) {
884 return NULL;
885 }
886
887 *ll = cl;
888 ll = &cl->next;
889
890 b = cl->buf;
891 dst = b->pos;
892 }
893
894 if (*src < 0x80) {
895 *dst++ = *src++;
896 continue;
897 }
898
899 len = buf->last - src;
900
901 n = ngx_utf8_decode(&src, len);
902
903 if (n < 0x10000) {
904
905 p = table[n >> 8];
906
907 if (p) {
908 c = p[n & 0xff];
909
910 if (c) {
911 *dst++ = c;
912 continue;
913 }
914 }
915
916 dst = ngx_sprintf(dst, "&#%uD;", n);
917
918 continue;
919 }
920
921 if (n == 0xfffffffe) {
922 /* incomplete UTF-8 symbol */
923
924 ngx_memcpy(ctx->saved, src, len);
925 ctx->saved_len = len;
926
927 if (b->pos == dst) {
928 b->sync = 1;
929 b->temporary = 0;
930 }
931
932 break;
933 }
934
935 if (n > 0x10ffff) {
936 *dst++ = '?';
937
938 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0,
939 "http charset invalid utf 2");
940
941 continue;
942 }
943
944 /* n > 0xffff */
945
946 dst = ngx_sprintf(dst, "&#%uD;", n);
947 }
948
949 b->last = dst;
950
951 b->last_buf = buf->last_buf;
952 b->last_in_chain = buf->last_in_chain;
953 b->flush = buf->flush;
954
955 b->shadow = buf;
956
957 return out;
958 }
959
960
961 static ngx_chain_t *
962 ngx_http_charset_recode_to_utf8(ngx_pool_t *pool, ngx_buf_t *buf,
963 ngx_http_charset_ctx_t *ctx)
964 {
965 size_t len, size;
966 u_char *p, *src, *dst, *table;
967 ngx_buf_t *b;
968 ngx_chain_t *out, *cl, **ll;
969
970 table = ctx->table;
971
972 for (src = buf->pos; src < buf->last; src++) {
973 if (table[*src * NGX_UTF_LEN] == '\1') {
974 continue;
975 }
976
977 goto recode;
978 }
979
980 out = ngx_alloc_chain_link(pool);
981 if (out == NULL) {
982 return NULL;
983 }
984
985 out->buf = buf;
986 out->next = NULL;
987
988 return out;
989
990 recode:
991
992 /*
993 * we assume that there are about half of characters to be recoded,
994 * so we preallocate "size / 2 + size / 2 * ctx->length"
995 */
996
997 len = src - buf->pos;
998
999 if (len > 512) {
1000 out = ngx_http_charset_get_buf(pool, ctx);
1001 if (out == NULL) {
1002 return NULL;
1003 }
1004
1005 b = out->buf;
1006
1007 b->temporary = buf->temporary;
1008 b->memory = buf->memory;
1009 b->mmap = buf->mmap;
1010 b->flush = buf->flush;
1011
1012 b->pos = buf->pos;
1013 b->last = src;
1014
1015 out->buf = b;
1016 out->next = NULL;
1017
1018 size = buf->last - src;
1019 size = size / 2 + size / 2 * ctx->length;
1020
1021 } else {
1022 out = NULL;
1023
1024 size = buf->last - src;
1025 size = len + size / 2 + size / 2 * ctx->length;
1026
1027 src = buf->pos;
1028 }
1029
1030 cl = ngx_http_charset_get_buffer(pool, ctx, size);
1031 if (cl == NULL) {
1032 return NULL;
1033 }
1034
1035 if (out) {
1036 out->next = cl;
1037
1038 } else {
1039 out = cl;
1040 }
1041
1042 ll = &cl->next;
1043
1044 b = cl->buf;
1045 dst = b->pos;
1046
1047 while (src < buf->last) {
1048
1049 p = &table[*src++ * NGX_UTF_LEN];
1050 len = *p++;
1051
1052 if ((size_t) (b->end - dst) < len) {
1053 b->last = dst;
1054
1055 size = buf->last - src;
1056 size = len + size / 2 + size / 2 * ctx->length;
1057
1058 cl = ngx_http_charset_get_buffer(pool, ctx, size);
1059 if (cl == NULL) {
1060 return NULL;
1061 }
1062
1063 *ll = cl;
1064 ll = &cl->next;
1065
1066 b = cl->buf;
1067 dst = b->pos;
1068 }
1069
1070 while (len) {
1071 *dst++ = *p++;
1072 len--;
1073 }
1074 }
1075
1076 b->last = dst;
1077
1078 b->last_buf = buf->last_buf;
1079 b->last_in_chain = buf->last_in_chain;
1080 b->flush = buf->flush;
1081
1082 b->shadow = buf;
1083
1084 return out;
1085 }
1086
1087
1088 static ngx_chain_t *
1089 ngx_http_charset_get_buf(ngx_pool_t *pool, ngx_http_charset_ctx_t *ctx)
1090 {
1091 ngx_chain_t *cl;
1092
1093 cl = ctx->free_bufs;
1094
1095 if (cl) {
1096 ctx->free_bufs = cl->next;
1097
1098 cl->buf->shadow = NULL;
1099 cl->next = NULL;
1100
1101 return cl;
1102 }
1103
1104 cl = ngx_alloc_chain_link(pool);
1105 if (cl == NULL) {
1106 return NULL;
1107 }
1108
1109 cl->buf = ngx_calloc_buf(pool);
1110 if (cl->buf == NULL) {
1111 return NULL;
1112 }
1113
1114 cl->next = NULL;
1115
1116 cl->buf->tag = (ngx_buf_tag_t) &ngx_http_charset_filter_module;
1117
1118 return cl;
1119 }
1120
1121
1122 static ngx_chain_t *
1123 ngx_http_charset_get_buffer(ngx_pool_t *pool, ngx_http_charset_ctx_t *ctx,
1124 size_t size)
1125 {
1126 ngx_buf_t *b;
1127 ngx_chain_t *cl, **ll;
1128
1129 for (ll = &ctx->free_buffers, cl = ctx->free_buffers;
1130 cl;
1131 ll = &cl->next, cl = cl->next)
1132 {
1133 b = cl->buf;
1134
1135 if ((size_t) (b->end - b->start) >= size) {
1136 *ll = cl->next;
1137 cl->next = NULL;
1138
1139 b->pos = b->start;
1140 b->temporary = 1;
1141 b->shadow = NULL;
1142
1143 return cl;
1144 }
1145 }
1146
1147 cl = ngx_alloc_chain_link(pool);
1148 if (cl == NULL) {
1149 return NULL;
1150 }
1151
1152 cl->buf = ngx_create_temp_buf(pool, size);
1153 if (cl->buf == NULL) {
1154 return NULL;
1155 }
1156
1157 cl->next = NULL;
1158
1159 cl->buf->temporary = 1;
1160 cl->buf->tag = (ngx_buf_tag_t) &ngx_http_charset_filter_module;
1161
1162 return cl;
1163 }
1164
1165
1166 static char *
1167 ngx_http_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1168 {
1169 ngx_http_charset_main_conf_t *mcf = conf;
1170
1171 char *rv;
1172 u_char *p, *dst2src, **pp;
1173 ngx_int_t src, dst;
1174 ngx_uint_t i, n;
1175 ngx_str_t *value;
1176 ngx_conf_t pvcf;
1177 ngx_http_charset_t *charset;
1178 ngx_http_charset_tables_t *table;
1179 ngx_http_charset_conf_ctx_t ctx;
1180
1181 value = cf->args->elts;
1182
1183 src = ngx_http_add_charset(&mcf->charsets, &value[1]);
1184 if (src == NGX_ERROR) {
1185 return NGX_CONF_ERROR;
1186 }
1187
1188 dst = ngx_http_add_charset(&mcf->charsets, &value[2]);
1189 if (dst == NGX_ERROR) {
1190 return NGX_CONF_ERROR;
1191 }
1192
1193 if (src == dst) {
1194 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1195 "\"charset_map\" between the same charsets "
1196 "\"%V\" and \"%V\"", &value[1], &value[2]);
1197 return NGX_CONF_ERROR;
1198 }
1199
1200 table = mcf->tables.elts;
1201 for (i = 0; i < mcf->tables.nelts; i++) {
1202 if ((src == table->src && dst == table->dst)
1203 || (src == table->dst && dst == table->src))
1204 {
1205 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1206 "duplicate \"charset_map\" between "
1207 "\"%V\" and \"%V\"", &value[1], &value[2]);
1208 return NGX_CONF_ERROR;
1209 }
1210 }
1211
1212 table = ngx_array_push(&mcf->tables);
1213 if (table == NULL) {
1214 return NGX_CONF_ERROR;
1215 }
1216
1217 table->src = src;
1218 table->dst = dst;
1219
1220 if (ngx_strcasecmp(value[2].data, (u_char *) "utf-8") == 0) {
1221 table->src2dst = ngx_pcalloc(cf->pool, 256 * NGX_UTF_LEN);
1222 if (table->src2dst == NULL) {
1223 return NGX_CONF_ERROR;
1224 }
1225
1226 table->dst2src = ngx_pcalloc(cf->pool, 256 * sizeof(void *));
1227 if (table->dst2src == NULL) {
1228 return NGX_CONF_ERROR;
1229 }
1230
1231 dst2src = ngx_pcalloc(cf->pool, 256);
1232 if (dst2src == NULL) {
1233 return NGX_CONF_ERROR;
1234 }
1235
1236 pp = (u_char **) &table->dst2src[0];
1237 pp[0] = dst2src;
1238
1239 for (i = 0; i < 128; i++) {
1240 p = &table->src2dst[i * NGX_UTF_LEN];
1241 p[0] = '\1';
1242 p[1] = (u_char) i;
1243 dst2src[i] = (u_char) i;
1244 }
1245
1246 for (/* void */; i < 256; i++) {
1247 p = &table->src2dst[i * NGX_UTF_LEN];
1248 p[0] = '\1';
1249 p[1] = '?';
1250 }
1251
1252 } else {
1253 table->src2dst = ngx_palloc(cf->pool, 256);
1254 if (table->src2dst == NULL) {
1255 return NGX_CONF_ERROR;
1256 }
1257
1258 table->dst2src = ngx_palloc(cf->pool, 256);
1259 if (table->dst2src == NULL) {
1260 return NGX_CONF_ERROR;
1261 }
1262
1263 for (i = 0; i < 128; i++) {
1264 table->src2dst[i] = (u_char) i;
1265 table->dst2src[i] = (u_char) i;
1266 }
1267
1268 for (/* void */; i < 256; i++) {
1269 table->src2dst[i] = '?';
1270 table->dst2src[i] = '?';
1271 }
1272 }
1273
1274 charset = mcf->charsets.elts;
1275
1276 ctx.table = table;
1277 ctx.charset = &charset[dst];
1278 ctx.characters = 0;
1279
1280 pvcf = *cf;
1281 cf->ctx = &ctx;
1282 cf->handler = ngx_http_charset_map;
1283 cf->handler_conf = conf;
1284
1285 rv = ngx_conf_parse(cf, NULL);
1286
1287 *cf = pvcf;
1288
1289 if (ctx.characters) {
1290 n = ctx.charset->length;
1291 ctx.charset->length /= ctx.characters;
1292
1293 if (((n * 10) / ctx.characters) % 10 > 4) {
1294 ctx.charset->length++;
1295 }
1296 }
1297
1298 return rv;
1299 }
1300
1301
1302 static char *
1303 ngx_http_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
1304 {
1305 u_char *p, *dst2src, **pp;
1306 uint32_t n;
1307 ngx_int_t src, dst;
1308 ngx_str_t *value;
1309 ngx_uint_t i;
1310 ngx_http_charset_tables_t *table;
1311 ngx_http_charset_conf_ctx_t *ctx;
1312
1313 if (cf->args->nelts != 2) {
1314 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameters number");
1315 return NGX_CONF_ERROR;
1316 }
1317
1318 value = cf->args->elts;
1319
1320 src = ngx_hextoi(value[0].data, value[0].len);
1321 if (src == NGX_ERROR || src > 255) {
1322 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1323 "invalid value \"%V\"", &value[0]);
1324 return NGX_CONF_ERROR;
1325 }
1326
1327 ctx = cf->ctx;
1328 table = ctx->table;
1329
1330 if (ctx->charset->utf8) {
1331 p = &table->src2dst[src * NGX_UTF_LEN];
1332
1333 *p++ = (u_char) (value[1].len / 2);
1334
1335 for (i = 0; i < value[1].len; i += 2) {
1336 dst = ngx_hextoi(&value[1].data[i], 2);
1337 if (dst == NGX_ERROR || dst > 255) {
1338 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1339 "invalid value \"%V\"", &value[1]);
1340 return NGX_CONF_ERROR;
1341 }
1342
1343 *p++ = (u_char) dst;
1344 }
1345
1346 i /= 2;
1347
1348 ctx->charset->length += i;
1349 ctx->characters++;
1350
1351 p = &table->src2dst[src * NGX_UTF_LEN] + 1;
1352
1353 n = ngx_utf8_decode(&p, i);
1354
1355 if (n > 0xffff) {
1356 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1357 "invalid value \"%V\"", &value[1]);
1358 return NGX_CONF_ERROR;
1359 }
1360
1361 pp = (u_char **) &table->dst2src[0];
1362
1363 dst2src = pp[n >> 8];
1364
1365 if (dst2src == NULL) {
1366 dst2src = ngx_pcalloc(cf->pool, 256);
1367 if (dst2src == NULL) {
1368 return NGX_CONF_ERROR;
1369 }
1370
1371 pp[n >> 8] = dst2src;
1372 }
1373
1374 dst2src[n & 0xff] = (u_char) src;
1375
1376 } else {
1377 dst = ngx_hextoi(value[1].data, value[1].len);
1378 if (dst == NGX_ERROR || dst > 255) {
1379 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1380 "invalid value \"%V\"", &value[1]);
1381 return NGX_CONF_ERROR;
1382 }
1383
1384 table->src2dst[src] = (u_char) dst;
1385 table->dst2src[dst] = (u_char) src;
1386 }
1387
1388 return NGX_CONF_OK;
1389 }
1390
1391
1392 static char *
1393 ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1394 {
1395 char *p = conf;
1396
1397 ngx_int_t *cp;
1398 ngx_str_t *value, var;
1399 ngx_http_charset_main_conf_t *mcf;
1400
1401 cp = (ngx_int_t *) (p + cmd->offset);
1402
1403 if (*cp != NGX_CONF_UNSET) {
1404 return "is duplicate";
1405 }
1406
1407 value = cf->args->elts;
1408
1409 if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, charset)
1410 && ngx_strcmp(value[1].data, "off") == 0)
1411 {
1412 *cp = NGX_HTTP_CHARSET_OFF;
1413 return NGX_CONF_OK;
1414 }
1415
1416
1417 if (value[1].data[0] == '$') {
1418 var.len = value[1].len - 1;
1419 var.data = value[1].data + 1;
1420
1421 *cp = ngx_http_get_variable_index(cf, &var);
1422
1423 if (*cp == NGX_ERROR) {
1424 return NGX_CONF_ERROR;
1425 }
1426
1427 *cp += NGX_HTTP_CHARSET_VAR;
1428
1429 return NGX_CONF_OK;
1430 }
1431
1432 mcf = ngx_http_conf_get_module_main_conf(cf,
1433 ngx_http_charset_filter_module);
1434
1435 *cp = ngx_http_add_charset(&mcf->charsets, &value[1]);
1436 if (*cp == NGX_ERROR) {
1437 return NGX_CONF_ERROR;
1438 }
1439
1440 return NGX_CONF_OK;
1441 }
1442
1443
1444 static ngx_int_t
1445 ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name)
1446 {
1447 ngx_uint_t i;
1448 ngx_http_charset_t *c;
1449
1450 c = charsets->elts;
1451 for (i = 0; i < charsets->nelts; i++) {
1452 if (name->len != c[i].name.len) {
1453 continue;
1454 }
1455
1456 if (ngx_strcasecmp(name->data, c[i].name.data) == 0) {
1457 break;
1458 }
1459 }
1460
1461 if (i < charsets->nelts) {
1462 return i;
1463 }
1464
1465 c = ngx_array_push(charsets);
1466 if (c == NULL) {
1467 return NGX_ERROR;
1468 }
1469
1470 c->tables = NULL;
1471 c->name = *name;
1472 c->length = 0;
1473
1474 if (ngx_strcasecmp(name->data, (u_char *) "utf-8") == 0) {
1475 c->utf8 = 1;
1476
1477 } else {
1478 c->utf8 = 0;
1479 }
1480
1481 return i;
1482 }
1483
1484
1485 static void *
1486 ngx_http_charset_create_main_conf(ngx_conf_t *cf)
1487 {
1488 ngx_http_charset_main_conf_t *mcf;
1489
1490 mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t));
1491 if (mcf == NULL) {
1492 return NULL;
1493 }
1494
1495 if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t))
1496 != NGX_OK)
1497 {
1498 return NULL;
1499 }
1500
1501 if (ngx_array_init(&mcf->tables, cf->pool, 1,
1502 sizeof(ngx_http_charset_tables_t))
1503 != NGX_OK)
1504 {
1505 return NULL;
1506 }
1507
1508 if (ngx_array_init(&mcf->recodes, cf->pool, 2,
1509 sizeof(ngx_http_charset_recode_t))
1510 != NGX_OK)
1511 {
1512 return NULL;
1513 }
1514
1515 return mcf;
1516 }
1517
1518
1519 static void *
1520 ngx_http_charset_create_loc_conf(ngx_conf_t *cf)
1521 {
1522 ngx_http_charset_loc_conf_t *lcf;
1523
1524 lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t));
1525 if (lcf == NULL) {
1526 return NULL;
1527 }
1528
1529 /*
1530 * set by ngx_pcalloc():
1531 *
1532 * lcf->types = { NULL };
1533 * lcf->types_keys = NULL;
1534 */
1535
1536 lcf->charset = NGX_CONF_UNSET;
1537 lcf->source_charset = NGX_CONF_UNSET;
1538 lcf->override_charset = NGX_CONF_UNSET;
1539
1540 return lcf;
1541 }
1542
1543
1544 static char *
1545 ngx_http_charset_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1546 {
1547 ngx_http_charset_loc_conf_t *prev = parent;
1548 ngx_http_charset_loc_conf_t *conf = child;
1549
1550 ngx_uint_t i;
1551 ngx_http_charset_recode_t *recode;
1552 ngx_http_charset_main_conf_t *mcf;
1553
1554 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
1555 &prev->types_keys, &prev->types,
1556 ngx_http_charset_default_types)
1557 != NGX_OK)
1558 {
1559 return NGX_CONF_ERROR;
1560 }
1561
1562 ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0);
1563 ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_CHARSET_OFF);
1564 ngx_conf_merge_value(conf->source_charset, prev->source_charset,
1565 NGX_HTTP_CHARSET_OFF);
1566
1567 if (conf->charset == NGX_HTTP_CHARSET_OFF
1568 || conf->source_charset == NGX_HTTP_CHARSET_OFF
1569 || conf->charset == conf->source_charset)
1570 {
1571 return NGX_CONF_OK;
1572 }
1573
1574 if (conf->source_charset >= NGX_HTTP_CHARSET_VAR
1575 || conf->charset >= NGX_HTTP_CHARSET_VAR)
1576 {
1577 return NGX_CONF_OK;
1578 }
1579
1580 mcf = ngx_http_conf_get_module_main_conf(cf,
1581 ngx_http_charset_filter_module);
1582 recode = mcf->recodes.elts;
1583 for (i = 0; i < mcf->recodes.nelts; i++) {
1584 if (conf->source_charset == recode[i].src
1585 && conf->charset == recode[i].dst)
1586 {
1587 return NGX_CONF_OK;
1588 }
1589 }
1590
1591 recode = ngx_array_push(&mcf->recodes);
1592 if (recode == NULL) {
1593 return NGX_CONF_ERROR;
1594 }
1595
1596 recode->src = conf->source_charset;
1597 recode->dst = conf->charset;
1598
1599 return NGX_CONF_OK;
1600 }
1601
1602
1603 static ngx_int_t
1604 ngx_http_charset_postconfiguration(ngx_conf_t *cf)
1605 {
1606 u_char **src, **dst;
1607 ngx_int_t c;
1608 ngx_uint_t i, t;
1609 ngx_http_charset_t *charset;
1610 ngx_http_charset_recode_t *recode;
1611 ngx_http_charset_tables_t *tables;
1612 ngx_http_charset_main_conf_t *mcf;
1613
1614 mcf = ngx_http_conf_get_module_main_conf(cf,
1615 ngx_http_charset_filter_module);
1616
1617 recode = mcf->recodes.elts;
1618 tables = mcf->tables.elts;
1619 charset = mcf->charsets.elts;
1620
1621 for (i = 0; i < mcf->recodes.nelts; i++) {
1622
1623 c = recode[i].src;
1624
1625 for (t = 0; t < mcf->tables.nelts; t++) {
1626
1627 if (c == tables[t].src && recode[i].dst == tables[t].dst) {
1628 goto next;
1629 }
1630
1631 if (c == tables[t].dst && recode[i].dst == tables[t].src) {
1632 goto next;
1633 }
1634 }
1635
1636 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1637 "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
1638 &charset[c].name, &charset[recode[i].dst].name);
1639 return NGX_ERROR;
1640
1641 next:
1642 continue;
1643 }
1644
1645
1646 for (t = 0; t < mcf->tables.nelts; t++) {
1647
1648 src = charset[tables[t].src].tables;
1649
1650 if (src == NULL) {
1651 src = ngx_pcalloc(cf->pool, sizeof(u_char *) * mcf->charsets.nelts);
1652 if (src == NULL) {
1653 return NGX_ERROR;
1654 }
1655
1656 charset[tables[t].src].tables = src;
1657 }
1658
1659 dst = charset[tables[t].dst].tables;
1660
1661 if (dst == NULL) {
1662 dst = ngx_pcalloc(cf->pool, sizeof(u_char *) * mcf->charsets.nelts);
1663 if (dst == NULL) {
1664 return NGX_ERROR;
1665 }
1666
1667 charset[tables[t].dst].tables = dst;
1668 }
1669
1670 src[tables[t].dst] = tables[t].src2dst;
1671 dst[tables[t].src] = tables[t].dst2src;
1672 }
1673
1674 ngx_http_next_header_filter = ngx_http_top_header_filter;
1675 ngx_http_top_header_filter = ngx_http_charset_header_filter;
1676
1677 ngx_http_next_body_filter = ngx_http_top_body_filter;
1678 ngx_http_top_body_filter = ngx_http_charset_body_filter;
1679
1680 return NGX_OK;
1681 }
1682
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.