Changed to detect recursion in xslt:include (bug #127687).
[platform/upstream/libxslt.git] / libxslt / imports.c
1 /*
2  * imports.c: Implementation of the XSLT imports
3  *
4  * Reference:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  */
11
12 #define IN_LIBXSLT
13 #include "libxslt.h"
14
15 #include <string.h>
16
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
19 #endif
20 #ifdef HAVE_MATH_H
21 #include <math.h>
22 #endif
23 #ifdef HAVE_FLOAT_H
24 #include <float.h>
25 #endif
26 #ifdef HAVE_IEEEFP_H
27 #include <ieeefp.h>
28 #endif
29 #ifdef HAVE_NAN_H
30 #include <nan.h>
31 #endif
32 #ifdef HAVE_CTYPE_H
33 #include <ctype.h>
34 #endif
35
36 #include <libxml/xmlmemory.h>
37 #include <libxml/tree.h>
38 #include <libxml/hash.h>
39 #include <libxml/xmlerror.h>
40 #include <libxml/uri.h>
41 #include "xslt.h"
42 #include "xsltInternals.h"
43 #include "xsltutils.h"
44 #include "imports.h"
45 #include "documents.h"
46 #include "security.h"
47 #include "pattern.h"
48
49
50 /************************************************************************
51  *                                                                      *
52  *                      Module interfaces                               *
53  *                                                                      *
54  ************************************************************************/
55
56 /**
57  * xsltParseStylesheetImport:
58  * @style:  the XSLT stylesheet
59  * @cur:  the import element
60  *
61  * parse an XSLT stylesheet import element
62  *
63  * Returns 0 in case of success -1 in case of failure.
64  */
65
66 int
67 xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
68     int ret = -1;
69     xmlDocPtr import = NULL;
70     xmlChar *base = NULL;
71     xmlChar *uriRef = NULL;
72     xmlChar *URI = NULL;
73     xsltStylesheetPtr res;
74     xsltSecurityPrefsPtr sec;
75
76     if ((cur == NULL) || (style == NULL))
77         return (ret);
78
79     uriRef = xsltGetNsProp(cur, (const xmlChar *)"href", XSLT_NAMESPACE);
80     if (uriRef == NULL) {
81         xsltTransformError(NULL, style, cur,
82             "xsl:import : missing href attribute\n");
83         goto error;
84     }
85
86     base = xmlNodeGetBase(style->doc, cur);
87     URI = xmlBuildURI(uriRef, base);
88     if (URI == NULL) {
89         xsltTransformError(NULL, style, cur,
90             "xsl:import : invalid URI reference %s\n", uriRef);
91         goto error;
92     }
93
94     res = style;
95     while (res != NULL) {
96         if (res->doc == NULL)
97             break;
98         if (xmlStrEqual(res->doc->URL, URI)) {
99             xsltTransformError(NULL, style, cur,
100                "xsl:import : recursion detected on imported URL %s\n", URI);
101             goto error;
102         }
103         res = res->parent;
104     }
105
106     /*
107      * Security framework check
108      */
109     sec = xsltGetDefaultSecurityPrefs();
110     if (sec != NULL) {
111         int secres;
112
113         secres = xsltCheckRead(sec, NULL, URI);
114         if (secres == 0) {
115             xsltTransformError(NULL, NULL, NULL,
116                  "xsl:import: read rights for %s denied\n",
117                              URI);
118             goto error;
119         }
120     }
121
122 #ifdef XSLT_PARSE_OPTIONS
123     import = xmlReadFile((const char *) URI, NULL, XSLT_PARSE_OPTIONS);
124 #else
125     import = xmlParseFile((const char *) URI);
126 #endif
127     if (import == NULL) {
128         xsltTransformError(NULL, style, cur,
129             "xsl:import : unable to load %s\n", URI);
130         goto error;
131     }
132
133     res = xsltParseStylesheetImportedDoc(import, style);
134     if (res != NULL) {
135         res->next = style->imports;
136         style->imports = res;
137         xmlHashScan(res->templatesHash, 
138                     (xmlHashScanner) xsltNormalizeCompSteps, style);
139         style->extrasNr += res->extrasNr;
140         ret = 0;
141     } else {
142         xmlFreeDoc(import);
143         }
144
145 error:
146     if (uriRef != NULL)
147         xmlFree(uriRef);
148     if (base != NULL)
149         xmlFree(base);
150     if (URI != NULL)
151         xmlFree(URI);
152
153     return (ret);
154 }
155
156 /**
157  * xsltParseStylesheetInclude:
158  * @style:  the XSLT stylesheet
159  * @cur:  the include node
160  *
161  * parse an XSLT stylesheet include element
162  *
163  * Returns 0 in case of success -1 in case of failure
164  */
165
166 int
167 xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) {
168     int ret = -1;
169     xmlDocPtr oldDoc;
170     xmlChar *base = NULL;
171     xmlChar *uriRef = NULL;
172     xmlChar *URI = NULL;
173     xsltDocumentPtr include;
174     xsltDocumentPtr docptr;
175
176     if ((cur == NULL) || (style == NULL))
177         return (ret);
178
179     uriRef = xsltGetNsProp(cur, (const xmlChar *)"href", XSLT_NAMESPACE);
180     if (uriRef == NULL) {
181         xsltTransformError(NULL, style, cur,
182             "xsl:include : missing href attribute\n");
183         goto error;
184     }
185
186     base = xmlNodeGetBase(style->doc, cur);
187     URI = xmlBuildURI(uriRef, base);
188     if (URI == NULL) {
189         xsltTransformError(NULL, style, cur,
190             "xsl:include : invalid URI reference %s\n", uriRef);
191         goto error;
192     }
193
194     /*
195      * in order to detect recursion, we check all previously included
196      * stylesheets.
197      */
198     docptr = style->includes;
199     while (docptr != NULL) {
200         if (xmlStrEqual(docptr->doc->URL, URI)) {
201             xsltTransformError(NULL, style, cur,
202                 "xsl:include : recursion detected on included URL %s\n", URI);
203             goto error;
204         }
205         docptr = docptr->includes;
206     }
207
208     include = xsltLoadStyleDocument(style, URI);
209     if (include == NULL) {
210         xsltTransformError(NULL, style, cur,
211             "xsl:include : unable to load %s\n", URI);
212         goto error;
213     }
214
215     oldDoc = style->doc;
216     style->doc = include->doc;
217     /* chain to stylesheet for recursion checking */
218     include->includes = style->includes;
219     style->includes = include;
220     ret = (int)xsltParseStylesheetProcess(style, include->doc);
221     style->includes = include->includes;
222     style->doc = oldDoc;
223     if (ret == 0) {
224                 ret = -1;
225                 goto error;
226         }
227     ret = 0;
228
229 error:
230     if (uriRef != NULL)
231         xmlFree(uriRef);
232     if (base != NULL)
233         xmlFree(base);
234     if (URI != NULL)
235         xmlFree(URI);
236
237     return (ret);
238 }
239
240 /**
241  * xsltNextImport:
242  * @cur:  the current XSLT stylesheet
243  *
244  * Find the next stylesheet in import precedence.
245  *
246  * Returns the next stylesheet or NULL if it was the last one
247  */
248
249 xsltStylesheetPtr
250 xsltNextImport(xsltStylesheetPtr cur) {
251     if (cur == NULL)
252         return(NULL);
253     if (cur->imports != NULL)
254         return(cur->imports);
255     if (cur->next != NULL)
256         return(cur->next) ;
257     do {
258         cur = cur->parent;
259         if (cur == NULL) return(NULL);
260         if (cur->next != NULL) return(cur->next);
261     } while (cur != NULL);
262     return(cur);
263 }
264
265 /**
266  * xsltNeedElemSpaceHandling:
267  * @ctxt:  an XSLT transformation context
268  *
269  * Checks whether that stylesheet requires white-space stripping
270  *
271  * Returns 1 if space should be stripped, 0 if not
272  */
273
274 int
275 xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) {
276     xsltStylesheetPtr style;
277
278     if (ctxt == NULL)
279         return(0);
280     style = ctxt->style;
281     while (style != NULL) {
282         if (style->stripSpaces != NULL)
283             return(1);
284         style = xsltNextImport(style);
285     }
286     return(0);
287 }
288
289 /**
290  * xsltFindElemSpaceHandling:
291  * @ctxt:  an XSLT transformation context
292  * @node:  an XML node
293  *
294  * Find strip-space or preserve-space informations for an element
295  * respect the import precedence or the wildcards
296  *
297  * Returns 1 if space should be stripped, 0 if not, and 2 if everything
298  *         should be CDTATA wrapped.
299  */
300
301 int
302 xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) {
303     xsltStylesheetPtr style;
304     const xmlChar *val;
305
306     if ((ctxt == NULL) || (node == NULL))
307         return(0);
308     style = ctxt->style;
309     while (style != NULL) {
310         if (node->ns != NULL) {
311             val = (const xmlChar *)
312               xmlHashLookup2(style->stripSpaces, node->name, node->ns->href);
313         } else {
314             val = (const xmlChar *)
315                   xmlHashLookup2(style->stripSpaces, node->name, NULL);
316         }
317         if (val != NULL) {
318             if (xmlStrEqual(val, (xmlChar *) "strip"))
319                 return(1);
320             if (xmlStrEqual(val, (xmlChar *) "preserve"))
321                 return(0);
322         } 
323         if (style->stripAll == 1)
324             return(1);
325         if (style->stripAll == -1)
326             return(0);
327
328         style = xsltNextImport(style);
329     }
330     return(0);
331 }
332
333 /**
334  * xsltFindTemplate:
335  * @ctxt:  an XSLT transformation context
336  * @name: the template name
337  * @nameURI: the template name URI
338  *
339  * Finds the named template, apply import precedence rule.
340  *
341  * Returns the xsltTemplatePtr or NULL if not found
342  */
343 xsltTemplatePtr
344 xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name,
345                  const xmlChar *nameURI) {
346     xsltTemplatePtr cur;
347     xsltStylesheetPtr style;
348
349     if ((ctxt == NULL) || (name == NULL))
350         return(NULL);
351     style = ctxt->style;
352     while (style != NULL) {
353         cur = style->templates;
354         while (cur != NULL) {
355             if (xmlStrEqual(name, cur->name)) {
356                 if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
357                     ((nameURI != NULL) && (cur->nameURI != NULL) &&
358                      (xmlStrEqual(nameURI, cur->nameURI)))) {
359                     return(cur);
360                 }
361             }
362             cur = cur->next;
363         }
364
365         style = xsltNextImport(style);
366     }
367     return(NULL);
368 }
369