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 : :
8152 bruce@momjian.us 43 :CBC 4 : PG_FUNCTION_INFO_V1(xslt_process);
44 : :
45 : : Datum
7975 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 resstr = 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 : : int reslen = 0;
84 : :
85 : : /* Parse document */
86 : : doctree = xmlReadMemory((char *) VARDATA_ANY(doct),
87 : : VARSIZE_ANY_EXHDR(doct), NULL, NULL,
88 : : XML_PARSE_NOENT);
89 : :
90 : : if (doctree == NULL || pg_xml_error_occurred(xmlerrcxt))
91 : : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
92 : : "error parsing XML document");
93 : :
94 : : /* Same for stylesheet */
95 : : ssdoc = xmlReadMemory((char *) VARDATA_ANY(ssheet),
96 : : VARSIZE_ANY_EXHDR(ssheet), NULL, NULL,
97 : : XML_PARSE_NOENT);
98 : :
99 : : if (ssdoc == NULL || pg_xml_error_occurred(xmlerrcxt))
100 : : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
101 : : "error parsing stylesheet as XML document");
102 : :
103 : : /*
104 : : * On success, the stylesheet owns ssdoc, with xsltFreeStylesheet()
105 : : * calling xmlFreeDoc() on its associated doc.
106 : : */
107 : : stylesheet = xsltParseStylesheetDoc(ssdoc);
108 : : if (stylesheet != NULL)
109 : : ssdoc = NULL;
110 : :
111 : : if (stylesheet == NULL || pg_xml_error_occurred(xmlerrcxt))
112 : : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
113 : : "failed to parse stylesheet");
114 : :
115 : : xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
116 : :
117 : : xslt_sec_prefs_error = false;
118 : : if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL)
119 : : xslt_sec_prefs_error = true;
120 : :
121 : : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE,
122 : : xsltSecurityForbid) != 0)
123 : : xslt_sec_prefs_error = true;
124 : : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE,
125 : : xsltSecurityForbid) != 0)
126 : : xslt_sec_prefs_error = true;
127 : : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY,
128 : : xsltSecurityForbid) != 0)
129 : : xslt_sec_prefs_error = true;
130 : : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK,
131 : : xsltSecurityForbid) != 0)
132 : : xslt_sec_prefs_error = true;
133 : : if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK,
134 : : xsltSecurityForbid) != 0)
135 : : xslt_sec_prefs_error = true;
136 : : if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0)
137 : : xslt_sec_prefs_error = true;
138 : :
139 : : if (xslt_sec_prefs_error)
140 : : ereport(ERROR,
141 : : (errmsg("could not set libxslt security preferences")));
142 : :
143 : : restree = xsltApplyStylesheetUser(stylesheet, doctree, params,
144 : : NULL, NULL, xslt_ctxt);
145 : :
146 : : if (restree == NULL || pg_xml_error_occurred(xmlerrcxt))
147 : : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
148 : : "failed to apply stylesheet");
149 : :
150 : : resstat = xsltSaveResultToString((xmlChar **) &resstr, &reslen,
151 : : restree, stylesheet);
152 : :
153 : : if (resstat >= 0)
154 : : {
155 : : /*
156 : : * If an empty string has been returned, resstr would be NULL. In
157 : : * this case, assume that the result is an empty string.
158 : : */
159 : : if (reslen == 0)
160 : : result = cstring_to_text("");
161 : : else
162 : : result = cstring_to_text_with_len((char *) resstr, reslen);
163 : : }
164 : : }
165 : : PG_CATCH();
166 : : {
167 : : if (restree != NULL)
168 : : xmlFreeDoc(restree);
169 : : if (xslt_ctxt != NULL)
170 : : xsltFreeTransformContext(xslt_ctxt);
171 : : if (xslt_sec_prefs != NULL)
172 : : xsltFreeSecurityPrefs(xslt_sec_prefs);
173 : : if (stylesheet != NULL)
174 : : xsltFreeStylesheet(stylesheet);
175 : : if (ssdoc != NULL)
176 : : xmlFreeDoc(ssdoc);
177 : : if (doctree != NULL)
178 : : xmlFreeDoc(doctree);
179 : : if (resstr != NULL)
180 : : xmlFree(resstr);
181 : : xsltCleanupGlobals();
182 : :
183 : : pg_xml_done(xmlerrcxt, true);
184 : :
185 : : PG_RE_THROW();
186 : : }
187 : : PG_END_TRY();
188 : :
189 : : xmlFreeDoc(restree);
190 : : xsltFreeTransformContext(xslt_ctxt);
191 : : xsltFreeSecurityPrefs(xslt_sec_prefs);
192 : : xsltFreeStylesheet(stylesheet);
193 : : xmlFreeDoc(doctree);
194 : : xsltCleanupGlobals();
195 : :
196 : : if (resstr)
197 : : xmlFree(resstr);
198 : :
199 : : pg_xml_done(xmlerrcxt, false);
200 : :
201 : : /* XXX this is pretty dubious, really ought to throw error instead */
202 : : if (resstat < 0)
203 : : PG_RETURN_NULL();
204 : :
205 : : PG_RETURN_TEXT_P(result);
206 : : #else /* !USE_LIBXSLT */
207 : :
5965 tgl@sss.pgh.pa.us 208 [ + - ]: 6 : ereport(ERROR,
209 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
210 : : errmsg("xslt_process() is not available without libxslt")));
211 : : PG_RETURN_NULL();
212 : : #endif /* USE_LIBXSLT */
213 : : }
214 : :
215 : : #ifdef USE_LIBXSLT
216 : :
217 : : static const char **
218 : : parse_params(text *paramstr)
219 : : {
220 : : char *pos;
221 : : char *pstr;
222 : : char *nvsep = "=";
223 : : char *itsep = ",";
224 : : const char **params;
225 : : int max_params;
226 : : int nparams;
227 : :
228 : : pstr = text_to_cstring(paramstr);
229 : :
230 : : max_params = 20; /* must be even! */
231 : : params = (const char **) palloc((max_params + 1) * sizeof(char *));
232 : : nparams = 0;
233 : :
234 : : pos = pstr;
235 : :
236 : : while (*pos != '\0')
237 : : {
238 : : if (nparams >= max_params)
239 : : {
240 : : max_params *= 2;
241 : : params = (const char **) repalloc(params,
242 : : (max_params + 1) * sizeof(char *));
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 */
|