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