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