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_i_soap_client.h"
19 #include "globus_service_engine.h"
20
21 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
22 static
23 void
24 globus_l_soap_client_response_callback(
25     void *                              args);
26 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
27
28 /**
29  * Nonblocking SOAP response handling.
30  * @ingroup globus_soap_client_response
31  *
32  * Processes the result of an operation previously invoked by calling
33  * globus_soap_client_register_request(). Once the reply has been completely
34  * processed, the @a callback function will be invoked. The application
35  * may then use the client handle to process a new operation, or destroy it.
36  *
37  * @param client_handle
38  *     The SOAP client handle to use for state while processing the
39  *     response.
40  * @param callback
41  *     Callback function to invoke once the operation response has been handled.
42  * @param user_args
43  *     Application-specific argument to the callback function.
44  *
45  * @retval GLOBUS_SUCCESS
46  *     Processing of this response has begun successfully.
47  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_INIT_FAILED
48  *     Processing the operation failed because the client could not initialize
49  *     some part of its data.
50  * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_CLIENT_REQUEST_FAILED
51  *     Processing the operation failed because the client could not initialize
52  *     some part of its data.
53  */
54
55 globus_result_t
56 globus_soap_client_register_response(
57     globus_soap_client_handle_t         client_handle,
58     globus_soap_client_response_callback_func_t
59                                         callback,
60     void *                              user_args)
61 3700 {
62 3700     globus_result_t                     result = GLOBUS_SUCCESS;
63     globus_i_soap_client_response_handle_t *
64 3700                                         response;
65 3700     globus_service_engine_t             engine;
66
67 3700     response = &client_handle->response;
68
69 3700     response->callback = callback;
70 3700     response->args = user_args;
71
72 3700     engine = globus_soap_message_attr_get(
73             client_handle->attrs,
74             GLOBUS_SOAP_CLIENT_LOCAL_INVOCATION_KEY);
75
76 3700     if (engine == NULL)
77     {
78 3247         response->output = NULL;
79 3247         response->state = GLOBUS_SOAP_CLIENT_RESPONSE_INIT;
80     }
81     else
82     {
83 453         response->state = GLOBUS_SOAP_CLIENT_RESPONSE_DONE;
84 453         response->done = GLOBUS_TRUE;
85     }
86
87 3700     if (client_handle->operation->response_action != NULL)
88     {
89 3700         result = globus_soap_message_handle_set_attr(
90             client_handle->message, 
91             WSADDR_ACTION_RESPONSE_KEY, 
92             NULL,
93             NULL,
94             (void *) client_handle->operation->response_action);
95
96 3700         if(result != GLOBUS_SUCCESS)
97         {
98 0             if(!GlobusSoapMessageStatusCheck(result))
99             {
100 0                 result = GlobusSoapMessageErrorClientRequestFailed(
101                     result, client_handle->operation->response_action);
102 0                 goto exit;
103             }
104         }
105     }
106
107 3700     result = globus_callback_register_oneshot(
108         &response->callback_handle,
109         NULL,
110         globus_l_soap_client_response_callback,
111         response);
112
113 3700     if(result != GLOBUS_SUCCESS)
114     {
115 0         result = GlobusSoapMessageErrorClientResponseFailed(
116             result, client_handle->operation->response_action);
117 0         goto exit;
118     }
119
120 3700     return result;
121     
122  exit:
123 0     return result;
124 }
125 /* globus_soap_client_register_response() */
126
127 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
128 static
129 void
130 globus_l_soap_client_response_done_callback(
131     globus_result_t                     result,
132     void *                              args)
133 23585 {
134 23585     globus_i_soap_client_response_handle_t * response;
135
136 23585     response = args;
137 23585     globus_assert_string(response, "response handle in callback is NULL");
138
139 23585     globus_mutex_lock(&response->client_handle->mutex);
140 23585     response->result = result;
141 23585     response->done = 1;
142 23585     globus_mutex_unlock(&response->client_handle->mutex);
143
144 23585     globus_l_soap_client_response_callback(response);
145 }
146 /* globus_l_soap_client_response_done_callback() */
147
148 extern
149 void
150 globus_i_soap_client_response_handle_destroy(
151     globus_i_soap_client_response_handle_t *
152                                         response)
153 3720 {
154 3720     globus_assert_string(response, "response handle in callback is NULL");
155
156 3720     if (response->output != NULL &&
157         response->client_handle->operation->output_type_info != NULL)
158     {
159 0         response->client_handle->operation->output_type_info->destroy(
160                 response->output);
161
162 0         response->output = NULL;
163     }
164
165 3720     if(response->fault)
166     {
167 0         xsd_any_destroy(response->fault);
168 0         response->fault_type = 0;
169 0         response->fault = NULL;
170     }
171 }
172 /* globus_i_soap_client_response_handle_destroy() */
173
174 static
175 void
176 globus_l_soap_client_response_callback(
177     void *                              args)
178 30611 {
179 30611     globus_soap_message_handle_t        message_handle = NULL;
180 30611     globus_soap_message_fault_t         soap_fault;
181 30611     globus_result_t                     result = GLOBUS_SUCCESS;
182 30611     globus_handler_chain_t              chain = NULL;
183 30611     xsd_QName *                         header_element = NULL;
184 30611     int                                 must;
185     globus_i_soap_client_response_handle_t *
186 30611                                         response;
187     const globus_soap_client_operation_t *
188 30611                                         operation;
189     globus_soap_client_response_callback_func_t
190 30611                                         callback;
191 30611     void *                              callback_arg;
192
193 30611     response = args;
194 30611     globus_assert_string(response, "response handle in callback is NULL");
195
196 30611     operation = response->client_handle->operation;
197     
198 new_state:
199 30612     switch(response->state)
200     {
201     case GLOBUS_SOAP_CLIENT_RESPONSE_INIT:
202
203 3247         globus_mutex_lock(&response->client_handle->mutex);
204 3247         response->done = 0;
205 3247         response->state = GLOBUS_SOAP_CLIENT_RESPONSE_READING;
206 3247         globus_mutex_unlock(&response->client_handle->mutex);
207
208 3247         result = globus_soap_message_register_read_response(
209             response->client_handle->message,
210             globus_l_soap_client_response_done_callback,
211             response);
212 3247         if(result != GLOBUS_SUCCESS)
213         {
214 0             goto error_exit;
215         }
216
217 3247         break;
218
219     case GLOBUS_SOAP_CLIENT_RESPONSE_READING:
220
221 3247         if(response->done)
222         {
223 3247             if(response->result != GLOBUS_SUCCESS)
224             {
225 0                 if(GlobusSoapMessageErrorCheckFailedResponse(response->result)
226                     || GlobusSoapMessageErrorCheckBadRequest(response->result))
227                 {
228 0                     response->result = GLOBUS_SUCCESS;
229                 }
230                 else
231                 {
232 0                     result = response->result;
233 0                     goto error_exit;
234                 }
235             }
236                 
237 3247             globus_mutex_lock(&response->client_handle->mutex);
238 3247             response->done = 0;
239 3247             response->state = GLOBUS_SOAP_CLIENT_RESPONSE_TRIGGER_HANDLERS;
240 3247             globus_mutex_unlock(&response->client_handle->mutex);
241
242 3247             result = globus_soap_message_deserialize_envelope(
243                 response->client_handle->message);
244 3247             if(result != GLOBUS_SUCCESS)
245             {
246 0                 goto error_exit;
247             }
248
249 3247             result = globus_soap_message_deserialize_element_begin_close(
250                 response->client_handle->message);
251 3247             if(result != GLOBUS_SUCCESS)
252             {
253 0                 goto error_exit;
254             }
255
256 3247             result = globus_soap_message_deserialize_header(
257                 response->client_handle->message);
258 3247             if(result != GLOBUS_SUCCESS)
259             {
260 1                 if(GlobusSoapMessageStatusElementNotFoundCheck(result))
261                 {
262 1                     globus_soap_message_deserialize_push_element(
263                         response->client_handle->message);
264 1                     result = GLOBUS_SUCCESS;
265 1                     globus_mutex_lock(&response->client_handle->mutex);
266 1                     response->state = 
267                         GLOBUS_SOAP_CLIENT_RESPONSE_HEADER_FAILED;
268 1                     response->done = 1;
269
270 1                     result = globus_soap_message_deserialize_body(
271                         response->client_handle->message);
272 1                     if(result != GLOBUS_SUCCESS)
273                     {
274 0                         if(response->result != GLOBUS_SUCCESS)
275                         {
276 0                             result = response->result;
277                         }
278 0                         goto error_exit;
279                     }
280 1                     globus_mutex_unlock(&response->client_handle->mutex);
281
282 1                     goto new_state;
283                 }
284                 
285 3246                 goto error_exit;
286             }
287
288 3246             globus_mutex_lock(&response->client_handle->mutex);
289 3246             response->done = 1;
290 3246             globus_mutex_unlock(&response->client_handle->mutex);
291         }
292
293     case GLOBUS_SOAP_CLIENT_RESPONSE_TRIGGER_HANDLERS:
294
295 17170         if(response->done)
296         {
297 17170             if(response->result != GLOBUS_SUCCESS)
298             {
299 0                 if(GlobusSoapMessageErrorCheckFailedResponse(
300                        response->result) ||
301                    GlobusSoapMessageErrorCheckBadRequest(response->result))
302                 {
303 0                     response->result = GLOBUS_SUCCESS;
304                 }
305                 else
306                 {
307 0                     result = response->result;
308 0                     goto error_exit;
309                 }
310             }
311                 
312 17170             globus_mutex_lock(&response->client_handle->mutex);
313 17170             response->done = 0;
314 17170             response->state = GLOBUS_SOAP_CLIENT_RESPONSE_TRIGGER_HANDLERS;
315 17170             globus_mutex_unlock(&response->client_handle->mutex);
316
317 17170             xsd_QName_init(&header_element);
318                 
319 17170             result = globus_soap_message_deserialize_element_unknown(
320                 response->client_handle->message,
321                 header_element);
322 17170             if(result != GLOBUS_SUCCESS)
323             {
324 3246                 if(!GlobusSoapMessageStatusFailedElementCheck(result))
325                 {
326 0                     xsd_QName_destroy(header_element);
327 0                     goto error_exit;
328                 }
329                 else
330                 {
331 3246                     globus_mutex_lock(&response->client_handle->mutex);
332 3246                     response->done = 1;
333 3246                     response->state = 
334                     GLOBUS_SOAP_CLIENT_RESPONSE_HANDLER_DESERIALIZE;
335 3246                     globus_mutex_unlock(&response->client_handle->mutex);
336
337 3246                     globus_callback_register_oneshot(
338                         NULL,
339                         &globus_i_reltime_zero,
340                         globus_l_soap_client_response_callback,
341                         (void *)response);
342 3246                     xsd_QName_destroy(header_element);
343 3246                     break;
344                 }
345             }
346
347 13924             result = globus_soap_message_deserialize_int_attribute(
348                 response->client_handle->message,
349                 &soap_mustUnderstand_qname,
350                 &must);
351 13924             if(result == GLOBUS_SUCCESS && (must == 1))
352             {
353 0                 globus_soap_message_add_required_header_element(
354                     response->client_handle->message,
355                     header_element);
356             }
357 13924             else if(result != GLOBUS_SUCCESS &&
358                     !GlobusSoapMessageStatusAttributeNotFoundCheck(result))
359             {
360 0                 xsd_QName_destroy(header_element);
361 0                 goto error_exit;
362             }
363
364 13924             globus_soap_message_deserialize_push_element(
365                 response->client_handle->message);
366
367 13924             result = globus_soap_message_get_handler_chain(
368                 response->client_handle->message, &chain);
369 13924             if(result != GLOBUS_SUCCESS)
370             {
371 0                 goto error_exit;
372             }
373
374 13924             if(chain)
375             {
376 13924                 result = globus_handler_chain_register_trigger(
377                     chain,
378                     response->client_handle->message,
379                     header_element,
380                     globus_l_soap_client_response_done_callback,
381                     response);
382 13924                 if(result == GLOBUS_SUCCESS)
383                 {
384 13924                     xsd_QName_destroy(header_element);
385 13924                     break;
386                 }
387 0                 else if(!GlobusHandlerStatusNotTriggeredCheck(result))
388                 {
389 0                     xsd_QName_destroy(header_element);
390 0                     goto error_exit;
391                 }
392             }
393
394 0             xsd_QName_destroy(header_element);
395 0             result = globus_soap_message_deserialize_skip(
396                 response->client_handle->message);
397 0             if(result != GLOBUS_SUCCESS)
398             {
399 0                 goto error_exit;
400             }
401             
402 0             globus_mutex_lock(&response->client_handle->mutex);
403 0             response->done = 1;
404 0             globus_mutex_unlock(&response->client_handle->mutex);
405 0             globus_callback_register_oneshot(
406                 NULL,
407                 &globus_i_reltime_zero,
408                 globus_l_soap_client_response_callback,
409                 (void *)response);
410         }
411
412 0         break;
413
414     case GLOBUS_SOAP_CLIENT_RESPONSE_HANDLER_DESERIALIZE:
415
416 3246         if(response->done)
417         {
418 3246             if(response->result != GLOBUS_SUCCESS)
419             {
420 0                 result = response->result;
421 0                 goto error_exit;
422             }
423
424 3246             globus_mutex_lock(&response->client_handle->mutex);
425 3246             response->state = GLOBUS_SOAP_CLIENT_RESPONSE_INVOKING_HANDLERS;
426 3246             globus_mutex_unlock(&response->client_handle->mutex);
427
428 3246             result = globus_soap_message_deserialize_header_end(
429                 response->client_handle->message);
430 3246             if(result != GLOBUS_SUCCESS)
431             {
432 0                 goto error_exit;
433             }
434
435 3246             result = globus_soap_message_deserialize_body(
436                 response->client_handle->message);
437 3246             if(result != GLOBUS_SUCCESS)
438             {
439 0                 goto error_exit;
440             }
441         }
442
443         /* FALLSTHROUGH */
444         
445     case GLOBUS_SOAP_CLIENT_RESPONSE_HEADER_FAILED:
446
447 3247         if(response->done)
448         {
449 3247             if(response->result != GLOBUS_SUCCESS)
450             {
451 0                 result = response->result;
452 0                 goto error_exit;
453             }
454
455 3247             globus_mutex_lock(&response->client_handle->mutex);
456 3247             response->state = GLOBUS_SOAP_CLIENT_RESPONSE_INVOKING_HANDLERS;
457 3247             globus_mutex_unlock(&response->client_handle->mutex);
458             
459 3247             response->fault_type = 0;
460 3247             response->fault_result = GLOBUS_SUCCESS;
461
462 3247             result = globus_soap_message_deserialize_fault(
463                 response->client_handle->message,
464                 &soap_fault,
465                 operation->fault_callback,
466                 &response->fault,
467                 &response->fault_type);
468 3247             if(result != GLOBUS_SUCCESS)
469             {
470 0                 if(response->result != GLOBUS_SUCCESS)
471                 {
472 0                     result = response->result;
473                 }
474 0                 goto error_exit;
475             }
476
477 3247             if(!soap_fault && response->fault_type == 0)
478             {
479 3167                 result = operation->output_type_info->deserialize(
480                     &operation->output_element,
481                     &response->output,
482                     response->client_handle->message,
483                     0);
484 3167                 if(result != GLOBUS_SUCCESS)
485                 {
486 0                     goto error_exit;
487                 }
488             }
489             else
490             {
491 80                 if(soap_fault)
492                 {
493 80                     response->fault_result = GlobusSoapMessageErrorFault(
494                         soap_fault);
495                 }                
496
497 80                 result = globus_soap_message_deserialize_fault_end(
498                     response->client_handle->message,
499                     response->fault
500                         ? response->fault->element
501                         : &soap_fault_qname);
502 80                 if(result != GLOBUS_SUCCESS)
503                 {
504 0                     goto error_exit;
505                 }
506             }
507
508 3247             result = globus_soap_message_deserialize_body_end(
509                 response->client_handle->message);
510 3247             if(result != GLOBUS_SUCCESS)
511             {
512 0                 goto error_exit;
513             }
514
515 3247             result = globus_soap_message_deserialize_envelope_end(
516                 response->client_handle->message);
517 3247             if(result != GLOBUS_SUCCESS)
518             {
519 0                 goto error_exit;
520             }
521
522
523 3247             if(!soap_fault && response->fault_type == 0)
524             {
525 3167                 result = globus_soap_message_get_handler_chain(
526                     response->client_handle->message, &chain);
527 3167                 if(result != GLOBUS_SUCCESS)
528                 {
529 0                     goto error_exit;
530                 }
531                 
532 3167                 if(chain)
533                 {
534 3167                     globus_handler_chain_register_invoke(
535                         chain,
536                         GLOBUS_HANDLER_TYPE_RESPONSE,
537                         response->client_handle->message,
538                         globus_l_soap_client_response_done_callback,
539                         response);
540                 }
541             }
542             else
543             {
544 80                 globus_mutex_lock(&response->client_handle->mutex);
545 80                 response->done = 1;
546 80                 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_CLOSE;
547 80                 globus_mutex_unlock(&response->client_handle->mutex);
548 80                 globus_callback_register_oneshot(
549                     NULL,
550                     &globus_i_reltime_zero,
551                     globus_l_soap_client_response_callback,
552                     (void *)response);
553             }
554         }
555         
556 80         break;
557
558     case GLOBUS_SOAP_CLIENT_RESPONSE_INVOKING_HANDLERS:
559
560 3167         if(response->done)
561         {
562 3167             if(response->result != GLOBUS_SUCCESS)
563             {
564 0                 result = response->result;
565 0                 goto error_exit;
566             }
567             
568 3167             result = globus_soap_message_check_required_headers(
569                 response->client_handle->message);
570 3167             if(result != GLOBUS_SUCCESS)
571             {
572                 /* continue on in case fault was returned and
573                  * no header elements exist
574                  */
575 0                 response->result = result;
576             }
577         }
578
579     case GLOBUS_SOAP_CLIENT_RESPONSE_CLOSE:
580
581 3247         if(response->done)
582         {
583 3247             if(response->result != GLOBUS_SUCCESS)
584             {
585 0                 result = response->result;
586 0                 goto error_exit;
587             }
588
589 3247             globus_mutex_lock(&response->client_handle->mutex);
590 3247             response->done = 0;
591 3247             response->state = GLOBUS_SOAP_CLIENT_RESPONSE_DONE;
592 3247             globus_mutex_unlock(&response->client_handle->mutex);
593             
594 3247             result = globus_soap_message_register_close(
595                 response->client_handle->message,
596                 globus_l_soap_client_response_done_callback,
597                 response);
598 3247             if(result != GLOBUS_SUCCESS)
599             {
600 0                 goto error_exit;
601             }
602         }
603
604 3700         break;
605
606     case GLOBUS_SOAP_CLIENT_RESPONSE_DONE:
607
608
609 3700         if(response->done)
610         {
611 3700             if(response->result != GLOBUS_SUCCESS)
612             {
613 0                 result = response->result;
614 0                 goto error_exit;
615             }
616
617 3700             globus_mutex_lock(&response->client_handle->mutex);
618 3700             response->done = 0;
619 3700             message_handle = response->client_handle->message;
620 3700             response->client_handle->message = NULL;
621 3700             callback = response->callback;
622 3700             callback_arg = response->args;
623 3700             response->callback = NULL;
624 3700             response->args = NULL;
625 3700             globus_mutex_unlock(&response->client_handle->mutex);
626
627 3700             callback(
628                 response->client_handle, 
629                 callback_arg,
630                 response->fault_result,
631                 response->output,
632                 response->fault_type,
633                 response->fault);
634
635 3700             globus_soap_message_handle_destroy(message_handle);
636         }
637
638 3700         break;
639
640     default:
641
642 0         globus_assert_string(NULL, "Unknown response state");
643     }
644
645 0     return;
646
647  error_exit:
648
649 0     if(!GlobusSoapMessageStatusCheck(result))
650     {
651 0         result = GlobusSoapMessageErrorClientResponseFailed(
652             result, operation->response_action);
653     }
654
655 0     globus_mutex_lock(&response->client_handle->mutex);
656 0     callback = response->callback;
657 0     callback_arg = response->args;
658 0     response->callback = NULL;
659 0     response->args = NULL;
660 0     message_handle = response->client_handle->message;
661 0     response->client_handle->message = NULL;
662 0     globus_mutex_unlock(&response->client_handle->mutex);
663     
664 0     callback(
665         response->client_handle,
666         callback_arg,
667         result,
668         response->output,
669         response->fault_type,
670         response->fault);
671
672 0     globus_soap_message_handle_destroy(message_handle);
673 }
674 /* globus_l_soap_client_response_callback() */
675