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
18 #include "globus_soap_message_attrs.h"
19 #include "globus_soap_message_utils.h"
20 #include "globus_i_soap_message.h"
21
22 typedef struct globus_l_message_attr_s
23 {
24     char *                                   name;
25     void *                                   value;
26     globus_soap_message_attr_copy_func_t     copy;
27     globus_soap_message_attr_destroy_func_t  destroy;
28 } globus_l_message_attr_t;
29
30 void
31 globus_l_message_attr_destroy(
32     void *                              attr)
33 93710 {
34 93710     globus_l_message_attr_t *           attribute;
35 93710     GlobusFuncName(globus_l_message_attr_destroy);
36 93710     GlobusSoapMessageDebugEnter();
37
38
39 93710     attribute = (globus_l_message_attr_t *) attr;
40
41 93710     if(attribute)
42     {
43 93710         if(attribute->name)
44         {
45 93710             free(attribute->name);
46         }
47         
48 93710         if(attribute->destroy && attribute->value)
49         {
50 46122             attribute->destroy(attribute->value);
51         }
52
53 93710         free(attribute);
54     }
55
56 93710     GlobusSoapMessageDebugExit();
57 }
58
59 /**
60  * Initialize a new SOAP Message Attribute Set
61  * @ingroup globus_soap_message_attrs
62  *
63  * @param attrs
64  *     New attribute set to initialize.
65  *
66  * @retval GLOBUS_SUCCESS
67  *     Attributes successfully initialized.
68  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
69  *     The @a attrs parameter was NULL.
70  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
71  *     Insufficient memory to initialize the attributes.
72  */
73 globus_result_t
74 globus_soap_message_attr_init(
75     globus_soap_message_attr_t *        attrs)
76 15002 {
77 15002     globus_result_t                     result = GLOBUS_SUCCESS;
78 15002     GlobusFuncName(globus_soap_message_attr_init);
79 15002     GlobusSoapMessageDebugEnter();
80
81 15002     if (attrs == NULL)
82     {
83 0         result = GlobusSoapMessageErrorNullParam;
84         
85 0         goto out;
86     }
87     
88 15002     result = globus_hashtable_init(attrs, 19,
89                                    globus_hashtable_string_hash,
90                                    globus_hashtable_string_keyeq);
91     
92 15002     if (result != GLOBUS_SUCCESS)
93     {
94 0         result = GlobusSoapMessageErrorOutOfMemory;
95     }
96 15002     GlobusSoapMessageDebugExit();
97 out:
98 15002     return result;
99 }
100
101 /**
102  * Copy the contents of a SOAP Message Attribute Set to a new Attribute Set
103  * @ingroup globus_soap_message_attrs
104  *
105  * @param copied_attrs
106  *     Attribute set to be initialized to contain the same attributes as
107  *     @a attrs.
108  * @param attrs
109  *     Attribute set to copy.
110  *
111  * @retval GLOBUS_SUCCESS
112  *     Attributes successfully copied.
113  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
114  *     The @a copied_attrs or @a attrs parameter was NULL.
115  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
116  *     Insufficient memory to copy the attributes.
117  */
118 globus_result_t
119 globus_soap_message_attr_copy(
120     globus_soap_message_attr_t *        copied_attrs,
121     globus_soap_message_attr_t          attrs)
122 5027 {
123 5027     globus_soap_message_attr_t          new_attrs;
124 5027     globus_l_message_attr_t *           attr;
125 5027     globus_result_t                     result = GLOBUS_SUCCESS;
126 5027     GlobusFuncName(globus_soap_message_attr_copy);
127 5027     GlobusSoapMessageDebugEnter();
128
129 5027     if (attrs == NULL || copied_attrs == NULL)
130     {
131 0         result = GlobusSoapMessageErrorNullParam;
132
133 0         goto error_exit;
134     }
135
136 5027     result = globus_soap_message_attr_init(&new_attrs);
137
138 5027     if (result != GLOBUS_SUCCESS)
139     {
140 0         goto error_exit;
141     }
142
143 5027     attr = globus_hashtable_first(&attrs);
144 23106     while(attr)
145     {
146         /* _set will copy the attr value */
147 18079         result = globus_soap_message_attr_set(
148             new_attrs,
149             attr->name,
150             attr->copy,
151             attr->destroy,
152             attr->value);
153 18079         if(result != GLOBUS_SUCCESS)
154         {
155 0             goto free_attrs_error;
156         }
157
158 18079         attr = globus_hashtable_next(&attrs);
159     }
160
161 5027     *copied_attrs = new_attrs;
162
163
164 free_attrs_error:
165 5027     if (result != GLOBUS_SUCCESS)
166     {
167 0         globus_hashtable_destroy_all(
168             &new_attrs, globus_l_message_attr_destroy);
169 error_exit:
170 0         GlobusSoapMessageDebugError(result);
171     }
172 5027     GlobusSoapMessageDebugExit();
173 5027     return result;
174 }
175 /* globus_soap_message_attr_copy() */
176
177 /**
178  * Destroy a SOAP Message Attribute Set
179  * @ingroup globus_soap_message_attrs
180  *
181  * @param attrs
182  *     Attribute set to destroy.
183  */
184 void
185 globus_soap_message_attr_destroy(
186     globus_soap_message_attr_t                  attrs)
187 14936 {
188 14936     GlobusFuncName(globus_soap_message_attr_destroy);
189 14936     GlobusSoapMessageDebugEnter();
190
191 14936     globus_hashtable_destroy_all(
192         &attrs, globus_l_message_attr_destroy);
193
194 14936     GlobusSoapMessageDebugExit();
195 }
196 /* globus_soap_message_attr_destroy() */
197
198 /**
199  * Set the value of an attribute
200  * @ingroup globus_soap_message_attrs
201  *
202  * @param attrs
203  *     Attribute set to modify.
204  * @param name
205  *     Name of the attribute to set.
206  * @param copy
207  *     Function to make a copy of the attribute value. If this is NULL, then
208  *     the attribute value will be treated as a scalar.
209  * @param destroy
210  *     Function to destroy a copy of the attribute value.  This may be NULL if
211  *     the attribute value is a scalar.
212  * @param attrvalue
213  *     Value to set the attribute to.
214  *
215  * @retval GLOBUS_SUCCESS
216  *     Attributes successfully set.
217  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
218  *     The @a attrs or @a name parameter was NULL.
219  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
220  *     Insufficient memory to set the attribute.
221  */
222 globus_result_t
223 globus_soap_message_attr_set(
224     globus_soap_message_attr_t               attrs,
225     const char *                             name,
226     globus_soap_message_attr_copy_func_t     copy,
227     globus_soap_message_attr_destroy_func_t  destroy,
228     void *                                   attrvalue)
229 115005 {
230 115005     void *                              newvalue = NULL;
231 115005     globus_result_t                     result = GLOBUS_SUCCESS;
232 115005     globus_l_message_attr_t *           attr;
233 115005     GlobusFuncName(globus_soap_message_attr_set);
234 115005     GlobusSoapMessageDebugEnter();
235
236 115005     if (attrs == NULL || name == NULL)
237     {
238 0         result = GlobusSoapMessageErrorNullParam;
239
240 0         goto error_exit;
241     }
242 115005     if(copy)
243     {
244 56514         result = copy(&newvalue, attrvalue);
245
246 56514         if (result != GLOBUS_SUCCESS)
247         {
248 0             goto error_exit;
249         }
250     }
251     else
252     {
253 58491         newvalue = attrvalue;
254     }
255     
256 115005     attr = globus_hashtable_lookup(&attrs, (char *)name);
257 115005     if(!attr)
258     {
259 93834         attr = malloc(sizeof(globus_l_message_attr_t));
260 93834         if(!attr)
261         {
262 0             result = GlobusSoapMessageErrorOutOfMemory;
263 0             goto error_exit;
264         }
265 93834         memset(attr, 0, sizeof(globus_l_message_attr_t));
266
267 93834         attr->name = globus_libc_strdup(name);
268 93834         if (!attr->name)
269         {
270 0             result = GlobusSoapMessageErrorOutOfMemory;
271
272 0             goto free_attr_exit;
273         }
274 93834         attr->destroy = destroy;
275 93834         attr->copy = copy;
276
277 93834         result = globus_hashtable_insert(&attrs, 
278                                          attr->name, attr);
279 93834         if(result != GLOBUS_SUCCESS)
280         {
281 0             result = GlobusSoapMessageErrorOutOfMemory;
282             
283 0             goto free_attr_name_exit;
284         }
285     }
286     else
287     {
288 21171         if(attr->destroy)
289         {
290 10360             attr->destroy(attr->value);
291         }
292
293 21171         attr->destroy = destroy;
294 21171         attr->copy = copy;
295     }
296 115005     attr->value = newvalue;
297
298 115005     if (result != GLOBUS_SUCCESS)
299     {
300 free_attr_name_exit:
301 0         free(attr->name);
302 free_attr_exit:
303 0         free(attr);
304 error_exit:
305 0         GlobusSoapMessageDebugError(result);
306     }
307 115005     GlobusSoapMessageDebugExit();
308 115005     return result;
309 }
310 /* globus_soap_message_attr_set() */
311
312 /**
313  * Set the value of an attribute on a handle
314  * @ingroup globus_soap_message_attrs
315  *
316  * @param handle
317  *     Handle whose attributes will be modified.
318  * @param attr_name
319  *     Name of the attribute to set.
320  * @param copy
321  *     Function to make a copy of the attribute value. If this is NULL, then
322  *     the attribute value will be treated as a scalar.
323  * @param destroy
324  *     Function to destroy a copy of the attribute value.  This may be NULL if
325  *     the attribute value is a scalar.
326  * @param attrvalue
327  *     Value to set the attribute to.
328  *
329  * @retval GLOBUS_SUCCESS
330  *     Attributes successfully set.
331  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
332  *     The @a handle or @a name parameter was NULL.
333  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
334  *     Insufficient memory to set the attribute.
335  */
336 globus_result_t
337 globus_soap_message_handle_set_attr(
338     globus_soap_message_handle_t             handle,
339     const char *                             attr_name,
340     globus_soap_message_attr_copy_func_t     copy,
341     globus_soap_message_attr_destroy_func_t  destroy,
342     void *                                   attrvalue)
343 81619 {
344 81619     globus_result_t                     result = GLOBUS_SUCCESS;
345 81619     GlobusFuncName(globus_soap_message_handle_set_attr);
346 81619     GlobusSoapMessageDebugEnter();
347
348 81619     if (handle == NULL || attr_name == NULL)
349     {
350 0         result = GlobusSoapMessageErrorNullParam;
351
352 0         goto error_exit;
353     }
354
355 81619     if (handle->attrs == NULL)
356     {
357 0         result = globus_soap_message_attr_init(&handle->attrs);
358
359 0         if (result != GLOBUS_SUCCESS)
360         {
361 0             goto error_exit;
362         }
363     }
364
365 81619     result = globus_soap_message_attr_set(
366         handle->attrs,
367         attr_name,
368         copy,
369         destroy,
370         attrvalue);
371
372 81619     if (result != GLOBUS_SUCCESS)
373     {
374 0         goto error_exit;
375     }
376     /* Hack: make the verbose attribute part of the handle struct for
377      * performance as its queried during all serialization and deserialization
378      * errors.
379      */
380 81619     if (strcmp(attr_name, GLOBUS_SOAP_MESSAGE_VERBOSE_ERRORS_KEY) == 0)
381     {
382 44         handle->verbose = (globus_bool_t) attrvalue;
383     }
384     
385 error_exit:
386 81619     GlobusSoapMessageDebugExit();
387 81619     return result;
388 }
389 /* globus_soap_message_handle_set_attr() */
390
391 /**
392  * Remove an attribute from an attribute set
393  * @ingroup globus_soap_message_attrs
394  *
395  * @param attrs
396  *     Attribute set to modify.
397  * @param attr_name
398  *     Name of the attribute to remove from the attribute set. Its current
399  *     value will be returned.
400  *
401  * @return
402  *     Returns the current value of the named attribute. This value is not
403  *     managed by the handle and should be freed by the caller if it is a 
404  *     non-scalar value.
405  */
406 void *
407 globus_soap_message_attr_remove(
408     globus_soap_message_attr_t          attrs,
409     const char *                        attr_name)
410 0 {
411 0     void *                              value;
412 0     globus_l_message_attr_t *           attr;
413 0     GlobusFuncName(globus_soap_message_attr_remove);
414 0     GlobusSoapMessageDebugEnter();
415     
416 0     if (attrs == NULL || attr_name == NULL)
417     {
418 0         value = NULL;
419
420 0         goto exit;
421     }
422 0     attr = globus_hashtable_remove(&attrs, (void *)attr_name);
423 0     if(!attr)
424     {
425 0         value = NULL;
426 0         goto exit;
427     }
428
429 0     value = attr->value;
430 0     attr->value = NULL;
431
432 0     globus_l_message_attr_destroy(attr);
433
434  exit:
435
436 0     GlobusSoapMessageDebugExit();
437 0     return value;
438 }
439 /* globus_soap_message_attr_remove() */
440
441 /**
442  * Remove an attribute from a handle's attribute set
443  * @ingroup globus_soap_message_attrs
444  *
445  * @param handle
446  *     Handle to modify.
447  * @param attr_name
448  *     Name of the attribute to remove from the handle's attribute set. Its
449  *     current value will be returned.
450  *
451  * @return
452  *     Returns the current value of the named attribute. This value is not
453  *     managed by the handle and should be freed by the caller if it is a 
454  *     non-scalar value.
455  */
456 void *
457 globus_soap_message_handle_remove_attr(
458     globus_soap_message_handle_t        handle,
459     const char *                        attr_name)
460 0 {
461 0     if (handle == NULL)
462     {
463 0         return NULL;
464     }
465 0     return globus_soap_message_attr_remove(
466         handle->attrs, attr_name);
467 }
468 /* globus_soap_message_handle_remove_attr() */
469
470 /**
471  * Get the current value of a SOAP message attribute
472  * @ingroup globus_soap_message_attrs
473  *
474  * @param attrs
475  *     Attribute set to query.
476  * @param attr_name
477  *     Name of the attribute to retrieve.
478  *
479  * @return
480  *     Returns the current value of the named attribute. This value is managed
481  *     by the handle and should not be freed or modified by the caller.
482  */
483 void *
484 globus_soap_message_attr_get(
485     globus_soap_message_attr_t          attrs,
486     const char *                        attr_name)
487 179623 {
488 179623     void *                              value;
489 179623     globus_l_message_attr_t *           attr;
490 179623     GlobusFuncName(globus_soap_message_attr_get);
491 179623     GlobusSoapMessageDebugEnter();
492
493 179623     if (attrs == NULL || attr_name == NULL)
494     {
495 0         value = NULL;
496
497 0         goto exit;
498     }
499 179623     attr = globus_hashtable_lookup(&attrs, (char *)attr_name);
500 179623     if(!attr)
501     {
502 87817         value = NULL;
503 87817         goto exit;
504     }
505
506 91806     value = attr->value;
507
508  exit:
509     
510 179623     GlobusSoapMessageDebugExit();
511 179623     return value;
512 }
513 /* globus_soap_message_attr_get() */
514     
515 /**
516  * Get the current value of a SOAP message attribute from a handle
517  * @ingroup globus_soap_message_attrs
518  *
519  * @param handle
520  *     Handle to query.
521  * @param attr_name
522  *     Name of the attribute to retrieve.
523  *
524  * @return
525  *     Returns the current value of the named attribute. This value is managed
526  *     by the handle and should not be freed or modified by the caller.
527  */
528 void *
529 globus_soap_message_handle_get_attr(
530     globus_soap_message_handle_t        handle,
531     char *                              attr_name)
532 163147 {
533 163147     void *                              value;
534 163147     GlobusFuncName(globus_soap_message_handle_get_attr);
535 163147     GlobusSoapMessageDebugEnter();
536
537 163147     if (handle == NULL || attr_name == NULL)
538     {
539 0         value = NULL;
540
541 0         goto exit;
542     }
543
544 163147     value = globus_soap_message_attr_get(
545         handle->attrs,
546         attr_name);
547
548 exit:
549 163147     GlobusSoapMessageDebugExit();
550 163147     return value;
551 }
552 /* globus_soap_message_handle_get_attr() */
553
554 /**
555  * Copy a SOAP message attribute set to a handle
556  * @ingroup globus_soap_message_attrs
557  *
558  * Replaces all of the attributes in an SOAP message handle with those in the
559  * given attribute set.
560  *
561  * @param handle
562  *     Handle to modify. If this function is successfull, all attributes
563  *     set on the handle will be freed and a copy of the attributes in 
564  *     @a attrs will be set on the handle.
565  * @param attrs
566  *     New attributes to set on the handle.
567  *
568  * @retval GLOBUS_SUCCESS
569  *     Attributes successfully set.
570  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
571  *     The @a handle or @a attrs parameter was NULL.
572  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
573  *     Insufficient memory to copy the attributes.
574  */
575 globus_result_t
576 globus_soap_message_handle_set_attrs(
577     globus_soap_message_handle_t        handle,
578     globus_soap_message_attr_t          attrs)
579 4972 {
580 4972     globus_result_t                     result;
581 4972     globus_soap_message_attr_t          tmp_attrs;
582 4972     GlobusFuncName(globus_soap_message_handle_set_attr);
583 4972     GlobusSoapMessageDebugEnter();
584
585 4972     if (handle == NULL || attrs == NULL)
586     {
587 0         result = GlobusSoapMessageErrorNullParam;
588
589 0         goto exit;
590     }
591 4972     tmp_attrs = handle->attrs;
592
593 4972     result = globus_soap_message_attr_copy(
594         &handle->attrs, attrs);
595
596 4972     if (result != GLOBUS_SUCCESS)
597     {
598 0         handle->attrs = tmp_attrs;
599 0         goto exit;
600     }
601     /* Hack: make the verbose attribute part of the handle struct for
602      * performance as its queried during all serialization and deserialization
603      * errors.
604      */
605 4972     handle->verbose = (globus_bool_t) globus_soap_message_attr_get(
606                 attrs,
607                 GLOBUS_SOAP_MESSAGE_VERBOSE_ERRORS_KEY);
608
609
610 4972     if(tmp_attrs);
611     {
612 4972         globus_soap_message_attr_destroy(tmp_attrs);
613     }
614 4972     GlobusSoapMessageDebugExit();
615 exit:
616 4972     return result;
617 }
618 /* globus_soap_message_handle_set_attrs() */
619
620 /**
621  * String copy wrapper for SOAP Message Attributes
622  * @ingroup globus_soap_message_attrs
623  *
624  * A version of strdup which matches the globus_soap_message_attr_copy_func_t
625  * function signature.
626  *
627  * @param new_str
628  * @param str
629  *
630  * @retval GLOBUS_SUCCESS
631  *     String successfully copied.
632  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
633  *     The @a new_str or @a str parameter was NULL.
634  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
635  *     Insufficient memory to copy the string.
636  */
637 globus_result_t
638 globus_soap_message_attr_copy_string(
639     void **                             new_str,
640     const void *                        str)
641 28792 {
642 28792     globus_result_t                     result = GLOBUS_SUCCESS;
643
644 28792     if (new_str == NULL || str == NULL)
645     {
646 0         result = GlobusSoapMessageErrorNullParam;
647
648 0         goto exit;
649     }
650 28792     *new_str = (void *) globus_libc_strdup((char *)str);
651
652 28792     if (*new_str == NULL)
653     {
654 0         result = GlobusSoapMessageErrorOutOfMemory;
655
656         goto exit;
657     }
658
659 exit:
660 28792     return result;
661 }