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 : volatile 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 || pg_xml_error_occurred(xmlerrcxt))
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 || pg_xml_error_occurred(xmlerrcxt))
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 || pg_xml_error_occurred(xmlerrcxt))
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 || pg_xml_error_occurred(xmlerrcxt))
141 : xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
142 : "failed to apply stylesheet");
143 :
144 : resstat = xsltSaveResultToString((xmlChar **) &resstr, &reslen,
145 : restree, stylesheet);
146 :
147 : if (resstat >= 0)
148 : result = cstring_to_text_with_len((char *) resstr, reslen);
149 : }
150 : PG_CATCH();
151 : {
152 : if (restree != NULL)
153 : xmlFreeDoc(restree);
154 : if (xslt_ctxt != NULL)
155 : xsltFreeTransformContext(xslt_ctxt);
156 : if (xslt_sec_prefs != NULL)
157 : xsltFreeSecurityPrefs(xslt_sec_prefs);
158 : if (stylesheet != NULL)
159 : xsltFreeStylesheet(stylesheet);
160 : if (doctree != NULL)
161 : xmlFreeDoc(doctree);
162 : if (resstr != NULL)
163 : xmlFree((xmlChar *) resstr);
164 : xsltCleanupGlobals();
165 :
166 : pg_xml_done(xmlerrcxt, true);
167 :
168 : PG_RE_THROW();
169 : }
170 : PG_END_TRY();
171 :
172 : xmlFreeDoc(restree);
173 : xsltFreeTransformContext(xslt_ctxt);
174 : xsltFreeSecurityPrefs(xslt_sec_prefs);
175 : xsltFreeStylesheet(stylesheet);
176 : xmlFreeDoc(doctree);
177 : xsltCleanupGlobals();
178 :
179 : if (resstr)
180 : xmlFree((xmlChar *) resstr);
181 :
182 : pg_xml_done(xmlerrcxt, false);
183 :
184 : /* XXX this is pretty dubious, really ought to throw error instead */
185 : if (resstat < 0)
186 : PG_RETURN_NULL();
187 :
188 : PG_RETURN_TEXT_P(result);
189 : #else /* !USE_LIBXSLT */
190 :
191 10 : ereport(ERROR,
192 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
193 : errmsg("xslt_process() is not available without libxslt")));
194 : PG_RETURN_NULL();
195 : #endif /* USE_LIBXSLT */
196 : }
197 :
198 : #ifdef USE_LIBXSLT
199 :
200 : static const char **
201 : parse_params(text *paramstr)
202 : {
203 : char *pos;
204 : char *pstr;
205 : char *nvsep = "=";
206 : char *itsep = ",";
207 : const char **params;
208 : int max_params;
209 : int nparams;
210 :
211 : pstr = text_to_cstring(paramstr);
212 :
213 : max_params = 20; /* must be even! */
214 : params = (const char **) palloc((max_params + 1) * sizeof(char *));
215 : nparams = 0;
216 :
217 : pos = pstr;
218 :
219 : while (*pos != '\0')
220 : {
221 : if (nparams >= max_params)
222 : {
223 : max_params *= 2;
224 : params = (const char **) repalloc(params,
225 : (max_params + 1) * sizeof(char *));
226 : }
227 : params[nparams++] = pos;
228 : pos = strstr(pos, nvsep);
229 : if (pos != NULL)
230 : {
231 : *pos = '\0';
232 : pos++;
233 : }
234 : else
235 : {
236 : /* No equal sign, so ignore this "parameter" */
237 : nparams--;
238 : break;
239 : }
240 :
241 : /* since max_params is even, we still have nparams < max_params */
242 : params[nparams++] = pos;
243 : pos = strstr(pos, itsep);
244 : if (pos != NULL)
245 : {
246 : *pos = '\0';
247 : pos++;
248 : }
249 : else
250 : break;
251 : }
252 :
253 : /* Add the terminator marker; we left room for it in the palloc's */
254 : params[nparams] = NULL;
255 :
256 : return params;
257 : }
258 :
259 : #endif /* USE_LIBXSLT */
|