| 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() */ |