1 /*
2  * Copyright 1999-2006 University of Chicago
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  * http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "globus_soap_message.h"
18 #include "globus_wsrf_resource.h"
19 #include "globus_service_engine.h"
20 #include "globus_operation_provider.h"
21 #include "globus_service_registry.h"
22 #include "globus_wsrf_core_tools.h"
23 #include "version.h"
24 #include "libxml/xpath.h"
25 #include "libxml/xpathInternals.h"
26 #include "libxml/tree.h"
27 #include "libxml/c14n.h"
28 #include "globus_xml_buffer.h"
29 #include <math.h>
30
31 #include "wsrp_QueryResourcePropertiesType.h"
32 #include "wsrp_QueryResourcePropertiesResponseType.h"
33 #include "xpath_XPathExpressionType.h"
34 #include "xpath_NamespaceMapEntryType.h"
35
36 #define WSRP_QUERY_RESOURCE_PROPERTIES 1
37 #define NEED_INVALID_QUERY_EXPRESSION_FAULT 1
38 #define NEED_QUERY_EVALUATION_ERROR_FAULT 1
39
40 #include "wsrp_i_faults.h"
41
42 /**
43  * @page wsrp_QueryResourceProperties_provider QueryResourceProperties Provider
44  *
45  * <h2>Provider Usage Overview</h2>
46  * This operation provider implements the QueryResourceProperties portType
47  * defined in
48  * http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl .
49  *
50  * This portType consists of the @a QueryResourceProperties operation and
51  * related faults.
52  *
53  * Currently, this provider supports XPATH Queries using the Dialect attribute
54  * "http://www.w3.org/TR/1999/REC-xpath-19991116".
55  *
56  * The WSRF service engine will automatically register this provider to handle
57  * the QueryResourceProperties operation for services which use the port type.
58  */
59
60 /* Prototypes */
61 static
62 globus_result_t
63 wsrp_QueryResourceProperties_provider(
64     globus_service_engine_t             engine,
65     globus_soap_message_handle_t        message,
66     globus_service_descriptor_t *       service,
67     wsrp_QueryResourcePropertiesType *  QueryResourceProperties,
68     wsrp_QueryResourcePropertiesResponseType *
69                                         QueryResourcePropertiesResponse,
70     char **                             fault_name,
71     void **                             fault);
72
73 static
74 int
75 wsrp_QueryResourceProperties_activate(void);
76
77 static
78 int
79 wsrp_QueryResourceProperties_deactivate(void);
80
81 static
82 globus_result_t
83 wsrp_l_c14n_node(
84     xmlDocPtr                           cur_doc,
85     xmlNodePtr                          cur_node,
86     xmlChar **                          data);
87
88 /* Local Variables */
89 static xsd_QName wsrp_QueryResourceProperties_qname =
90 {
91     "http://www.globus.org/docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl",
92     "QueryResourceProperties"
93 };
94
95 static
96 globus_operation_provider_descriptor_t
97 wsrp_QueryResourceProperties_descriptor =
98 {
99     &wsrp_QueryResourceProperties_qname,
100     "QueryResourceProperties",
101     (void *)wsrp_QueryResourceProperties_provider,
102     NULL
103 };
104
105 GlobusExtensionDefineModule(globus_wsrp_QueryResourceProperties_provider) =
106 {
107     "globus_wsrp_QueryResourceProperties_provider",
108     wsrp_QueryResourceProperties_activate,
109     wsrp_QueryResourceProperties_deactivate,
110     NULL,
111     NULL,
112     &local_version
113 };
114
115 /* Implementation */
116
117 #define RP_DOC_NS "http://www.globus.org/namespaces/2006/04/QueryResourceProperties"
118 #define RP_DOC    "Document"
119
120 static
121 globus_result_t
122 wsrp_QueryResourceProperties_provider(
123     globus_service_engine_t             engine,
124     globus_soap_message_handle_t        message,
125     globus_service_descriptor_t *       service,
126     wsrp_QueryResourcePropertiesType *  QueryResourceProperties,
127     wsrp_QueryResourcePropertiesResponseType *
128                                         QueryResourcePropertiesResponse,
129     char **                             fault_name,
130     void **                             fault)
131 21 {
132 21     globus_result_t                     result;
133 21     globus_resource_t                   resource;
134 21     xsd_QName_array *                   property_names = NULL;
135 21     globus_soap_message_handle_t        dom_handle = NULL;
136 21     xmlDocPtr                           dom = NULL;
137 21     xsd_anyType                         rp_doc_element;
138 21     xsd_any_array *                     rp_array = NULL;
139 21     xsd_any *                           tmp = NULL;
140 21     xsd_QName                           rp_doc_element_qname = { RP_DOC_NS, RP_DOC};
141 21     int                                 i;
142 21     xmlXPathContextPtr                  xpath_context;
143 21     xmlXPathObjectPtr                   xpath_result;
144 21     xmlXPathCompExprPtr                 xpath_expression;
145 21     xpath_XPathExpressionType *         serialized_expression;
146
147 21     result = globus_wsrf_core_get_resource(
148         message,
149         service,
150         &resource);
151
152 21     if (result != GLOBUS_SUCCESS || resource == NULL)
153     {
154 0         result = wsrp_l_ResourceUnknownFaultType_create(
155             fault_name,
156             (wsrp_ResourceUnknownFaultType **) fault);
157
158 0         goto out;
159     }
160 21     if (QueryResourceProperties->QueryExpression._Dialect == NULL ||
161            (strcmp(*QueryResourceProperties->QueryExpression._Dialect,
162                "http://www.w3.org/TR/1999/REC-xpath-19991116") != 0))
163     {
164         /* Unknown/unsupported dialect */
165 0         result = wsrp_l_UnknownQueryExpressionDialectFaultType_create(
166                 fault_name,
167                 (wsrp_UnknownQueryExpressionDialectFaultType **) fault);
168
169 0         goto finish_out;
170     }
171 21     result = globus_resource_enumerate_properties(
172             resource,
173             &property_names);
174 21     if (result != GLOBUS_SUCCESS)
175     {
176 0         goto finish_out;
177     }
178     /* Create a document containing all of the resource properties */
179 21     result = xsd_anyType_init_contents(&rp_doc_element);
180 21     if (result != GLOBUS_SUCCESS)
181     {
182 0         goto free_property_qnames;
183     }
184 21     rp_doc_element.any_info = &xsd_any_array_info;
185
186 21     result = xsd_any_array_init(&rp_array);
187 21     if (result != GLOBUS_SUCCESS)
188     {
189 0         goto free_rp_doc_element;
190     }
191 21     rp_doc_element.value = rp_array;
192
193 45     for (i = 0; i < property_names->length; i++)
194     {
195 24         xsd_any *                       tmp;
196 24         void *                          prop_value;
197 24         globus_xsd_type_info_t          prop_type_info;
198
199 24         result = globus_resource_get_property(
200                 resource,
201                 &property_names->elements[i],
202                 &prop_value,
203                 &prop_type_info);
204 24         if (result != GLOBUS_SUCCESS)
205         {
206 0             goto free_rp_doc_element;
207         }
208 24         if (prop_value != NULL)
209         {
210 23             tmp = xsd_any_array_push(rp_array);
211 23             if (tmp == NULL)
212             {
213 0                 goto free_rp_doc_element;
214             }
215 23             xsd_QName_copy(&tmp->element, &property_names->elements[i]);
216 23             tmp->any_info = prop_type_info;
217 23             prop_type_info->copy(&tmp->value, prop_value);
218         }
219     }
220
221     /* Serialize the document to a DOM */
222 21     result = globus_soap_message_handle_init_to_dom(&dom_handle, &dom);
223 21     if (result != GLOBUS_SUCCESS)
224     {
225 0         goto free_rp_doc_element;
226     }
227 21     result = xsd_anyType_serialize(
228             &rp_doc_element_qname,
229             &rp_doc_element,
230             dom_handle,
231             0);
232 21     if (result != GLOBUS_SUCCESS)
233     {
234 0         goto free_dom_handle;
235     }
236 21     globus_soap_message_handle_destroy(dom_handle);
237 21     dom_handle = NULL;
238
239     /* Perform XPATH query on the DOM */
240 21     globus_assert(QueryResourceProperties->QueryExpression.any->any_info ==
241             &xpath_XPathExpressionType_contents_info);
242 21     xpath_context = xmlXPathNewContext(dom);
243 21     serialized_expression = QueryResourceProperties->QueryExpression.any->value;
244 163     for (i = 0; i < serialized_expression->NamespaceMap.length; i++)
245     {
246 142         xmlXPathRegisterNs(xpath_context,
247                 (xmlChar *) serialized_expression->NamespaceMap.elements[i].Prefix, 
248                 (xmlChar *) serialized_expression->NamespaceMap.elements[i].Namespace);
249     }
250
251 21     xpath_expression = xmlXPathCompile(
252             (xmlChar *) serialized_expression->ExpressionString);
253 21     if (xpath_expression == NULL)
254     {
255 0         result = INVALID_QUERY_EXPRESSION(fault_name, fault);
256 0         goto free_xpath_context;
257     }
258 21     xpath_result = xmlXPathCompiledEval(xpath_expression, xpath_context);
259 21     if (xpath_result == NULL || 
260             (xpath_result->type == XPATH_NODESET && 
261              (xpath_result->nodesetval == NULL ||
262               xpath_result->nodesetval->nodeNr == 0)))
263     {
264 2         result = QUERY_EVAULATION_ERROR(fault_name, fault);
265 2         goto free_xpath_result;
266     }
267     /* Transform XPATH result into a QueryResourcePropertiesResponseType */
268 19     switch (xpath_result->type)
269     {
270         case XPATH_UNDEFINED:
271 10             break;
272         case XPATH_NODESET:
273 22             for (i = 0; i < xpath_result->nodesetval->nodeNr; i++)
274             {
275 12                 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
276
277                 /* If the entire doc is returned, xmlNodeDump will not work properly as
278                  * the type of the node is not castable to xmlNodePtr
279                  */
280 12                 if (dom == (xmlDocPtr) xpath_result->nodesetval->nodeTab[i])
281                 {
282 0                     globus_xml_buffer_array * gbuf_array = NULL;
283 0                     globus_xml_buffer * gbuf = NULL;
284 0                     xmlNodePtr          tnode = dom->children->children;
285
286 0                     tmp->any_info = &globus_xml_buffer_array_info;
287 0                     globus_xml_buffer_array_init(&gbuf_array);
288 0                     tmp->value = gbuf_array;
289
290 0                     while (tnode != NULL)
291                     {
292 0                         xmlBufferPtr        buf;
293 0                         buf = xmlBufferCreate();
294
295 0                         xmlNodeDump(buf, dom, tnode, 0, 0);
296 0                         gbuf = globus_xml_buffer_array_push(gbuf_array);
297 0                         gbuf->buffer = malloc(buf->use);
298 0                         gbuf->length = buf->use;
299 0                         memcpy(gbuf->buffer, buf->content, buf->use);
300
301 0                         tnode = tnode->next;
302 0                         xmlBufferFree(buf);
303                     }
304                 }
305 12                 else if (xpath_result->nodesetval->nodeTab[i]->type == XML_ATTRIBUTE_NODE)
306                 {
307 6                     globus_xml_buffer * gbuf = NULL;
308 6                     xmlBufferPtr        buf;
309 6                     buf = xmlBufferCreate();
310
311 6                     globus_xml_buffer_init(&gbuf);
312 6                     tmp->any_info = &globus_xml_buffer_info;
313 6                     tmp->element = NULL;
314 6                     tmp->value = gbuf;
315 6                     xmlNodeDump(buf, dom, xpath_result->nodesetval->nodeTab[i]->children, 0, 0);
316 6                     gbuf->buffer = malloc(buf->use+1);
317 6                     gbuf->length = buf->use+1;
318 6                     gbuf->buffer[0] = ' ';
319 6                     memcpy(gbuf->buffer+1, buf->content, buf->use);
320 6                     xmlBufferFree(buf);
321                 }
322                 else
323                 {
324 6                     globus_xml_buffer * gbuf = NULL;
325
326 6                     globus_xml_buffer_init(&gbuf);
327 6                     tmp->any_info = &globus_xml_buffer_info;
328 6                     tmp->element = NULL;
329 6                     tmp->value = gbuf;
330 6                     result = wsrp_l_c14n_node(dom,
331                             xpath_result->nodesetval->nodeTab[i],
332                             (xmlChar **) &gbuf->buffer);
333 6                     gbuf->length = strlen(gbuf->buffer);
334                 }
335
336             }
337
338 5             break;
339
340         case XPATH_BOOLEAN:
341             {
342 5                 xsd_boolean *           b = NULL;
343 5                 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
344 5                 tmp->any_info = &xsd_boolean_info;
345 5                 xsd_boolean_init(&b);
346 5                 *b = xpath_result->boolval;
347 5                 tmp->value = b;
348             }
349 5             break;
350             
351         case XPATH_NUMBER:
352 4             if (floor(xpath_result->floatval) == ceil(xpath_result->floatval))
353             {
354 4                 xsd_long *              l = NULL;
355
356 4                 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
357 4                 tmp->any_info = &xsd_long_info;
358 4                 xsd_long_init(&l);
359 4                 *l = (long) xpath_result->floatval;
360 4                 tmp->value = l;
361             }
362             else
363             {
364 0                 xsd_double *            d = NULL;
365
366 0                 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
367 0                 tmp->any_info = &xsd_double_info;
368 0                 xsd_double_init(&d);
369 0                 *d = xpath_result->floatval;
370 0                 tmp->value = d;
371             }
372 0             break;
373         case XPATH_STRING:
374             {
375 0                 xsd_string *            s = NULL;
376
377 0                 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
378 0                 tmp->any_info = &xsd_string_info;
379 0                 xsd_string_init_cstr(&s, (xsd_string) xpath_result->stringval);
380 0                 tmp->value = s;
381             }
382             break;
383         case XPATH_POINT:
384         case XPATH_RANGE:
385         case XPATH_LOCATIONSET:
386         case XPATH_USERS:
387         case XPATH_XSLT_TREE:
388 21             break;
389     }
390 free_xpath_result:
391 21     if (xpath_result != NULL)
392     {
393 21         xmlXPathFreeObject(xpath_result);
394     }
395 21     xmlXPathFreeCompExpr(xpath_expression);
396 free_xpath_context:
397 21     xmlXPathFreeContext(xpath_context);
398 free_dom_handle:
399 21     if (dom_handle != NULL)
400     {
401 0         globus_soap_message_handle_destroy(dom_handle);
402 0         dom_handle = NULL;
403     }
404 free_rp_doc_element:
405 21     xsd_anyType_destroy_contents(&rp_doc_element);
406 free_property_qnames:
407 21     xsd_QName_array_destroy(property_names);
408 finish_out:
409 21     globus_resource_finish(resource);
410 out:
411 21     return result;
412 }
413 /* wsrp_QueryResourceProperties_provider() */
414
415 static
416 int
417 wsrp_QueryResourceProperties_activate(void)
418 93 {
419 93     int                                 res = 0;
420 93     GlobusFuncName(wsrp_QueryResourceProperties_activate);
421     
422
423 93     res = globus_extension_registry_add(
424         GLOBUS_OPERATION_PROVIDER_REGISTRY,
425         &wsrp_QueryResourceProperties_qname,
426         GlobusExtensionMyModule(globus_wsrp_QueryResourceProperties_provider),
427         &wsrp_QueryResourceProperties_descriptor);
428
429 93     return res;
430 }
431 /* wsrp_QueryResourceProperties_activate(void) */
432
433 static
434 int
435 wsrp_QueryResourceProperties_deactivate(void)
436 21 {
437 21     GlobusFuncName(wsrp_QueryResourceProperties_deactivate);
438
439 21     globus_extension_registry_remove(
440         GLOBUS_OPERATION_PROVIDER_REGISTRY,
441         &wsrp_QueryResourceProperties_qname);
442
443 21     return 0;
444 }
445 /* wsrp_QueryResourceProperties_deactivate() */
446
447 static
448 globus_result_t
449 wsrp_l_c14n_node(
450     xmlDocPtr                           cur_doc,
451     xmlNodePtr                          cur_node,
452     xmlChar **                          data)
453 6 {
454 6     xmlDocPtr                           doc;
455 6     xmlNodePtr                          node;
456 6     xmlNsPtr *                          ns_list;
457 6     xmlChar **                          ns_prefixes;
458 6     int                                 i;
459 6     int                                 j;
460
461     /* Canonicalize the XML when dumping so that the data can be used
462      * in other XML documents
463      */
464 6     node = xmlDocCopyNode(cur_node, cur_doc, 1);
465
466 6     doc = xmlNewDoc(BAD_CAST "1.0");
467 6     xmlDocSetRootElement(doc, node);
468
469 6     ns_list = xmlGetNsList(cur_doc, cur_node);
470
471 6     if (ns_list != NULL)
472     {
473 6         for (i = 0; ns_list[i] != NULL; i++)
474         {
475         }
476
477 6         ns_prefixes = malloc((i+1) * sizeof(xmlChar*));
478
479 30         for (i = 0, j = 0; ns_list[i] != NULL; i++)
480         {
481 24             if (ns_list[i]->prefix != NULL)
482             {
483 24                 ns_prefixes[j++] = xmlStrdup(ns_list[i]->prefix);
484             }
485 24             xmlNewNs(node, ns_list[i]->href, ns_list[i]->prefix);
486         }
487 6         ns_prefixes[j++] = NULL;
488
489 6         xmlFree(ns_list);
490     }
491
492 6     if (xmlC14NDocDumpMemory(doc, NULL, 1, ns_prefixes, 0, data) == -1)
493     {
494 0         xmlFreeDoc(doc);
495 0         xmlFree(ns_prefixes);
496 0         return GlobusSoapMessageErrorOutOfMemory;
497     }
498 30     for (i = 0; ns_prefixes[i] != NULL; i++)
499     {
500 24         xmlFree(ns_prefixes[i]);
501     }
502 6     xmlFree(ns_prefixes);
503 6     xmlFreeDoc(doc);
504 6     return GLOBUS_SUCCESS;
505 }