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_common.h"
18 #include "globus_xsd_types.h"
19 #include "globus_i_handler_chain.h"
20 #include "globus_extension.h"
21 #include "globus_soap_message.h"
22 #include "globus_soap_message_utils.h"
23 #include "xsd_QName.h"
24 #include "version.h"
25
26 /**
27 * @defgroup globus_handler_chain SOAP Handler Chains
28 *
29 * Handler chains are lists of functions which are invoked at various times
30 * during SOAP message processing as a way to extend functionality of the
31 * SOAP messaging stack. Functionality such as adding WS-Addressing headers or
32 * providing debug information may be done via handlers. Applications may add
33 * additional message handling functionality by pushing handlers onto a handler
34 * chain associated with a service engine, client handle, or SOAP message
35 * handle.
36 *
37 * Two types of handlers are supported: those which are called during
38 * particular stages of the SOAP message processing, and those which are
39 * triggered by the presence of certain elements within a SOAP header.
40 *
41 * The first type of handlers are called by the SOAP processing at
42 * <table>
43 * <tr>
44 * <th>Handler type</th>
45 * <th>Handler descriptor field</th>
46 * <th>Description</th>
47 * </tr>
48 * <tr>
49 * <td>GLOBUS_HANDLER_TYPE_REQUEST_INIT</td>
50 * <td>request_init</td>
51 * <td>On the client, this is called before the HTTP handle which will be
52 * used to serialize the SOAP message has been opened. On the server,
53 * it is called after the SOAP request has been read but before it has
54 * been parsed.
55 * </td>
56 * </tr>
57 * <tr>
58 * <td>GLOBUS_HANDLER_TYPE_REQUEST</td>
59 * <td>request</td>
60 * <td>On the client, this is called after the SOAP body has been serialized
61 * but before the SOAP envelope headers have been serialized. On the
62 * server, it is called after the SOAP envelope headers triggers
63 * have been called to parse the envelope before the operation has been
64 * invoked.
65 * </td>
66 * </tr>
67 * <tr>
68 * <td>GLOBUS_HANDLER_TYPE_REQUEST_DESTROY</td>
69 * <td>request_destroy</td>
70 * <td>On the client, this is called after the SOAP request message has
71 * been sent. On the server, it is called after the
72 * GLOBUS_HANDLER_TYPE_REQUEST handlers.
73 * </td>
74 * </tr>
75 * <tr>
76 * <td>GLOBUS_HANDLER_TYPE_RESPONSE_INIT</td>
77 * <td>response_init</td>
78 * <td>On the client, this is called after the SOAP request message has
79 * been sent. On the server, it is called after the
80 * GLOBUS_HANDLER_TYPE_REQUEST handlers.
81 * </td>
82 * </tr>
83 * <tr>
84 * <td>GLOBUS_HANDLER_TYPE_RESPONSE</td>
85 * <td>response</td>
86 * <td>On the client, this is called after the SOAP header triggers have
87 * been called to process SOAP envelope header elements. On the server,
88 * this is called after the operation has completed and serialized its
89 * response. The SOAP
90 * message handle will be set to write to the SOAP envelope headers.
91 * </td>
92 * </tr>
93 * <tr>
94 * <td>GLOBUS_HANDLER_TYPE_RESPONSE_DESTROY</td>
95 * <td>response_destroy</td>
96 * <td>On the client, this is not called. On the server, this is called
97 * after the GLOBUS_HANDLER_TYPE_RESPONSE handlers just prior to the
98 * response message being sent.
99 * </td>
100 * </tr>
101 * </table>
102 */
103 globus_extension_registry_t globus_handler_registry =
104 {
105 NULL,
106 GLOBUS_FALSE,
107 GLOBUS_FALSE
108 };
109
110 0 GlobusDebugDefine(GLOBUS_HANDLER);
111
112 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
113 static globus_list_t * globus_l_handler_extensions = NULL;
114 static globus_mutex_t globus_l_handler_extensions_mutex;
115
116 static
117 int
118 globus_l_handler_activate(void);
119
120 static
121 int
122 globus_l_handler_deactivate(void);
123
124 static
125 void
126 globus_l_handler_extension_destroy(
127 void * ep);
128
129 static
130 void
131 globus_l_handler_destroy(
132 void * h);
133
134 static
135 globus_result_t
136 globus_l_handler_chain_copy(
137 globus_list_t ** dest,
138 globus_list_t * src);
139
140 static
141 void
142 globus_l_handler_hash_entry_copy(
143 void ** dest_key,
144 void ** dest_datum,
145 void * src_key,
146 void * src_datum);
147
148 static
149 globus_result_t
150 globus_l_handler_chain_push(
151 globus_list_t ** chain,
152 globus_extension_handle_t extension_handle,
153 globus_handler_invoke_func_t invoke,
154 globus_bool_t last);
155
156 globus_module_descriptor_t globus_i_handler_module =
157 {
158 "globus_handler",
159 globus_l_handler_activate,
160 globus_l_handler_deactivate,
161 GLOBUS_NULL,
162 GLOBUS_NULL,
163 &local_version
164 };
165
166 typedef struct globus_l_handler_s
167 {
168 globus_extension_handle_t extension_handle;
169 globus_handler_invoke_func_t invoke;
170 globus_handler_trigger_t * trigger;
171 } globus_l_handler_t;
172
173 static
174 globus_result_t
175 globus_l_handler_triggers_insert(
176 globus_hashtable_t * triggers,
177 globus_extension_handle_t ext,
178 globus_list_t * trigger_list);
179
180 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
181
182 /**
183 * Initialize a new handler chain
184 * @ingroup globus_handle_chain
185 *
186 * @param chain
187 * Pointer to location to set to the new handler chain.
188 *
189 * @retval GLOBUS_SUCCESS
190 * Handler chain intialized successfully.
191 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
192 * The @a chain parameter was NULL.
193 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
194 * Insufficient memory to initialize the handler chain.
195 */
196 globus_result_t
197 globus_handler_chain_init(
198 globus_handler_chain_t * chain)
199 51340 {
200 globus_handler_chain_t new_chain;
201 51340 globus_result_t result = GLOBUS_SUCCESS;
202
203 GlobusFuncName(globus_handler_chain_init);
204 51340 GlobusHandlerDebugEnter();
205
206 51340 if (chain == NULL)
207 {
208 0 result = GlobusSoapMessageErrorNullParam;
209
210 0 goto exit;
211 }
212 51340 new_chain = calloc(1, sizeof(globus_i_handler_chain_t));
213 51340 if(!new_chain)
214 {
215 0 result = GlobusSoapMessageErrorOutOfMemory;
216 }
217
218 51340 *chain = new_chain;
219
220 51340 exit:
221 51340 GlobusHandlerDebugExit();
222 51340 return result;
223 }
224 /* globus_handler_chain_init() */
225
226 /**
227 * Destroy all state associated with a handler chain
228 * @ingroup globus_handler_chain
229 *
230 * Destroys the handler chain and frees all memory associated with it. The
231 * chain referred to by @a chain should not be used after this function returns.
232 *
233 * @param chain
234 * The handler chain to destroy.
235 */
236 void
237 globus_handler_chain_destroy(
238 globus_handler_chain_t chain)
239 62808 {
240 globus_extension_handle_t ext;
241 globus_list_t * extensions;
242 GlobusFuncName(globus_handler_chain_init);
243 62808 GlobusHandlerDebugEnter();
244
245 62808 globus_list_destroy_all(chain->request_handlers,
246 globus_l_handler_destroy);
247 62808 globus_list_destroy_all(chain->response_handlers,
248 globus_l_handler_destroy);
249 62808 globus_list_destroy_all(chain->request_init_handlers,
250 globus_l_handler_destroy);
251 62808 globus_list_destroy_all(chain->request_destroy_handlers,
252 globus_l_handler_destroy);
253 62808 globus_list_destroy_all(chain->response_init_handlers,
254 globus_l_handler_destroy);
255 62808 globus_list_destroy_all(chain->response_destroy_handlers,
256 globus_l_handler_destroy);
257 62808 if(chain->triggers)
258 {
259 12281 globus_hashtable_destroy_all(
260 &chain->triggers,
261 globus_l_handler_destroy);
262 }
263
264 62808 extensions = chain->extensions;
265 150178 while(extensions)
266 {
267 24562 ext = globus_list_first(extensions);
268 24562 globus_extension_release(ext);
269 24562 extensions = globus_list_rest(extensions);
270 }
271
272 62808 globus_list_free(chain->extensions);
273
274 62808 globus_free(chain);
275
276 62808 GlobusHandlerDebugExit();
277 62808 }
278 /* globus_handler_chain_destroy() */
279
280 /**
281 * Create a copy of a handler chain
282 * @ingroup globus_handler_chain
283 *
284 * @param dest
285 * Pointer to hold the location of the new handler chain. This must
286 * be destroyed by the caller.
287 * @param src
288 * Handler chain to copy.
289 *
290 * @retval GLOBUS_SUCCESS
291 * Handler chain successfully copied.
292 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
293 * One of @a src or @a dest was NULL.
294 */
295 globus_result_t
296 globus_handler_chain_copy(
297 globus_handler_chain_t * dest,
298 globus_handler_chain_t src)
299 12045 {
300 globus_extension_handle_t ext;
301 globus_list_t * extensions;
302 globus_handler_chain_t new_chain;
303 int rc;
304 12045 globus_result_t result = GLOBUS_SUCCESS;
305
306 GlobusFuncName(globus_handler_chain_copy);
307 12045 GlobusHandlerDebugEnter();
308
309 12045 if (dest == NULL)
310 {
311 0 result = GlobusSoapMessageErrorNullParam;
312
313 0 goto exit;
314 }
315 12045 *dest = NULL;
316 12045 if (src == NULL)
317 {
318 0 result = GlobusSoapMessageErrorNullParam;
319
320 0 goto exit;
321 }
322 12045 new_chain = calloc(1, sizeof(globus_i_handler_chain_t));
323 12045 if(!new_chain)
324 {
325 0 result = GlobusSoapMessageErrorOutOfMemory;
326 0 goto exit;
327 }
328
329 12045 result = globus_l_handler_chain_copy(
330 &new_chain->request_handlers, src->request_handlers);
331 12045 if(result != GLOBUS_SUCCESS)
332 {
333 0 goto error;
334 }
335
336 12045 result = globus_l_handler_chain_copy(
337 &new_chain->response_handlers, src->response_handlers);
338 12045 if(result != GLOBUS_SUCCESS)
339 {
340 0 goto destroy_request_handlers;
341 }
342
343 12045 result = globus_l_handler_chain_copy(
344 &new_chain->request_init_handlers, src->request_init_handlers);
345 12045 if(result != GLOBUS_SUCCESS)
346 {
347 0 goto destroy_response_handlers;
348 }
349
350 12045 result = globus_l_handler_chain_copy(
351 &new_chain->request_destroy_handlers, src->request_destroy_handlers);
352 12045 if(result != GLOBUS_SUCCESS)
353 {
354 0 goto destroy_request_init_handlers;
355 }
356
357 12045 result = globus_l_handler_chain_copy(
358 &new_chain->response_init_handlers, src->response_init_handlers);
359 12045 if(result != GLOBUS_SUCCESS)
360 {
361 0 goto destroy_request_destroy_handlers;
362 }
363
364 12045 result = globus_l_handler_chain_copy(
365 &new_chain->response_destroy_handlers, src->response_destroy_handlers);
366 12045 if(result != GLOBUS_SUCCESS)
367 {
368 0 goto destroy_response_init_handlers;
369 }
370
371 12045 if(src->triggers)
372 {
373 12045 rc = globus_hashtable_copy(
374 &new_chain->triggers,
375 &src->triggers,
376 globus_l_handler_hash_entry_copy);
377
378 12045 if (rc != GLOBUS_SUCCESS)
379 {
380 0 result = GlobusSoapMessageErrorOutOfMemory;
381
382 0 goto destroy_response_destroy_handlers;
383 }
384 }
385
386 12045 new_chain->default_trigger = src->default_trigger;
387
388 12045 extensions = src->extensions;
389 48180 while(extensions)
390 {
391 24090 ext = globus_list_first(extensions);
392 24090 globus_extension_reference(ext);
393 24090 rc = globus_list_insert(&new_chain->extensions, (void *)ext);
394
395 24090 if (rc != GLOBUS_SUCCESS)
396 {
397 0 result = GlobusSoapMessageErrorOutOfMemory;
398
399 0 goto release_extension_exit;
400 }
401 24090 extensions = globus_list_rest(extensions);
402 }
403
404 12045 *dest = new_chain;
405
406 12045 if (result != GLOBUS_SUCCESS)
407 {
408 0 release_extension_exit:
409 0 extensions = new_chain->extensions;
410 0 while (extensions)
411 {
412 0 ext = globus_list_first(extensions);
413 0 globus_extension_release(ext);
414 0 extensions = globus_list_rest(extensions);
415 }
416 0 globus_list_free(new_chain->extensions);
417 0 destroy_response_destroy_handlers:
418 0 globus_list_destroy_all(
419 new_chain->response_destroy_handlers, globus_l_handler_destroy);
420 0 destroy_response_init_handlers:
421 0 globus_list_destroy_all(
422 new_chain->response_init_handlers, globus_l_handler_destroy);
423 0 destroy_request_destroy_handlers:
424 0 globus_list_destroy_all(
425 new_chain->request_destroy_handlers, globus_l_handler_destroy);
426 0 destroy_request_init_handlers:
427 0 globus_list_destroy_all(
428 new_chain->request_init_handlers, globus_l_handler_destroy);
429 0 destroy_response_handlers:
430 0 globus_list_destroy_all(
431 new_chain->response_handlers, globus_l_handler_destroy);
432 0 destroy_request_handlers:
433 0 globus_list_destroy_all(
434 new_chain->request_handlers, globus_l_handler_destroy);
435 0 error:
436 0 free(new_chain);
437 }
438
439 12045 exit:
440 12045 GlobusHandlerDebugExit();
441 12045 return result;
442 }
443 /* globus_handler_chain_copy() */
444
445 /**
446 * Add a new handler to a handler chain
447 * @ingroup globus_handler_chain
448 *
449 * Append the handler located in @a endpoint to handle the @a type sequence
450 * of the handling processing to the given handler chain @a chain.
451 *
452 * @param chain
453 * Handler chain to update.
454 * @param type
455 * Type of processing to be associated with this handler.
456 * @param endpoint
457 * Name of the shared library containing the handler.
458 *
459 * @retval GLOBUS_SUCCESS
460 * Handler successfully added to the handler chain.
461 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
462 * One of @a chain or @a endpoint was NULL.
463 * @retval GLOBUS_HANDLER_ERROR_TYPE_REGISTRY_LOOKUP_FAILED
464 * Unable to load the handler module.
465 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
466 * Insufficient memory to add the handler to the chain.
467 */
468 globus_result_t
469 globus_handler_chain_push(
470 globus_handler_chain_t chain,
471 globus_handler_type_t type,
472 const char * endpoint)
473 1580 {
474 globus_handler_descriptor_t * handler_desc;
475 1580 globus_result_t result = GLOBUS_SUCCESS;
476 globus_extension_handle_t extension_handle;
477 globus_l_handler_t * tmp_entry;
478 int rc;
479 GlobusFuncName(globus_handler_chain_push);
480 1580 GlobusHandlerDebugEnter();
481
482 1580 if (chain == NULL || endpoint == NULL)
483 {
484 0 result = GlobusSoapMessageErrorNullParam;
485
486 0 goto exit;
487 }
488 1580 handler_desc = globus_extension_lookup(
489 &extension_handle, GLOBUS_HANDLER_REGISTRY, (void *)endpoint);
490 1580 if(!handler_desc)
491 {
492 globus_result_t tmp_result;
493 char * tmp_endpoint;
494
495 0 tmp_endpoint = globus_libc_strdup(endpoint);
496 0 if (tmp_endpoint == NULL)
497 {
498 0 goto exit;
499 }
500 0 tmp_result = globus_extension_activate(endpoint);
501 0 if(tmp_result != GLOBUS_SUCCESS)
502 {
503 0 result = GlobusHandlerErrorRegistryLookupFailed(
504 tmp_result, endpoint);
505 0 free(tmp_endpoint);
506 0 goto exit;
507 }
508
509 0 globus_mutex_lock(&globus_l_handler_extensions_mutex);
510 0 rc = globus_list_insert(
511 &globus_l_handler_extensions, tmp_endpoint);
512 0 globus_mutex_unlock(&globus_l_handler_extensions_mutex);
513 0 if (rc != GLOBUS_SUCCESS)
514 {
515 0 result = GlobusSoapMessageErrorOutOfMemory;
516
517 0 free(tmp_endpoint);
518 0 goto exit;
519 }
520
521 0 handler_desc = globus_extension_lookup(
522 &extension_handle, GLOBUS_HANDLER_REGISTRY, (void *)endpoint);
523 0 if(!handler_desc)
524 {
525 0 result = GlobusHandlerErrorRegistryLookupFailed(
526 GLOBUS_FAILURE, endpoint);
527 0 goto exit;
528 }
529 }
530
531 1580 rc = globus_list_insert(&chain->extensions, (void *)extension_handle);
532 1580 if (rc != GLOBUS_SUCCESS)
533 {
534 0 result = GlobusSoapMessageErrorOutOfMemory;
535
536 0 goto exit;
537 }
538
539 1580 if((type & GLOBUS_HANDLER_TYPE_REQUEST) && handler_desc->request)
540 {
541 791 result = globus_l_handler_chain_push(&chain->request_handlers,
542 extension_handle, handler_desc->request, GLOBUS_FALSE);
543
544 791 if (result != GLOBUS_SUCCESS)
545 {
546 0 goto remove_extension_exit;
547 }
548
549 }
550
551 1580 if((type & GLOBUS_HANDLER_TYPE_RESPONSE) && handler_desc->response)
552 {
553 791 result = globus_l_handler_chain_push(&chain->response_handlers,
554 extension_handle, handler_desc->response, GLOBUS_TRUE);
555 791 if (result != GLOBUS_SUCCESS)
556 {
557 0 goto remove_request_handler_exit;
558 }
559 }
560
561 1580 if((type & GLOBUS_HANDLER_TYPE_REQUEST_INIT) && handler_desc->request_init)
562 {
563 0 result = globus_l_handler_chain_push(
564 &chain->request_init_handlers,
565 extension_handle, handler_desc->request_init, GLOBUS_FALSE);
566 0 if (result != GLOBUS_SUCCESS)
567 {
568 0 goto remove_response_handler_exit;
569 }
570 }
571
572 1580 if((type & GLOBUS_HANDLER_TYPE_RESPONSE_INIT) &&
573 handler_desc->response_init)
574 {
575 1 result = globus_l_handler_chain_push(
576 &chain->response_init_handlers,
577 extension_handle, handler_desc->response_init, GLOBUS_FALSE);
578 1 if (result != GLOBUS_SUCCESS)
579 {
580 0 goto remove_request_init_handler_exit;
581 }
582 }
583
584 1580 if((type & GLOBUS_HANDLER_TYPE_REQUEST_DESTROY) &&
585 handler_desc->request_destroy)
586 {
587 0 result = globus_l_handler_chain_push(
588 &chain->request_destroy_handlers,
589 extension_handle, handler_desc->request_destroy, GLOBUS_FALSE);
590 0 if (result != GLOBUS_SUCCESS)
591 {
592 0 goto remove_response_init_handler_exit;
593 }
594 }
595
596 1580 if((type & GLOBUS_HANDLER_TYPE_RESPONSE_DESTROY) &&
597 handler_desc->response_destroy)
598 {
599 1 result = globus_l_handler_chain_push(
600 &chain->response_destroy_handlers,
601 extension_handle, handler_desc->response_destroy, GLOBUS_FALSE);
602 1 if (result != GLOBUS_SUCCESS)
603 {
604 0 goto remove_request_destroy_handler_exit;
605 }
606 }
607
608 1580 if(handler_desc->default_trigger)
609 {
610 607 if(chain->default_trigger &&
611 (chain->default_trigger != handler_desc->default_trigger))
612 {
613 0 result = GlobusHandlerErrorDefaultTriggerAlreadyDefined();
614 0 goto remove_response_destroy_handler_exit;
615 }
616
617 607 chain->default_trigger = handler_desc->default_trigger;
618 }
619
620 1580 if(handler_desc->trigger_list)
621 {
622 1580 result = globus_l_handler_triggers_insert(
623 &chain->triggers, extension_handle,
624 handler_desc->trigger_list);
625 }
626 1580 if (result != GLOBUS_SUCCESS)
627 {
628 0 if (handler_desc->default_trigger &&
629 handler_desc->default_trigger != chain->default_trigger)
630 {
631 0 chain->default_trigger = NULL;
632 }
633 0 remove_response_destroy_handler_exit:
634 0 if((type & GLOBUS_HANDLER_TYPE_RESPONSE_DESTROY) &&
635 handler_desc->response_destroy)
636 {
637 0 tmp_entry = globus_list_remove(&chain->response_destroy_handlers,
638 chain->response_destroy_handlers);
639 0 globus_assert(tmp_entry);
640 0 free(tmp_entry);
641 }
642 0 remove_request_destroy_handler_exit:
643 0 if((type & GLOBUS_HANDLER_TYPE_REQUEST_DESTROY) &&
644 handler_desc->request_destroy)
645 {
646 0 tmp_entry = globus_list_remove(&chain->request_destroy_handlers,
647 chain->request_destroy_handlers);
648 0 globus_assert(tmp_entry);
649 0 free(tmp_entry);
650 }
651 0 remove_response_init_handler_exit:
652 0 if((type & GLOBUS_HANDLER_TYPE_RESPONSE_INIT) &&
653 handler_desc->response_init)
654 {
655 0 tmp_entry = globus_list_remove(&chain->response_init_handlers,
656 chain->response_init_handlers);
657 0 globus_assert(tmp_entry);
658 0 free(tmp_entry);
659 }
660 0 remove_request_init_handler_exit:
661 0 if((type & GLOBUS_HANDLER_TYPE_REQUEST_INIT) &&
662 handler_desc->request_init)
663 {
664 0 tmp_entry = globus_list_remove(&chain->request_init_handlers,
665 chain->request_init_handlers);
666 0 globus_assert(tmp_entry);
667 0 free(tmp_entry);
668 }
669 0 remove_response_handler_exit:
670 0 if((type & GLOBUS_HANDLER_TYPE_RESPONSE) && handler_desc->response)
671 {
672 0 globus_list_t * tmp = chain->response_handlers;
673 0 globus_list_t * prev = chain->response_handlers;
674 0 while(tmp->next)
675 {
676 0 prev = tmp;
677 0 tmp = globus_list_rest(tmp);
678 }
679 0 tmp_entry = globus_list_remove(&prev, tmp);
680 0 globus_assert(tmp_entry);
681 0 free(tmp_entry);
682 }
683 0 remove_request_handler_exit:
684 0 if((type & GLOBUS_HANDLER_TYPE_REQUEST) && handler_desc->request)
685 {
686 0 tmp_entry = globus_list_remove(&chain->request_init_handlers,
687 chain->request_init_handlers);
688 0 globus_assert(tmp_entry);
689 0 free(tmp_entry);
690 }
691 0 remove_extension_exit:
692 0 globus_list_remove(&chain->extensions,
693 globus_list_search(chain->extensions, extension_handle));
694 }
695 1580 exit:
696
697 1580 GlobusHandlerDebugExit();
698 1580 return result;
699 }
700 /* globus_handler_chain_push() */
701
702 /**
703 * Determine if a handler exists for a given element
704 * @ingroup globus_handler_chain
705 *
706 * @param chain
707 * Handler chain to check.
708 * @param element
709 * QName of the element to check for a handler for.
710 *
711 * @retval GLOBUS_TRUE
712 * The handler chain has a handler for @a element.
713 * @retval GLOBUS_FALSE
714 * The handler chain does not have a handler for @a element.
715 */
716 globus_bool_t
717 globus_handler_chain_has_trigger(
718 globus_handler_chain_t chain,
719 const xsd_QName * element)
720 17 {
721 17 if(chain->triggers && globus_hashtable_lookup(
722 &chain->triggers,
723 (void *)element))
724 {
725 15 return GLOBUS_TRUE;
726 }
727 2 return GLOBUS_FALSE;
728 }
729 /* globus_handler_chain_has_trigger() */
730
731 /**
732 * Invoke triggers for a SOAP header element
733 * @ingroup globus_soap_message
734 *
735 * Starts nonblocking processing of a header element, invoking all handlers
736 * in @a chain which have triggers associated with @a element. The @a callback
737 * function will be called after all triggers have been processed, or an error
738 * occurs in any trigger. Element triggers are typically called by the SOAP
739 * engine as elements in a SOAP header are parsed. If GLOBUS_SUCCESS is
740 * returned, then the @a callback function will be called to signal the caller
741 * that the trigger processing has finished; otherwise, @a callback will not
742 * be called.
743 *
744 * @param chain
745 * Handler chain to invoke triggers from.
746 * @param message
747 * SOAP message handle associated with the current SOAP message.
748 * @param element
749 * XML element QName which will be used to select triggers.
750 * @param callback
751 * Callback function to be invoked when all triggers have finished
752 * processing.
753 * @param user_args
754 * Argument to the @a callback function.
755 *
756 * @retval GLOBUS_SUCCESS
757 * Header element trigger processing begun.
758 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
759 * One of @a chain, @a message, or @a element is NULL.
760 */
761 globus_result_t
762 globus_handler_chain_trigger(
763 globus_handler_chain_t chain,
764 globus_soap_message_handle_t message,
765 const xsd_QName * element)
766 106713 {
767 globus_l_handler_t * handler;
768 106713 globus_result_t result = GLOBUS_SUCCESS;
769 globus_handler_invoke_func_t trigger;
770 GlobusFuncName(globus_handler_chain_trigger);
771 106713 GlobusHandlerDebugEnter();
772
773 106713 if (chain == NULL || message == NULL || element == NULL)
774 {
775 0 result = GlobusSoapMessageErrorNullParam;
776 0 goto exit;
777 }
778 106713 if(!chain->triggers)
779 {
780 0 goto exit;
781 }
782
783 106713 handler = globus_hashtable_lookup(
784 &chain->triggers,
785 (void *)element);
786 106713 if(handler)
787 {
788 97003 trigger = handler->trigger->invoke;
789 }
790 9710 else if(chain->default_trigger)
791 {
792 9710 trigger = chain->default_trigger;
793 }
794 else
795 {
796 0 goto exit;
797 }
798
799 106713 result = trigger(message, result);
800
801 106713 exit:
802 106713 GlobusHandlerDebugExit();
803 106713 return result;
804 }
805 /* globus_handler_chain_trigger() */
806
807 /**
808 * Invoke a handler for a particular message processing state
809 * @ingroup globus_soap_message_handler
810 *
811 * Handlers in a handler chain are invoked during various stages of the
812 * SOAP message processing done by the client and service SOAP handling
813 * engines. This function is called by the engines to process the
814 * handlers associated with the @a type stage of processing.
815 *
816 * @param chain
817 * Handler chain to invoke handlers from
818 * @param type
819 * Type of handlers to invoke from @a chain.
820 * @param message
821 * SOAP message being processed
822 */
823 globus_result_t
824 globus_handler_chain_invoke(
825 globus_handler_chain_t chain,
826 globus_handler_type_t type,
827 globus_soap_message_handle_t message)
828 105778 {
829 105778 globus_result_t result = GLOBUS_SUCCESS;
830 globus_list_t * handlers;
831 globus_l_handler_t * handler;
832 GlobusFuncName(globus_handler_chain_invoke);
833 105778 GlobusHandlerDebugEnter();
834
835 105778 if (chain == NULL)
836 {
837 0 result = GlobusSoapMessageErrorNullParam;
838
839 0 goto exit;
840 }
841
842 105778 switch(type)
843 {
844 case GLOBUS_HANDLER_TYPE_REQUEST_INIT:
845 21583 handlers = chain->request_init_handlers;
846 21583 break;
847 case GLOBUS_HANDLER_TYPE_REQUEST_DESTROY:
848 21553 handlers = chain->request_destroy_handlers;
849 21553 break;
850 case GLOBUS_HANDLER_TYPE_REQUEST:
851 21553 handlers = chain->request_handlers;
852 21553 break;
853 case GLOBUS_HANDLER_TYPE_RESPONSE_INIT:
854 10022 handlers = chain->response_init_handlers;
855 10022 break;
856 case GLOBUS_HANDLER_TYPE_RESPONSE_DESTROY:
857 9936 handlers = chain->response_destroy_handlers;
858 9936 break;
859 case GLOBUS_HANDLER_TYPE_RESPONSE:
860 21131 handlers = chain->response_handlers;
861 21131 break;
862 default:
863 0 handlers = NULL;
864 }
865
866 254252 while (!globus_list_empty(handlers))
867 {
868 42696 handler = globus_list_first(handlers);
869 42696 handlers = globus_list_rest(handlers);
870
871 42696 result = handler->invoke(message, result);
872 }
873
874 105778 exit:
875 105778 GlobusHandlerDebugExit();
876
877 105778 return result;
878 }
879 /* globus_handler_chain_invoke() */
880
881 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
882 static
883 int
884 globus_l_handler_activate(void)
885 0 {
886 int rc;
887
888 0 rc = globus_module_activate(GLOBUS_COMMON_MODULE);
889 0 if(rc != GLOBUS_SUCCESS)
890 {
891 0 return rc;
892 }
893
894 0 GlobusHandlerDebugEnter();
895
896 0 rc = globus_module_activate(GLOBUS_SOAP_MESSAGE_MODULE);
897 0 if(rc != GLOBUS_SUCCESS)
898 {
899 0 globus_module_deactivate(GLOBUS_COMMON_MODULE);
900 0 return rc;
901 }
902
903 0 globus_mutex_init(&globus_l_handler_extensions_mutex, NULL);
904
905 0 GlobusHandlerDebugExit();
906 0 return GLOBUS_SUCCESS;
907 }
908 /* globus_l_handler_activate() */
909
910 static
911 int
912 globus_l_handler_deactivate(void)
913 0 {
914 GlobusFuncName(globus_l_handler_deactivate);
915 0 GlobusHandlerDebugEnter();
916
917 0 globus_mutex_lock(&globus_l_handler_extensions_mutex);
918 0 if(globus_l_handler_extensions)
919 {
920 0 globus_list_destroy_all(globus_l_handler_extensions,
921 globus_l_handler_extension_destroy);
922 0 globus_l_handler_extensions = NULL;
923 }
924 0 globus_mutex_unlock(&globus_l_handler_extensions_mutex);
925 0 globus_mutex_destroy(&globus_l_handler_extensions_mutex);
926
927 0 globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
928
929 0 GlobusHandlerDebugExit();
930 0 GlobusDebugDestroy(GLOBUS_HANDLER);
931
932 0 globus_module_deactivate(GLOBUS_COMMON_MODULE);
933
934 0 return GLOBUS_SUCCESS;
935 }
936 /* globus_l_handler_deactivate() */
937
938 static
939 void
940 globus_l_handler_extension_destroy(
941 void * ep)
942 0 {
943 0 char * symbol = (char *) ep;
944
945 0 globus_extension_deactivate(symbol);
946 0 globus_free(symbol);
947 0 }
948 /* globus_l_handler_extension_destroy() */
949
950 static
951 void
952 globus_l_handler_destroy(
953 void * h)
954 146800 {
955 146800 globus_l_handler_t * entry = h;
956
957 146800 if(entry)
958 {
959 146800 free(entry);
960 }
961 146800 }
962 /* globus_l_handler_destroy() */
963
964 static
965 void
966 globus_l_handler_hash_entry_copy(
967 void ** dest_key,
968 void ** dest_datum,
969 void * src_key,
970 void * src_datum)
971 120450 {
972 globus_l_handler_t * dest_handler;
973 120450 globus_l_handler_t * src_handler = src_datum;
974
975 120450 dest_handler = calloc(1, sizeof(globus_l_handler_t));
976 120450 if(!dest_handler)
977 {
978 0 *dest_key = NULL;
979 0 *dest_datum = NULL;
980 }
981
982 120450 dest_handler->invoke = src_handler->invoke;
983 120450 dest_handler->trigger = src_handler->trigger;
984
985 120450 *dest_datum = (void *)dest_handler;
986 120450 *dest_key = (void *)dest_handler->trigger->element;
987 120450 }
988 /* globus_l_handler_hash_entry_copy() */
989
990 static
991 globus_result_t
992 globus_l_handler_chain_copy(
993 globus_list_t ** dest,
994 globus_list_t * src)
995 72270 {
996 72270 globus_result_t result = GLOBUS_SUCCESS;
997 globus_l_handler_t * src_handler;
998 globus_l_handler_t * new_handler;
999 GlobusFuncName(globus_l_handler_chain_copy);
1000 72270 GlobusHandlerDebugEnter();
1001
1002 96360 for(; !globus_list_empty(src); src = globus_list_rest(src))
1003 {
1004 24090 src_handler = globus_list_first(src);
1005
1006 24090 new_handler = calloc(1, sizeof(globus_l_handler_t));
1007 24090 if(!new_handler)
1008 {
1009 0 result = GlobusSoapMessageErrorOutOfMemory;
1010 0 GlobusHandlerDebugExit();
1011 0 return result;
1012 }
1013
1014 24090 new_handler->invoke = src_handler->invoke;
1015 24090 globus_list_insert(dest, new_handler);
1016 24090 dest = globus_list_rest_ref(*dest);
1017 }
1018
1019 72270 GlobusHandlerDebugExit();
1020 72270 return result;
1021 }
1022 /* globus_l_handler_chain_copy() */
1023
1024 static
1025 int
1026 globus_l_handler_chain_list_insert_last(
1027 globus_list_t * volatile * headp,
1028 void * datum)
1029 791 {
1030 791 globus_list_t * entry = NULL;
1031 globus_list_t * tmp_list;
1032 791 int rc = GLOBUS_SUCCESS;
1033
1034 791 if(!*headp)
1035 {
1036 790 rc = globus_list_insert(headp, datum);
1037 }
1038 else
1039 {
1040 1 tmp_list = *headp;
1041
1042 2 while(tmp_list->next)
1043 {
1044 0 tmp_list = globus_list_rest(tmp_list);
1045 }
1046 1 rc = globus_list_insert(&entry, datum);
1047 1 if (rc == GLOBUS_SUCCESS)
1048 {
1049 1 tmp_list->next = entry;
1050 }
1051 }
1052
1053 791 return rc;
1054 }
1055 /* globus_l_handler_chain_list_insert_last() */
1056
1057 static
1058 globus_result_t
1059 globus_l_handler_chain_push(
1060 globus_list_t ** chain,
1061 globus_extension_handle_t extension_handle,
1062 globus_handler_invoke_func_t invoke,
1063 globus_bool_t last)
1064 1584 {
1065 1584 globus_result_t result = GLOBUS_SUCCESS;
1066 globus_l_handler_t * handler;
1067 GlobusFuncName(globus_handler_chain_push);
1068 1584 GlobusHandlerDebugEnter();
1069
1070 1584 handler = calloc(1, sizeof(globus_l_handler_t));
1071 1584 if(!handler)
1072 {
1073 0 result = GlobusSoapMessageErrorOutOfMemory;
1074 0 goto exit;
1075 }
1076
1077 1584 handler->invoke = invoke;
1078
1079 1584 if(last)
1080 {
1081 791 globus_l_handler_chain_list_insert_last(chain, handler);
1082 }
1083 else
1084 {
1085 793 globus_list_insert(chain, handler);
1086 }
1087
1088 1584 exit:
1089 1584 GlobusHandlerDebugExit();
1090 1584 return result;
1091 }
1092 /* globus_l_handler_chain_push() */
1093
1094 static
1095 globus_result_t
1096 globus_l_handler_triggers_insert(
1097 globus_hashtable_t * triggers,
1098 globus_extension_handle_t ext,
1099 globus_list_t * trigger_list)
1100 1580 {
1101 1580 globus_result_t result = GLOBUS_SUCCESS;
1102 globus_list_t * trigger_iter;
1103 globus_handler_trigger_t * trigger;
1104 globus_l_handler_t * handler;
1105 GlobusFuncName(globus_l_handler_triggers_insert);
1106 1580 GlobusHandlerDebugEnter();
1107
1108 1580 if(!*triggers)
1109 {
1110 790 globus_hashtable_init(
1111 triggers, 19, xsd_QName_hash, xsd_QName_keyeq);
1112 }
1113
1114 1580 trigger_iter = trigger_list;
1115 17737 while(trigger_iter)
1116 {
1117 14577 trigger = globus_list_first(trigger_iter);
1118
1119 14577 handler = calloc(1, sizeof(globus_l_handler_t));
1120 14577 if(!handler)
1121 {
1122 0 result = GlobusSoapMessageErrorOutOfMemory;
1123 0 goto exit;
1124 }
1125
1126 14577 handler->trigger = trigger;
1127
1128 14577 globus_hashtable_insert(
1129 triggers,
1130 handler->trigger->element,
1131 handler);
1132 14577 trigger_iter = globus_list_rest(trigger_iter);
1133 }
1134
1135 1580 exit:
1136 1580 GlobusHandlerDebugExit();
1137 1580 return result;
1138 }
1139