Line data Source code
1 : /*
2 : * contrib/xml2/xslt_proc.c
3 : *
4 : * XSLT processing functions (requiring libxslt)
5 : *
6 : * John Gray, for Torchbox 2003-04-01
7 : */
8 : #include "postgres.h"
9 :
10 : #include "fmgr.h"
11 : #include "utils/builtins.h"
12 : #include "utils/xml.h"
13 :
14 : #ifdef USE_LIBXSLT
15 :
16 : /* libxml includes */
17 :
18 : #include <libxml/xpath.h>
19 : #include <libxml/tree.h>
20 : #include <libxml/xmlmemory.h>
21 :
22 : /* libxslt includes */
23 :
24 : #include <libxslt/xslt.h>
25 : #include <libxslt/xsltInternals.h>
26 : #include <libxslt/security.h>
27 : #include <libxslt/transform.h>
28 : #include <libxslt/xsltutils.h>
29 : #endif /* USE_LIBXSLT */
30 :
31 :
32 : #ifdef USE_LIBXSLT
33 :
34 : /* declarations to come from xpath.c */
35 : extern PgXmlErrorContext *pgxml_parser_init(PgXmlStrictness strictness);
36 :
37 : /* local defs */
38 : static const char **parse_params(text *paramstr);
39 : #endif /* USE_LIBXSLT */
40 :
41 :
42 8 : PG_FUNCTION_INFO_V1(xslt_process);
43 :
44 : Datum
45 10 : xslt_process(PG_FUNCTION_ARGS)
46 : {
47 : #ifdef USE_LIBXSLT
48 :
49 : text *doct = PG_GETARG_TEXT_PP(0);
50 : text *ssheet = PG_GETARG_TEXT_PP(1);
51 : text *result;
52 : text *paramstr;
53 : const char **params;
54 : PgXmlErrorContext *xmlerrcxt;
55 : volatile xsltStylesheetPtr stylesheet = NULL;
56 : volatile xmlDocPtr doctree = NULL;
57 : volatile xmlDocPtr restree = NULL;
58 : volatile xsltSecurityPrefsPtr xslt_sec_prefs = NULL;
59 : volatile xsltTransformContextPtr xslt_ctxt = NULL;
60 : volatile int resstat = -1;
61 : xmlChar *resstr = NULL;
62 : int reslen = 0;
63 :
64 : if (fcinfo->nargs == 3)
65 : {
66 : paramstr = PG_GETARG_TEXT_PP(2);
67 : params = parse_params(paramstr);
68 : }
69 : else
70 : {
71 : /* No parameters */
72 : params = (const char **) palloc(sizeof(char *));
73 : params[0] = NULL;
74 : }
75 :
76 : /* Setup parser */
77 : xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
78 :
79 : PG_TRY();
80 : {
81 : xmlDocPtr ssdoc;
82 : bool xslt_sec_prefs_error;
83 :
84 : /* Parse document */
85 : doctree = xmlReadMemory((char *) VARDATA_ANY(doct),
86 : VARSIZE_ANY_EXHDR(doct), NULL, NULL,
87 : XML_PARSE_NOENT);
88 :
89 : if (doctree == NULL)
90 : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
91 : "error parsing XML document");
92 :
93 : /* Same for stylesheet */
94 : ssdoc = xmlReadMemory((char *) VARDATA_ANY(ssheet),
95 : VARSIZE_ANY_EXHDR(ssheet), NULL, NULL,
96 : XML_PARSE_NOENT);
97 :
98 : if (ssdoc == NULL)
99 : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
100 : "error parsing stylesheet as XML document");
101 :
102 : /* After this call we need not free ssdoc separately */
103 : stylesheet = xsltParseStylesheetDoc(ssdoc);
104 :
105 : if (stylesheet == NULL)
106 : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
107 : "failed to parse stylesheet");
108 :
109 : xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
110 :
111 : xslt_sec_prefs_error = false;
112 : if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL)
113 : xslt_sec_prefs_error = true;
114 :
115 : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE,
116 : xsltSecurityForbid) != 0)
117 : xslt_sec_prefs_error = true;
118 : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE,
119 : xsltSecurityForbid) != 0)
120 : xslt_sec_prefs_error = true;
121 : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY,
122 : xsltSecurityForbid) != 0)
123 : xslt_sec_prefs_error = true;
124 : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK,
125 : xsltSecurityForbid) != 0)
126 : xslt_sec_prefs_error = true;
127 : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK,
128 : xsltSecurityForbid) != 0)
129 : xslt_sec_prefs_error = true;
130 : if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0)
131 : xslt_sec_prefs_error = true;
132 :
133 : if (xslt_sec_prefs_error)
134 : ereport(ERROR,
135 : (errmsg("could not set libxslt security preferences")));
136 :
137 : restree = xsltApplyStylesheetUser(stylesheet, doctree, params,
138 : NULL, NULL, xslt_ctxt);
139 :
140 : if (restree == NULL)
141 : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
142 : "failed to apply stylesheet");
143 :
144 : resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
145 : }
146 : PG_CATCH();
147 : {
148 : if (restree != NULL)
149 : xmlFreeDoc(restree);
150 : if (xslt_ctxt != NULL)
151 : xsltFreeTransformContext(xslt_ctxt);
152 : if (xslt_sec_prefs != NULL)
153 : xsltFreeSecurityPrefs(xslt_sec_prefs);
154 : if (stylesheet != NULL)
155 : xsltFreeStylesheet(stylesheet);
156 : if (doctree != NULL)
157 : xmlFreeDoc(doctree);
158 : xsltCleanupGlobals();
159 :
160 : pg_xml_done(xmlerrcxt, true);
161 :
162 : PG_RE_THROW();
163 : }
164 : PG_END_TRY();
165 :
166 : xmlFreeDoc(restree);
167 : xsltFreeTransformContext(xslt_ctxt);
168 : xsltFreeSecurityPrefs(xslt_sec_prefs);
169 : xsltFreeStylesheet(stylesheet);
170 : xmlFreeDoc(doctree);
171 : xsltCleanupGlobals();
172 :
173 : pg_xml_done(xmlerrcxt, false);
174 :
175 : /* XXX this is pretty dubious, really ought to throw error instead */
176 : if (resstat < 0)
177 : PG_RETURN_NULL();
178 :
179 : result = cstring_to_text_with_len((char *) resstr, reslen);
180 :
181 : if (resstr)
182 : xmlFree(resstr);
183 :
184 : PG_RETURN_TEXT_P(result);
185 : #else /* !USE_LIBXSLT */
186 :
187 10 : ereport(ERROR,
188 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
189 : errmsg("xslt_process() is not available without libxslt")));
190 : PG_RETURN_NULL();
191 : #endif /* USE_LIBXSLT */
192 : }
193 :
194 : #ifdef USE_LIBXSLT
195 :
196 : static const char **
197 : parse_params(text *paramstr)
198 : {
199 : char *pos;
200 : char *pstr;
201 : char *nvsep = "=";
202 : char *itsep = ",";
203 : const char **params;
204 : int max_params;
205 : int nparams;
206 :
207 : pstr = text_to_cstring(paramstr);
208 :
209 : max_params = 20; /* must be even! */
210 : params = (const char **) palloc((max_params + 1) * sizeof(char *));
211 : nparams = 0;
212 :
213 : pos = pstr;
214 :
215 : while (*pos != '\0')
216 : {
217 : if (nparams >= max_params)
218 : {
219 : max_params *= 2;
220 : params = (const char **) repalloc(params,
221 : (max_params + 1) * sizeof(char *));
222 : }
223 : params[nparams++] = pos;
224 : pos = strstr(pos, nvsep);
225 : if (pos != NULL)
226 : {
227 : *pos = '\0';
228 : pos++;
229 : }
230 : else
231 : {
232 : /* No equal sign, so ignore this "parameter" */
233 : nparams--;
234 : break;
235 : }
236 :
237 : /* since max_params is even, we still have nparams < max_params */
238 : params[nparams++] = pos;
239 : pos = strstr(pos, itsep);
240 : if (pos != NULL)
241 : {
242 : *pos = '\0';
243 : pos++;
244 : }
245 : else
246 : break;
247 : }
248 :
249 : /* Add the terminator marker; we left room for it in the palloc's */
250 : params[nparams] = NULL;
251 :
252 : return params;
253 : }
254 :
255 : #endif /* USE_LIBXSLT */
|