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_fault.h"
18 #include "globus_soap_message_utils.h"
19
20 /**
21 * @defgroup globus_soap_message_fault SOAP Message Fault handling
22 *
23 * SOAP messages may contain fault information indicating that an error
24 * occurred, either processing a message or handling an operation. These
25 * may be converted to and from <code>globus_object_t</code>-style errors.
26 */
27
28 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
29 static
30 void
31 globus_l_soap_message_fault_copy(
32 void * src,
33 void ** dst);
34
35 static
36 char *
37 globus_l_soap_message_fault_printable(
38 globus_object_t * error);
39
40
41 globus_object_type_t globus_i_soap_fault_type =
42 {
43 GLOBUS_ERROR_TYPE_BASE,
44 globus_l_soap_message_fault_copy,
45 globus_soap_message_fault_destroy,
46 globus_l_soap_message_fault_printable
47 };
48 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
49
50 /**
51 * Initialize a new fault
52 * @ingroup globus_soap_message_fault
53 * Allocates a new fault structure and sets its initial value.
54 *
55 * @param fault
56 * Fault to initialize. After returning, this will be set to point
57 * to a new fault structure. The caller is responsible for destroying
58 * this fault.
59 *
60 * @retval GLOBUS_SUCCESS
61 * Fault initialized successfully.
62 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
63 * The @a fault parameter is NULL.
64 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
65 * Insufficient memory to allocate the new fault structure.
66 */
67 globus_result_t
68 globus_soap_message_fault_init(
69 globus_soap_message_fault_t * fault)
70 252 {
71 252 globus_result_t result = GLOBUS_SUCCESS;
72 GlobusFuncName(globus_soap_message_fault_init);
73 252 GlobusSoapMessageDebugEnter();
74
75 252 if (fault == NULL)
76 {
77 0 result = GlobusSoapMessageErrorNullParam;
78
79 0 goto exit;
80 }
81 252 *fault = calloc(1, sizeof(struct globus_soap_message_fault_s));
82 252 if(!*fault)
83 {
84 0 result = GlobusSoapMessageErrorOutOfMemory;
85 0 goto exit;
86 }
87
88 252 exit:
89 252 GlobusSoapMessageDebugExit();
90 252 return result;
91 }
92 /* globus_soap_message_fault_init() */
93
94 /**
95 * Destroy a fault
96 * @ingroup globus_soap_message_fault
97 *
98 * @param f
99 * Pointer to the fault to destroy, cast to a <code>void *</code>.
100 */
101 void
102 globus_soap_message_fault_destroy(
103 void * f)
104 132 {
105 globus_soap_message_fault_t fault;
106 GlobusFuncName(globus_soap_message_fault_destroy);
107 132 GlobusSoapMessageDebugEnter();
108
109 132 fault = (globus_soap_message_fault_t) f;
110
111 132 if(fault)
112 {
113 132 if(fault->faultcode)
114 {
115 132 free(fault->faultcode);
116 }
117
118 132 if(fault->faultstring)
119 {
120 132 free(fault->faultstring);
121 }
122
123 132 if(fault->faultactor)
124 {
125 0 free(fault->faultactor);
126 }
127
128 132 if(fault->detail)
129 {
130 132 xsd_any_destroy(fault->detail);
131 }
132
133 132 free(fault);
134 }
135
136 132 GlobusSoapMessageDebugExit();
137 132 }
138 /* globus_soap_message_fault_destroy() */
139
140 /**
141 * Create a globus_object_t-style error from a fault
142 * @ingroup globus_soap_fault
143 * Returns a newly allocated <code>globus_object_t *</code> of type
144 * GLOBUS_SOAP_FAULT_TYPE. The new object becomes the owner of the fault passed
145 * to it. The object returned must be freed by the caller by calling
146 * globus_object_free()
147 *
148 * @param fault
149 * Fault to wrap as a globus_object_t
150 *
151 * @return
152 * This function returns the new object if successful, NULL otherwise.
153 */
154 globus_object_t *
155 globus_soap_message_fault_object_initialize(
156 globus_soap_message_fault_t fault)
157 252 {
158 globus_object_t * obj;
159 GlobusFuncName(globus_soap_message_fault_object_initialize);
160 252 GlobusSoapMessageDebugEnter();
161
162 252 obj = globus_object_construct(GLOBUS_SOAP_FAULT_TYPE);
163 252 globus_object_set_local_instance_data(obj, fault);
164 252 obj = globus_error_initialize_base(obj, GLOBUS_SOAP_MESSAGE_MODULE, NULL);
165
166 252 GlobusSoapMessageDebugExit();
167 252 return obj;
168 }
169 /* globus_soap_message_fault_object_initialize() */
170
171 /**
172 * Predicate returning true if @a obj is a GLOBUS_SOAP_FAULT_TYPE object
173 * @ingroup globus_soap_fault
174 * Returns GLOBUS_TRUE of @a obj is an error of type GLOBUS_SOAP_FAULT_TYPE or
175 * was caused by an error of that type.
176 *
177 * @param obj
178 * Object to probe.
179 *
180 * @retval GLOBUS_TRUE
181 * The @a obj is a GLOBUS_SOAP_FAULT_TYPE error or was caused by that
182 * type of error.
183 * @retval GLOBUS_FALSE
184 * The @a obj is not and is not caused by a GLOBUS_SOAP_FAULT_TYPE error.
185 */
186 globus_bool_t
187 globus_soap_message_is_fault(
188 globus_object_t * obj)
189 0 {
190 globus_object_t * errobj;
191 0 globus_bool_t res = GLOBUS_FALSE;
192 GlobusFuncName(globus_soap_message_is_fault);
193 0 GlobusSoapMessageDebugEnter();
194
195 0 errobj = obj;
196 0 while(globus_object_get_type(errobj) == GLOBUS_ERROR_TYPE_GLOBUS &&
197 globus_error_get_cause(errobj))
198 {
199 0 errobj = globus_error_get_cause(errobj);
200 }
201
202 0 if(globus_object_get_type(errobj) == GLOBUS_SOAP_FAULT_TYPE)
203 {
204 0 res = GLOBUS_TRUE;
205 }
206
207 0 GlobusSoapMessageDebugExit();
208 0 return res;
209 }
210 /* globus_soap_message_is_fault() */
211
212 /**
213 * Extracts a SOAP from a globus_object_t
214 * @ingroup globus_soap_message_fault
215 * Removes the first globus_soap_message_fault_t instance data it finds in
216 * the causality chain of @a obj and returns it. The obj is modified to no
217 * longer refer to the returned value. The caller is responsible for
218 * destroying the returned globus_soap_message_fault_t.
219 *
220 * @param obj
221 * Object to search for a SOAP fault.
222 *
223 * @return
224 * If @a obj is a GLOBUS_SOAP_FAULT_TYPE object or caused by one, then
225 * the first globus_soap_message_fault_t instace found in the causality
226 * chain is returned. Otherwise, NULL is returned.
227 */
228 globus_soap_message_fault_t
229 globus_soap_message_fault_get(
230 globus_object_t * obj)
231 4 {
232 globus_object_t * errobj;
233 4 globus_soap_message_fault_t soap_fault = NULL;
234 4 globus_object_t * parentobj = NULL;
235 GlobusFuncName(globus_soap_message_fault_get);
236 4 GlobusSoapMessageDebugEnter();
237
238 4 errobj = obj;
239 10 while(globus_object_get_type(errobj) == GLOBUS_ERROR_TYPE_GLOBUS &&
240 globus_error_get_cause(errobj))
241 {
242 2 parentobj = errobj;
243 2 errobj = globus_error_get_cause(errobj);
244 }
245
246 4 if(globus_object_get_type(errobj) == GLOBUS_SOAP_FAULT_TYPE)
247 {
248 0 soap_fault = errobj->instance_data;
249 0 errobj->instance_data = NULL;
250 0 globus_object_free(errobj);
251 0 if(parentobj)
252 {
253 0 globus_error_set_cause(
254 parentobj, (globus_object_t *)GLOBUS_FAILURE);
255 }
256 }
257
258 4 GlobusSoapMessageDebugExit();
259 4 return soap_fault;
260 }
261 /* globus_soap_message_fault_get() */
262
263 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
264 static
265 void
266 globus_l_soap_message_fault_copy(
267 void * src,
268 void ** dst)
269 0 {
270 globus_soap_message_fault_t src_fault =
271 0 (globus_soap_message_fault_t) src;
272 globus_soap_message_fault_t dest_fault;
273 GlobusFuncName(globus_l_soap_message_fault_copy);
274 0 GlobusSoapMessageDebugEnter();
275
276 0 dest_fault = globus_calloc(1, sizeof(struct globus_soap_message_fault_s));
277 0 if(dest_fault)
278 {
279 0 if(src_fault->faultcode)
280 {
281 0 dest_fault->faultcode = globus_libc_strdup(src_fault->faultcode);
282 }
283
284 0 if(src_fault->faultstring)
285 {
286 0 dest_fault->faultstring =
287 globus_libc_strdup(src_fault->faultstring);
288 }
289
290 0 if(src_fault->faultactor)
291 {
292 0 dest_fault->faultactor = globus_libc_strdup(src_fault->faultactor);
293 }
294
295 0 if(src_fault->detail)
296 {
297 0 xsd_any_copy(&dest_fault->detail, src_fault->detail);
298 }
299 }
300
301 0 *dst = dest_fault;
302 0 GlobusSoapMessageDebugExit();
303 0 }
304 /* globus_l_soap_message_fault_copy() */
305
306 static
307 char *
308 globus_l_soap_message_fault_printable(
309 globus_object_t * error)
310 6 {
311 globus_soap_message_fault_t fault;
312 const char * layout[9];
313 6 char * buffer = NULL;
314 char * str;
315 6 int i = 0;
316 6 globus_bool_t newline = GLOBUS_FALSE;
317
318 6 fault = (globus_soap_message_fault_t)
319 globus_object_get_local_instance_data(error);
320
321 6 if(fault->faultcode)
322 {
323 6 layout[i++] = "Fault code: ";
324 6 layout[i++] = fault->faultcode;
325 6 newline = GLOBUS_TRUE;
326 }
327
328 6 if(fault->faultstring)
329 {
330 6 layout[i++] = newline ? "\nFault string: " : "Fault string: ";
331 6 layout[i++] = fault->faultstring;
332 6 newline = GLOBUS_TRUE;
333 }
334
335 6 if(fault->faultactor)
336 {
337 0 layout[i++] = newline ? "\nFault actor: " : "Fault actor: ";
338 0 layout[i++] = fault->faultactor;
339 0 newline = GLOBUS_TRUE;
340 }
341
342 6 if(globus_i_error_verbose && fault->detail &&
343 fault->detail->any_info == &globus_xml_buffer_contents_info)
344 {
345 globus_xml_buffer * xml_buffer;
346
347 0 xml_buffer = (globus_xml_buffer *) fault->detail->value;
348 0 if(xml_buffer->length > 0)
349 {
350 0 buffer = (char *) globus_malloc(
351 sizeof(char) * xml_buffer->length + 1);
352 0 if(buffer)
353 {
354 0 memcpy(buffer, xml_buffer->buffer, xml_buffer->length);
355 0 buffer[xml_buffer->length] = 0;
356 0 layout[i++] = newline ? "\nFault detail:\n" : "Fault detail:\n";
357 0 layout[i++] = buffer;
358 }
359 }
360 }
361
362 6 str = globus_libc_join(layout, i);
363
364 6 if(buffer)
365 {
366 0 globus_free(buffer);
367 }
368
369 6 return str;
370 }
371 /* globus_l_soap_message_fault_printable() */