Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_xslt_filter_module.c @ 2153:6476e445d6ce
xsl:output's media-type and encoding support
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 05 Aug 2008 14:24:16 +0000 |
parents | b23e83f5b182 |
children | 4f48a2765da0 |
rev | line source |
---|---|
2139 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 #include <libxml/parser.h> | |
12 #include <libxml/tree.h> | |
13 #include <libxslt/xslt.h> | |
14 #include <libxslt/xsltInternals.h> | |
15 #include <libxslt/transform.h> | |
16 #include <libxslt/xsltutils.h> | |
17 | |
18 | |
19 #ifndef NGX_HTTP_XSLT_REUSE_DTD | |
20 #define NGX_HTTP_XSLT_REUSE_DTD 1 | |
21 #endif | |
22 | |
23 | |
24 typedef struct { | |
25 ngx_array_t *lengths; | |
26 ngx_array_t *values; | |
27 } ngx_http_xslt_param_t; | |
28 | |
29 | |
30 typedef struct { | |
31 xsltStylesheetPtr stylesheet; | |
32 ngx_array_t params; /* ngx_http_xslt_param_t */ | |
33 } ngx_http_xslt_sheet_t; | |
34 | |
35 | |
36 typedef struct { | |
37 xmlDtdPtr dtd; | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
38 ngx_array_t sheets; /* ngx_http_xslt_sheet_t */ |
2148 | 39 ngx_hash_t types; |
40 ngx_array_t *types_keys; | |
2139 | 41 } ngx_http_xslt_filter_conf_t; |
42 | |
43 | |
44 typedef struct { | |
45 xmlDocPtr doc; | |
46 xmlParserCtxtPtr ctxt; | |
47 xmlSAXHandler *sax; | |
48 ngx_http_request_t *request; | |
49 ngx_array_t params; | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
50 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
51 ngx_uint_t done; /* unsigned done:1; */ |
2139 | 52 } ngx_http_xslt_filter_ctx_t; |
53 | |
54 | |
55 static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r, | |
56 ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); | |
57 static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r); | |
58 static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r, | |
59 ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); | |
60 | |
61 | |
62 static void ngx_http_xslt_sax_start_document(void *data); | |
63 static void ngx_http_xslt_sax_end_document(void *data); | |
64 static void ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name, | |
65 const xmlChar *externalId, const xmlChar *systemId); | |
66 static void ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name, | |
67 const xmlChar *externalId, const xmlChar *systemId); | |
68 static void ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name, | |
69 int type, const xmlChar *publicId, const xmlChar *systemId, | |
70 xmlChar *content); | |
71 static void ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem, | |
72 const xmlChar *fullname, int type, int def, const xmlChar *defaultValue, | |
73 xmlEnumerationPtr tree); | |
74 static void ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name, | |
75 int type, xmlElementContentPtr content); | |
76 static void ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name, | |
77 const xmlChar *publicId, const xmlChar *systemId); | |
78 static void ngx_http_xslt_sax_unparsed_entity_decl(void *data, | |
79 const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, | |
80 const xmlChar *notationName); | |
81 static void ngx_http_xslt_sax_start_element(void *data, | |
82 const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, | |
83 int nb_namespaces, const xmlChar **namespaces, int nb_attributes, | |
84 int nb_defaulted, const xmlChar **attributes); | |
85 static void ngx_http_xslt_sax_end_element(void *data, | |
86 const xmlChar * localname ATTRIBUTE_UNUSED, | |
87 const xmlChar * prefix ATTRIBUTE_UNUSED, | |
88 const xmlChar * URI ATTRIBUTE_UNUSED); | |
89 static void ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len); | |
90 static void ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p, | |
91 int len); | |
92 static xmlEntityPtr ngx_http_xslt_sax_get_entity(void *data, | |
93 const xmlChar *name); | |
94 static xmlEntityPtr ngx_http_xslt_sax_get_parameter_entity(void *data, | |
95 const xmlChar *name); | |
96 static xmlParserInputPtr ngx_http_xslt_sax_resolve_entity(void *data, | |
97 const xmlChar *publicId, const xmlChar *systemId); | |
98 static void ngx_http_xslt_sax_reference(void *data, const xmlChar *name); | |
99 static void ngx_http_xslt_sax_comment(void *data, const xmlChar *value); | |
100 static void ngx_http_xslt_sax_processing_instruction(void *data, | |
101 const xmlChar *target, const xmlChar *pidata); | |
102 static int ngx_http_xslt_sax_is_standalone(void *data); | |
103 static int ngx_http_xslt_sax_has_internal_subset(void *data); | |
104 static int ngx_http_xslt_sax_has_external_subset(void *data); | |
105 static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...); | |
106 | |
107 | |
108 static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r, | |
109 ngx_http_xslt_filter_ctx_t *ctx); | |
110 static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r, | |
111 ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params); | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
112 static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
113 static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s); |
2139 | 114 static void ngx_http_xslt_cleanup(void *data); |
115 | |
116 static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, | |
117 void *conf); | |
118 static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, | |
119 void *conf); | |
120 static void ngx_http_xslt_cleanup_stylesheet(void *data); | |
121 static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf); | |
122 static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, | |
123 void *child); | |
124 static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf); | |
125 | |
126 | |
127 ngx_str_t ngx_http_xslt_default_types[] = { | |
128 ngx_string("text/xml"), | |
129 ngx_null_string | |
130 }; | |
131 | |
132 | |
133 static ngx_command_t ngx_http_xslt_filter_commands[] = { | |
134 | |
135 { ngx_string("xml_entities"), | |
2150
50cede290146
fix xslt module context levels
Igor Sysoev <igor@sysoev.ru>
parents:
2148
diff
changeset
|
136 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
2139 | 137 ngx_http_xslt_entities, |
138 NGX_HTTP_LOC_CONF_OFFSET, | |
139 0, | |
140 NULL }, | |
141 | |
142 { ngx_string("xslt_stylesheet"), | |
2151
c8331f70d799
xslt_stylesheet should be valid for location only
Igor Sysoev <igor@sysoev.ru>
parents:
2150
diff
changeset
|
143 NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, |
2139 | 144 ngx_http_xslt_stylesheet, |
145 NGX_HTTP_LOC_CONF_OFFSET, | |
146 0, | |
147 NULL }, | |
148 | |
149 { ngx_string("xslt_types"), | |
2150
50cede290146
fix xslt module context levels
Igor Sysoev <igor@sysoev.ru>
parents:
2148
diff
changeset
|
150 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, |
2139 | 151 ngx_http_types_slot, |
152 NGX_HTTP_LOC_CONF_OFFSET, | |
2148 | 153 offsetof(ngx_http_xslt_filter_conf_t, types_keys), |
2139 | 154 &ngx_http_xslt_default_types[0] }, |
155 | |
156 ngx_null_command | |
157 }; | |
158 | |
159 | |
160 static ngx_http_module_t ngx_http_xslt_filter_module_ctx = { | |
161 NULL, /* preconfiguration */ | |
162 ngx_http_xslt_filter_init, /* postconfiguration */ | |
163 | |
164 NULL, /* create main configuration */ | |
165 NULL, /* init main configuration */ | |
166 | |
167 NULL, /* create server configuration */ | |
168 NULL, /* merge server configuration */ | |
169 | |
170 ngx_http_xslt_filter_create_conf, /* create location configuration */ | |
171 ngx_http_xslt_filter_merge_conf /* merge location configuration */ | |
172 }; | |
173 | |
174 | |
175 ngx_module_t ngx_http_xslt_filter_module = { | |
176 NGX_MODULE_V1, | |
177 &ngx_http_xslt_filter_module_ctx, /* module context */ | |
178 ngx_http_xslt_filter_commands, /* module directives */ | |
179 NGX_HTTP_MODULE, /* module type */ | |
180 NULL, /* init master */ | |
181 NULL, /* init module */ | |
182 NULL, /* init process */ | |
183 NULL, /* init thread */ | |
184 NULL, /* exit thread */ | |
185 NULL, /* exit process */ | |
186 NULL, /* exit master */ | |
187 NGX_MODULE_V1_PADDING | |
188 }; | |
189 | |
190 | |
191 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; | |
192 static ngx_http_output_body_filter_pt ngx_http_next_body_filter; | |
193 | |
194 | |
195 static ngx_int_t | |
196 ngx_http_xslt_header_filter(ngx_http_request_t *r) | |
197 { | |
198 ngx_http_xslt_filter_ctx_t *ctx; | |
199 ngx_http_xslt_filter_conf_t *conf; | |
200 | |
201 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
202 "xslt filter header"); | |
203 | |
204 if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { | |
205 return ngx_http_next_header_filter(r); | |
206 } | |
207 | |
208 conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); | |
209 | |
210 if (conf->sheets.nelts == 0 | |
2148 | 211 || ngx_http_test_content_type(r, &conf->types) == NULL) |
2139 | 212 { |
213 return ngx_http_next_header_filter(r); | |
214 } | |
215 | |
216 ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module); | |
217 | |
218 if (ctx) { | |
219 return ngx_http_next_header_filter(r); | |
220 } | |
221 | |
222 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xslt_filter_ctx_t)); | |
223 if (ctx == NULL) { | |
224 return NGX_ERROR; | |
225 } | |
226 | |
227 ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module); | |
228 | |
229 r->main_filter_need_in_memory = 1; | |
230 | |
231 return NGX_OK; | |
232 } | |
233 | |
234 | |
235 static ngx_int_t | |
236 ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
237 { | |
238 ngx_chain_t *cl; | |
239 ngx_http_xslt_filter_ctx_t *ctx; | |
240 | |
241 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
242 "xslt filter body"); | |
243 | |
244 if (in == NULL) { | |
245 return ngx_http_next_body_filter(r, in); | |
246 } | |
247 | |
248 ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module); | |
249 | |
250 if (ctx == NULL || ctx->done) { | |
251 return ngx_http_next_body_filter(r, in); | |
252 } | |
253 | |
254 for (cl = in; cl; cl = cl->next) { | |
255 | |
256 if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) { | |
257 | |
258 if (ctx->ctxt->myDoc){ | |
259 | |
260 #if (NGX_HTTP_XSLT_REUSE_DTD) | |
261 ctx->ctxt->myDoc->extSubset = NULL; | |
262 #endif | |
263 xmlFreeDoc(ctx->ctxt->myDoc); | |
264 } | |
265 | |
266 xmlFreeParserCtxt(ctx->ctxt); | |
267 | |
268 return ngx_http_xslt_send(r, ctx, NULL); | |
269 } | |
270 | |
271 if (cl->buf->last_buf) { | |
272 | |
273 ctx->doc = ctx->ctxt->myDoc; | |
274 | |
275 #if (NGX_HTTP_XSLT_REUSE_DTD) | |
276 ctx->doc->extSubset = NULL; | |
277 #endif | |
278 | |
279 xmlFreeParserCtxt(ctx->ctxt); | |
280 | |
281 if (ctx->ctxt->wellFormed) { | |
282 return ngx_http_xslt_send(r, ctx, | |
283 ngx_http_xslt_apply_stylesheet(r, ctx)); | |
284 } | |
285 | |
286 xmlFreeDoc(ctx->doc); | |
287 | |
288 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
289 "not well formed XML document"); | |
290 | |
291 return ngx_http_xslt_send(r, ctx, NULL); | |
292 } | |
293 } | |
294 | |
295 return NGX_OK; | |
296 } | |
297 | |
298 | |
299 static ngx_int_t | |
300 ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, | |
301 ngx_buf_t *b) | |
302 { | |
303 ngx_int_t rc; | |
304 ngx_chain_t out; | |
305 ngx_pool_cleanup_t *cln; | |
306 | |
307 ctx->done = 1; | |
308 | |
309 if (b == NULL) { | |
310 return ngx_http_xslt_filter_internal_error(r); | |
311 } | |
312 | |
313 cln = ngx_pool_cleanup_add(r->pool, 0); | |
314 | |
315 if (cln == NULL) { | |
316 ngx_free(b->pos); | |
317 return ngx_http_special_response_handler(r, | |
318 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
319 } | |
320 | |
321 r->headers_out.content_length_n = b->last - b->pos; | |
322 | |
323 if (r->headers_out.content_length) { | |
324 r->headers_out.content_length->hash = 0; | |
325 r->headers_out.content_length = NULL; | |
326 } | |
327 | |
328 r->allow_ranges = 1; | |
329 | |
330 rc = ngx_http_next_header_filter(r); | |
331 | |
332 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { | |
333 ngx_free(b->pos); | |
334 return rc; | |
335 } | |
336 | |
337 cln->handler = ngx_http_xslt_cleanup; | |
338 cln->data = b->pos; | |
339 | |
340 out.buf = b; | |
341 out.next = NULL; | |
342 | |
343 return ngx_http_next_body_filter(r, &out); | |
344 } | |
345 | |
346 | |
347 static ngx_int_t | |
348 ngx_http_xslt_filter_internal_error(ngx_http_request_t *r) | |
349 { | |
350 ngx_int_t rc; | |
351 | |
352 /* clear the modules contexts */ | |
353 ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); | |
354 | |
355 rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
356 | |
357 /* NGX_ERROR resets any pending data */ | |
358 | |
359 return (rc == NGX_OK) ? NGX_ERROR : rc; | |
360 } | |
361 | |
362 | |
363 static ngx_int_t | |
364 ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, | |
365 ngx_buf_t *b) | |
366 { | |
367 int err; | |
368 xmlSAXHandler *sax; | |
369 xmlParserCtxtPtr ctxt; | |
370 | |
371 if (ctx->ctxt == NULL) { | |
372 | |
373 ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); | |
374 if (ctxt == NULL) { | |
375 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
376 "xmlCreatePushParserCtxt() failed"); | |
377 return NGX_ERROR; | |
378 } | |
379 | |
380 ctx->sax = ngx_palloc(r->pool, sizeof(xmlSAXHandler)); | |
381 if (ctx->sax == NULL) { | |
382 return NGX_ERROR; | |
383 } | |
384 | |
385 sax = ctxt->sax; | |
386 | |
387 ngx_memcpy(ctx->sax, sax, sizeof(xmlSAXHandler)); | |
388 | |
389 sax->startDocument = ngx_http_xslt_sax_start_document; | |
390 sax->endDocument = ngx_http_xslt_sax_end_document; | |
391 | |
392 sax->internalSubset = ngx_http_xslt_sax_internal_subset; | |
393 sax->externalSubset = ngx_http_xslt_sax_external_subset; | |
394 sax->entityDecl = ngx_http_xslt_sax_entity_decl; | |
395 sax->attributeDecl = ngx_http_xslt_sax_attribute_decl; | |
396 sax->elementDecl = ngx_http_xslt_sax_element_decl; | |
397 sax->notationDecl = ngx_http_xslt_sax_notation_decl; | |
398 sax->unparsedEntityDecl = ngx_http_xslt_sax_unparsed_entity_decl; | |
399 sax->setDocumentLocator = NULL; | |
400 | |
401 sax->startElementNs = ngx_http_xslt_sax_start_element; | |
402 sax->endElementNs = ngx_http_xslt_sax_end_element; | |
403 | |
404 sax->characters = ngx_http_xslt_sax_characters; | |
405 sax->ignorableWhitespace = ngx_http_xslt_sax_characters; | |
406 sax->cdataBlock = ngx_http_xslt_sax_cdata_block; | |
407 sax->getEntity = ngx_http_xslt_sax_get_entity; | |
408 sax->resolveEntity = ngx_http_xslt_sax_resolve_entity; | |
409 sax->getParameterEntity = ngx_http_xslt_sax_get_parameter_entity; | |
410 sax->reference = ngx_http_xslt_sax_reference; | |
411 sax->comment = ngx_http_xslt_sax_comment; | |
412 sax->processingInstruction = ngx_http_xslt_sax_processing_instruction; | |
413 | |
414 sax->isStandalone = ngx_http_xslt_sax_is_standalone; | |
415 sax->hasInternalSubset = ngx_http_xslt_sax_has_internal_subset; | |
416 sax->hasExternalSubset = ngx_http_xslt_sax_has_external_subset; | |
417 | |
418 sax->warning = NULL; | |
419 sax->error = ngx_http_xslt_sax_error; | |
420 sax->fatalError = ngx_http_xslt_sax_error; | |
421 | |
422 ctxt->userData = ctx; | |
423 | |
424 ctxt->replaceEntities = 1; | |
425 ctxt->loadsubset = 1; | |
426 | |
427 ctx->ctxt = ctxt; | |
428 ctx->request = r; | |
429 } | |
430 | |
431 err = xmlParseChunk(ctx->ctxt, (char *) b->pos, | |
432 (int) (b->last - b->pos), b->last_buf); | |
433 | |
434 if (err == 0) { | |
435 b->pos = b->last; | |
436 return NGX_OK; | |
437 } | |
438 | |
439 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
440 "xmlParseChunk() failed, error:%d", err); | |
441 | |
442 return NGX_ERROR; | |
443 } | |
444 | |
445 | |
446 static void | |
447 ngx_http_xslt_sax_start_document(void *data) | |
448 { | |
449 ngx_http_xslt_filter_ctx_t *ctx = data; | |
450 | |
451 ctx->sax->startDocument(ctx->ctxt); | |
452 } | |
453 | |
454 | |
455 static void | |
456 ngx_http_xslt_sax_end_document(void *data) | |
457 { | |
458 ngx_http_xslt_filter_ctx_t *ctx = data; | |
459 | |
460 ctx->sax->endDocument(ctx->ctxt); | |
461 } | |
462 | |
463 | |
464 static void | |
465 ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name, | |
466 const xmlChar *externalId, const xmlChar *systemId) | |
467 { | |
468 ngx_http_xslt_filter_ctx_t *ctx = data; | |
469 | |
470 ctx->sax->internalSubset(ctx->ctxt, name, externalId, systemId); | |
471 } | |
472 | |
473 | |
474 static void | |
475 ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name, | |
476 const xmlChar *externalId, const xmlChar *systemId) | |
477 { | |
478 ngx_http_xslt_filter_ctx_t *ctx = data; | |
479 | |
480 xmlDocPtr doc; | |
481 xmlDtdPtr dtd; | |
482 ngx_http_request_t *r; | |
483 ngx_http_xslt_filter_conf_t *conf; | |
484 | |
485 r = ctx->request; | |
486 | |
487 conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); | |
488 | |
489 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
490 "xslt filter extSubset: \"%s\" \"%s\" \"%s\"", | |
491 name ? name : (xmlChar *) "", | |
492 externalId ? externalId : (xmlChar *) "", | |
493 systemId ? systemId : (xmlChar *) ""); | |
494 | |
495 doc = ctx->ctxt->myDoc; | |
496 | |
497 #if (NGX_HTTP_XSLT_REUSE_DTD) | |
498 | |
499 dtd = conf->dtd; | |
500 | |
501 #else | |
502 | |
503 dtd = xmlCopyDtd(conf->dtd); | |
504 if (dtd == NULL) { | |
505 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
506 "xmlCopyDtd() failed"); | |
507 return; | |
508 } | |
509 | |
510 if (doc->children == NULL) { | |
511 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); | |
512 | |
513 } else { | |
514 xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd); | |
515 } | |
516 | |
517 #endif | |
518 | |
519 doc->extSubset = dtd; | |
520 } | |
521 | |
522 | |
523 static void | |
524 ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name, int type, | |
525 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) | |
526 { | |
527 ngx_http_xslt_filter_ctx_t *ctx = data; | |
528 | |
529 ctx->sax->entityDecl(ctx->ctxt, name, type, publicId, systemId, content); | |
530 } | |
531 | |
532 | |
533 static void | |
534 ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem, | |
535 const xmlChar *fullname, int type, int def, const xmlChar *defaultValue, | |
536 xmlEnumerationPtr tree) | |
537 { | |
538 ngx_http_xslt_filter_ctx_t *ctx = data; | |
539 | |
540 ctx->sax->attributeDecl(ctx->ctxt, elem, fullname, type, def, defaultValue, | |
541 tree); | |
542 } | |
543 | |
544 | |
545 static void | |
546 ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name, int type, | |
547 xmlElementContentPtr content) | |
548 { | |
549 ngx_http_xslt_filter_ctx_t *ctx = data; | |
550 | |
551 ctx->sax->elementDecl(ctx->ctxt, name, type, content); | |
552 } | |
553 | |
554 | |
555 static void | |
556 ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name, | |
557 const xmlChar *publicId, const xmlChar *systemId) | |
558 { | |
559 ngx_http_xslt_filter_ctx_t *ctx = data; | |
560 | |
561 ctx->sax->notationDecl(ctx->ctxt, name, publicId, systemId); | |
562 } | |
563 | |
564 | |
565 static void | |
566 ngx_http_xslt_sax_unparsed_entity_decl(void *data, const xmlChar *name, | |
567 const xmlChar *publicId, const xmlChar *systemId, | |
568 const xmlChar *notationName) | |
569 { | |
570 ngx_http_xslt_filter_ctx_t *ctx = data; | |
571 | |
572 ctx->sax->unparsedEntityDecl(ctx->ctxt, name, publicId, systemId, | |
573 notationName); | |
574 } | |
575 | |
576 | |
577 static void | |
578 ngx_http_xslt_sax_start_element(void *data, const xmlChar *localname, | |
579 const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, | |
580 const xmlChar **namespaces, int nb_attributes, int nb_defaulted, | |
581 const xmlChar **attributes) | |
582 { | |
583 ngx_http_xslt_filter_ctx_t *ctx = data; | |
584 | |
585 ctx->sax->startElementNs(ctx->ctxt, localname, prefix, URI, nb_namespaces, | |
586 namespaces, nb_attributes, nb_defaulted, attributes); | |
587 } | |
588 | |
589 | |
590 static void | |
591 ngx_http_xslt_sax_end_element(void *data, | |
592 const xmlChar * localname ATTRIBUTE_UNUSED, | |
593 const xmlChar * prefix ATTRIBUTE_UNUSED, | |
594 const xmlChar * URI ATTRIBUTE_UNUSED) | |
595 { | |
596 ngx_http_xslt_filter_ctx_t *ctx = data; | |
597 | |
598 ctx->sax->endElementNs(ctx->ctxt, localname, prefix, URI); | |
599 } | |
600 | |
601 | |
602 static void | |
603 ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len) | |
604 { | |
605 ngx_http_xslt_filter_ctx_t *ctx = data; | |
606 | |
607 ctx->sax->characters(ctx->ctxt, p, len); | |
608 } | |
609 | |
610 | |
611 static void | |
612 ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p, int len) | |
613 { | |
614 ngx_http_xslt_filter_ctx_t *ctx = data; | |
615 | |
616 ctx->sax->cdataBlock(ctx->ctxt, p, len); | |
617 } | |
618 | |
619 | |
620 static xmlEntityPtr | |
621 ngx_http_xslt_sax_get_entity(void *data, const xmlChar *name) | |
622 { | |
623 ngx_http_xslt_filter_ctx_t *ctx = data; | |
624 | |
625 return ctx->sax->getEntity(ctx->ctxt, name); | |
626 } | |
627 | |
628 | |
629 static xmlEntityPtr | |
630 ngx_http_xslt_sax_get_parameter_entity(void *data, const xmlChar *name) | |
631 { | |
632 ngx_http_xslt_filter_ctx_t *ctx = data; | |
633 | |
634 return ctx->sax->getParameterEntity(ctx->ctxt, name); | |
635 } | |
636 | |
637 | |
638 static xmlParserInputPtr | |
639 ngx_http_xslt_sax_resolve_entity(void *data, const xmlChar *publicId, | |
640 const xmlChar *systemId) | |
641 { | |
642 ngx_http_xslt_filter_ctx_t *ctx = data; | |
643 | |
644 return ctx->sax->resolveEntity(ctx->ctxt, publicId, systemId); | |
645 } | |
646 | |
647 | |
648 static void | |
649 ngx_http_xslt_sax_reference(void *data, const xmlChar *name) | |
650 { | |
651 ngx_http_xslt_filter_ctx_t *ctx = data; | |
652 | |
653 ctx->sax->reference(ctx->ctxt, name); | |
654 } | |
655 | |
656 | |
657 static void | |
658 ngx_http_xslt_sax_comment(void *data, const xmlChar *value) | |
659 { | |
660 ngx_http_xslt_filter_ctx_t *ctx = data; | |
661 | |
662 ctx->sax->comment(ctx->ctxt, value); | |
663 } | |
664 | |
665 | |
666 static void | |
667 ngx_http_xslt_sax_processing_instruction(void *data, const xmlChar *target, | |
668 const xmlChar *pidata) | |
669 { | |
670 ngx_http_xslt_filter_ctx_t *ctx = data; | |
671 | |
672 ctx->sax->processingInstruction(ctx->ctxt, target, pidata); | |
673 } | |
674 | |
675 | |
676 static int | |
677 ngx_http_xslt_sax_is_standalone(void *data) | |
678 { | |
679 ngx_http_xslt_filter_ctx_t *ctx = data; | |
680 | |
681 return ctx->sax->isStandalone(ctx->ctxt); | |
682 } | |
683 | |
684 | |
685 static int | |
686 ngx_http_xslt_sax_has_internal_subset(void *data) | |
687 { | |
688 ngx_http_xslt_filter_ctx_t *ctx = data; | |
689 | |
690 return ctx->sax->hasInternalSubset(ctx->ctxt); | |
691 } | |
692 | |
693 | |
694 static int | |
695 ngx_http_xslt_sax_has_external_subset(void *data) | |
696 { | |
697 ngx_http_xslt_filter_ctx_t *ctx = data; | |
698 | |
699 return ctx->sax->hasExternalSubset(ctx->ctxt); | |
700 } | |
701 | |
702 | |
703 static void ngx_cdecl | |
704 ngx_http_xslt_sax_error(void *data, const char *msg, ...) | |
705 { | |
706 ngx_http_xslt_filter_ctx_t *ctx = data; | |
707 | |
708 size_t n; | |
709 va_list args; | |
710 u_char buf[NGX_MAX_ERROR_STR]; | |
711 | |
712 buf[0] = '\0'; | |
713 | |
714 va_start(args, msg); | |
715 n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args); | |
716 va_end(args); | |
717 | |
718 while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ } | |
719 | |
720 ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, | |
721 "libxml2 error: \"%*s\"", n, buf); | |
722 } | |
723 | |
724 | |
725 static ngx_buf_t * | |
726 ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r, | |
727 ngx_http_xslt_filter_ctx_t *ctx) | |
728 { | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
729 int len, rc, doc_type; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
730 u_char *type, *encoding; |
2139 | 731 ngx_buf_t *b; |
732 ngx_uint_t i; | |
733 xmlChar *buf; | |
734 xmlDocPtr doc, res; | |
735 ngx_http_xslt_sheet_t *sheet; | |
736 ngx_http_xslt_filter_conf_t *conf; | |
737 | |
738 conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); | |
739 sheet = conf->sheets.elts; | |
740 doc = ctx->doc; | |
741 | |
742 /* preallocate array for 4 params */ | |
743 | |
744 if (ngx_array_init(&ctx->params, r->pool, 4 * 2 + 1, sizeof(char *)) | |
745 != NGX_OK) | |
746 { | |
747 xmlFreeDoc(doc); | |
748 return NULL; | |
749 } | |
750 | |
751 for (i = 0; i < conf->sheets.nelts; i++) { | |
752 | |
753 if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) { | |
754 xmlFreeDoc(doc); | |
755 return NULL; | |
756 } | |
757 | |
758 res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts); | |
759 | |
760 xmlFreeDoc(doc); | |
761 | |
762 if (res == NULL) { | |
763 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
764 "xsltApplyStylesheet() failed"); | |
765 return NULL; | |
766 } | |
767 | |
768 doc = res; | |
769 | |
770 /* reset array elements */ | |
771 ctx->params.nelts = 0; | |
772 } | |
773 | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
774 /* there must be at least one stylesheet */ |
2139 | 775 |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
776 type = ngx_http_xslt_content_type(sheet[i - 1].stylesheet); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
777 encoding = ngx_http_xslt_encoding(sheet[i - 1].stylesheet); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
778 doc_type = doc->type; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
779 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
780 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
781 "xslt filter type: %d t:%s e:%s", |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
782 doc_type, type ? type : (u_char *) "(null)", |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
783 encoding ? encoding : (u_char *) "(null)"); |
2139 | 784 |
785 rc = xsltSaveResultToString(&buf, &len, doc, sheet[i - 1].stylesheet); | |
786 | |
787 xmlFreeDoc(doc); | |
788 | |
789 if (rc != 0) { | |
790 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
791 "xsltSaveResultToString() failed"); | |
792 return NULL; | |
793 } | |
794 | |
795 if (len == 0) { | |
796 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
797 "xsltSaveResultToString() returned zero-length result"); | |
798 return NULL; | |
799 } | |
800 | |
801 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); | |
802 if (b == NULL) { | |
803 ngx_free(buf); | |
804 return NULL; | |
805 } | |
806 | |
807 b->pos = buf; | |
808 b->last = buf + len; | |
809 b->memory = 1; | |
810 b->last_buf = 1; | |
811 | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
812 if (type) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
813 len = ngx_strlen(type); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
814 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
815 r->headers_out.content_type_len = len; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
816 r->headers_out.content_type.len = len; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
817 r->headers_out.content_type.data = type; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
818 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
819 } else if (doc_type == XML_HTML_DOCUMENT_NODE) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
820 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
821 r->headers_out.content_type_len = sizeof("text/html") - 1; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
822 r->headers_out.content_type.len = sizeof("text/html") - 1; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
823 r->headers_out.content_type.data = (u_char *) "text/html"; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
824 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
825 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
826 if (encoding) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
827 r->headers_out.charset.len = ngx_strlen(encoding); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
828 r->headers_out.charset.data = encoding; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
829 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
830 |
2139 | 831 return b; |
832 } | |
833 | |
834 | |
835 static ngx_int_t | |
836 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, | |
837 ngx_array_t *params) | |
838 { | |
839 u_char *p, *last, *value, *dst, *src, **s; | |
840 size_t len; | |
841 ngx_uint_t i; | |
842 ngx_str_t string; | |
843 ngx_http_xslt_param_t *param; | |
844 | |
845 param = params->elts; | |
846 | |
847 for (i = 0; i < params->nelts; i++) { | |
848 | |
849 if (ngx_http_script_run(r, &string, param[i].lengths->elts, 1, | |
850 param[i].values->elts) | |
851 == NULL) | |
852 { | |
853 return NGX_ERROR; | |
854 } | |
855 | |
856 last = string.data + string.len - 1; | |
857 *last = '\0'; | |
858 | |
859 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
860 "xslt filter param: \"%s\"", string.data); | |
861 | |
862 p = string.data; | |
863 | |
864 while (p && *p) { | |
865 | |
866 value = p; | |
867 p = (u_char *) ngx_strchr(p, '='); | |
868 if (p == NULL) { | |
869 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
870 "invalid libxslt parameter \"%s\"", value); | |
871 return NGX_ERROR; | |
872 } | |
873 *p++ = '\0'; | |
874 | |
875 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
876 "xslt filter param name: \"%s\"", value); | |
877 | |
878 s = ngx_array_push(&ctx->params); | |
879 if (s == NULL) { | |
880 return NGX_ERROR; | |
881 } | |
882 | |
883 *s = value; | |
884 | |
885 value = p; | |
886 p = (u_char *) ngx_strchr(p, ':'); | |
887 | |
888 if (p) { | |
889 len = p - value; | |
890 *p++ = '\0'; | |
891 | |
892 } else { | |
893 len = last - value; | |
894 } | |
895 | |
896 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
897 "xslt filter param value: \"%s\"", value); | |
898 | |
899 dst = value; | |
900 src = value; | |
901 | |
902 ngx_unescape_uri(&dst, &src, len, 0); | |
903 | |
904 *dst = '\0'; | |
905 | |
906 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
907 "xslt filter param unescaped: \"%s\"", value); | |
908 | |
909 s = ngx_array_push(&ctx->params); | |
910 if (s == NULL) { | |
911 return NGX_ERROR; | |
912 } | |
913 | |
914 *s = value; | |
915 } | |
916 } | |
917 | |
918 s = ngx_array_push(&ctx->params); | |
919 if (s == NULL) { | |
920 return NGX_ERROR; | |
921 } | |
922 | |
923 *s = NULL; | |
924 | |
925 return NGX_OK; | |
926 } | |
927 | |
928 | |
2153
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
929 static u_char * |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
930 ngx_http_xslt_content_type(xsltStylesheetPtr s) |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
931 { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
932 u_char *type; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
933 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
934 if (s->mediaType) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
935 return s->mediaType; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
936 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
937 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
938 for (s = s->imports; s; s = s->next) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
939 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
940 type = ngx_http_xslt_content_type(s); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
941 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
942 if (type) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
943 return type; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
944 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
945 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
946 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
947 return NULL; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
948 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
949 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
950 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
951 static u_char * |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
952 ngx_http_xslt_encoding(xsltStylesheetPtr s) |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
953 { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
954 u_char *encoding; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
955 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
956 if (s->encoding) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
957 return s->encoding; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
958 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
959 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
960 for (s = s->imports; s; s = s->next) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
961 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
962 encoding = ngx_http_xslt_encoding(s); |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
963 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
964 if (encoding) { |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
965 return encoding; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
966 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
967 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
968 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
969 return NULL; |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
970 } |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
971 |
6476e445d6ce
xsl:output's media-type and encoding support
Igor Sysoev <igor@sysoev.ru>
parents:
2152
diff
changeset
|
972 |
2139 | 973 static void |
974 ngx_http_xslt_cleanup(void *data) | |
975 { | |
976 ngx_free(data); | |
977 } | |
978 | |
979 | |
980 static char * | |
981 ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
982 { | |
983 ngx_http_xslt_filter_conf_t *xlcf = conf; | |
984 | |
985 ngx_str_t *value; | |
986 | |
987 if (xlcf->dtd) { | |
988 return "is duplicate"; | |
989 } | |
990 | |
991 value = cf->args->elts; | |
992 | |
993 xlcf->dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data); | |
994 | |
995 if (xlcf->dtd == NULL) { | |
996 ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "xmlParseDTD() failed"); | |
997 return NGX_CONF_ERROR; | |
998 } | |
999 | |
1000 return NGX_CONF_OK; | |
1001 } | |
1002 | |
1003 | |
1004 | |
1005 static char * | |
1006 ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
1007 { | |
1008 ngx_http_xslt_filter_conf_t *xlcf = conf; | |
1009 | |
1010 ngx_str_t *value; | |
1011 ngx_uint_t i, n; | |
1012 ngx_pool_cleanup_t *cln; | |
1013 ngx_http_xslt_sheet_t *sheet; | |
1014 ngx_http_xslt_param_t *param; | |
1015 ngx_http_script_compile_t sc; | |
1016 | |
1017 value = cf->args->elts; | |
1018 | |
1019 if (xlcf->sheets.elts == NULL) { | |
1020 if (ngx_array_init(&xlcf->sheets, cf->pool, 1, | |
1021 sizeof(ngx_http_xslt_sheet_t)) | |
1022 != NGX_OK) | |
1023 { | |
1024 return NGX_CONF_ERROR; | |
1025 } | |
1026 } | |
1027 | |
1028 sheet = ngx_array_push(&xlcf->sheets); | |
1029 if (sheet == NULL) { | |
1030 return NGX_CONF_ERROR; | |
1031 } | |
1032 | |
1033 ngx_memzero(sheet, sizeof(ngx_http_xslt_sheet_t)); | |
1034 | |
1035 if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { | |
1036 return NGX_CONF_ERROR; | |
1037 } | |
1038 | |
1039 cln = ngx_pool_cleanup_add(cf->pool, 0); | |
1040 if (cln == NULL) { | |
1041 return NGX_CONF_ERROR; | |
1042 } | |
1043 | |
1044 sheet->stylesheet = xsltParseStylesheetFile(value[1].data); | |
1045 if (sheet->stylesheet == NULL) { | |
1046 ngx_conf_log_error(NGX_LOG_ERR, cf, 0, | |
1047 "xsltParseStylesheetFile(\"%s\") failed", | |
1048 value[1].data); | |
1049 return NGX_CONF_ERROR; | |
1050 } | |
1051 | |
1052 cln->handler = ngx_http_xslt_cleanup_stylesheet; | |
1053 cln->data = sheet->stylesheet; | |
1054 | |
1055 n = cf->args->nelts; | |
1056 | |
1057 if (n == 2) { | |
1058 return NGX_CONF_OK; | |
1059 } | |
1060 | |
1061 if (ngx_array_init(&sheet->params, cf->pool, n - 2, | |
1062 sizeof(ngx_http_xslt_param_t)) | |
1063 != NGX_OK) | |
1064 { | |
1065 return NGX_CONF_ERROR; | |
1066 } | |
1067 | |
1068 for (i = 2; i < n; i++) { | |
1069 | |
1070 param = ngx_array_push(&sheet->params); | |
1071 if (param == NULL) { | |
1072 return NGX_CONF_ERROR; | |
1073 } | |
1074 | |
1075 param->lengths = NULL; | |
1076 param->values = NULL; | |
1077 | |
1078 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
1079 | |
1080 sc.cf = cf; | |
1081 sc.source = &value[i]; | |
1082 sc.lengths = ¶m->lengths; | |
1083 sc.values = ¶m->values; | |
1084 sc.variables = ngx_http_script_variables_count(&value[i]); | |
1085 sc.complete_lengths = 1; | |
1086 sc.complete_values = 1; | |
1087 | |
1088 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
1089 return NGX_CONF_ERROR; | |
1090 } | |
1091 } | |
1092 | |
1093 return NGX_CONF_OK; | |
1094 } | |
1095 | |
1096 | |
1097 static void | |
1098 ngx_http_xslt_cleanup_stylesheet(void *data) | |
1099 { | |
1100 xsltStylesheetPtr stylesheet = data; | |
1101 | |
1102 xsltFreeStylesheet(stylesheet); | |
1103 } | |
1104 | |
1105 | |
1106 | |
1107 static void * | |
1108 ngx_http_xslt_filter_create_conf(ngx_conf_t *cf) | |
1109 { | |
1110 ngx_http_xslt_filter_conf_t *conf; | |
1111 | |
1112 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_conf_t)); | |
1113 if (conf == NULL) { | |
1114 return NGX_CONF_ERROR; | |
1115 } | |
1116 | |
1117 /* | |
1118 * set by ngx_pcalloc(): | |
1119 * | |
2148 | 1120 * conf->dtd = NULL; |
1121 * conf->sheets = { NULL }; | |
1122 * conf->types = { NULL }; | |
1123 * conf->types_keys = NULL; | |
2139 | 1124 */ |
1125 | |
1126 return conf; | |
1127 } | |
1128 | |
1129 | |
1130 static char * | |
1131 ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
1132 { | |
1133 ngx_http_xslt_filter_conf_t *prev = parent; | |
1134 ngx_http_xslt_filter_conf_t *conf = child; | |
1135 | |
1136 if (conf->dtd == NULL) { | |
1137 conf->dtd = prev->dtd; | |
1138 } | |
1139 | |
1140 if (conf->sheets.nelts == 0) { | |
1141 conf->sheets = prev->sheets; | |
1142 } | |
1143 | |
2148 | 1144 if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, |
1145 prev->types_keys, &prev->types, | |
1146 ngx_http_xslt_default_types) | |
2139 | 1147 != NGX_OK) |
1148 { | |
1149 return NGX_CONF_ERROR; | |
1150 } | |
1151 | |
1152 return NGX_CONF_OK; | |
1153 } | |
1154 | |
1155 | |
1156 static ngx_int_t | |
1157 ngx_http_xslt_filter_init(ngx_conf_t *cf) | |
1158 { | |
1159 xmlInitParser(); | |
1160 | |
1161 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
1162 ngx_http_top_header_filter = ngx_http_xslt_header_filter; | |
1163 | |
1164 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
1165 ngx_http_top_body_filter = ngx_http_xslt_body_filter; | |
1166 | |
1167 return NGX_OK; | |
1168 } | |
1169 | |
1170 | |
1171 static void | |
1172 ngx_http_xslt_filter_exit(ngx_cycle_t *cycle) | |
1173 { | |
1174 xsltCleanupGlobals(); | |
1175 xmlCleanupParser(); | |
1176 } |