1 #define _XOPEN_SOURCE 500 /* For strdup(3) */
2 #include "../test-tools.h"
6 #include <libxml/parser.h>
7 #include <libxml/xpath.h>
8 #include <libxml/xpathInternals.h>
9 #include <libxml/xmlsave.h>
11 static const char *soap_mime_type
= "text/xml"; /* SOAP/1.1 requires text/xml */
13 /* Used to choose proper name space for message elements.
14 * See _isds_register_namespaces(). */
18 MESSAGE_NS_SIGNED_INCOMING
,
19 MESSAGE_NS_SIGNED_OUTGOING
,
20 MESSAGE_NS_SIGNED_DELIVERY
,
24 #define SOAP_NS "http://schemas.xmlsoap.org/soap/envelope/"
25 #define SOAP2_NS "http://www.w3.org/2003/05/soap-envelope"
26 #define ISDS1_NS "http://isds.czechpoint.cz"
27 #define ISDS_NS "http://isds.czechpoint.cz/v20"
28 #define OISDS_NS "http://isds.czechpoint.cz/v20/asws"
29 #define SISDS_INCOMING_NS "http://isds.czechpoint.cz/v20/message"
30 #define SISDS_OUTGOING_NS "http://isds.czechpoint.cz/v20/SentMessage"
31 #define SISDS_DELIVERY_NS "http://isds.czechpoint.cz/v20/delivery"
32 #define SCHEMA_NS "http://www.w3.org/2001/XMLSchema"
33 #define DEPOSIT_NS "urn:uschovnaWSDL"
38 const char *end_point
;
39 const xmlChar
*name_space
;
41 http_error (*function
) (const struct http_connection
*, xmlDocPtr
,
42 xmlXPathContextPtr
, xmlNodePtr
, xmlDocPtr
, xmlNodePtr
,
43 const void *arguments
);
46 /* Following EXTRACT_* macros expect @xpath_ctx, @message, and leave label */
47 #define EXTRACT_STRING(element, string) { \
48 xmlXPathObjectPtr result = NULL; \
49 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
50 if (NULL == result) { \
51 error = HTTP_ERROR_SERVER; \
54 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
55 if (result->nodesetval->nodeNr > 1) { \
56 xmlXPathFreeObject(result); \
57 test_asprintf(&message, "Multiple %s element", element); \
58 error = HTTP_ERROR_CLIENT; \
62 xmlXPathCastNodeSetToString(result->nodesetval); \
64 xmlXPathFreeObject(result); \
65 error = HTTP_ERROR_SERVER; \
69 xmlXPathFreeObject(result); \
72 #define EXTRACT_BOOLEAN(element, booleanPtr) { \
73 char *string = NULL; \
74 EXTRACT_STRING(element, string); \
76 if (NULL != string) { \
77 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
78 if (NULL == (booleanPtr)) { \
80 error = HTTP_ERROR_SERVER; \
84 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
85 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
87 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
88 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
91 test_asprintf(&message, \
92 "%s value is not valid boolean: %s", \
95 error = HTTP_ERROR_CLIENT; \
104 /* Following INSERT_* macros expect @error and leave label */
105 #define INSERT_STRING_WITH_NS(parent, ns, element, string) \
107 xmlNodePtr node = xmlNewTextChild(parent, ns, BAD_CAST (element), \
108 (xmlChar *) (string)); \
109 if (NULL == node) { \
110 error = HTTP_ERROR_SERVER; \
115 #define INSERT_STRING(parent, element, string) \
116 { INSERT_STRING_WITH_NS(parent, NULL, element, string) }
118 #define INSERT_ELEMENT(child, parent, element) \
120 (child) = xmlNewChild((parent), NULL, BAD_CAST (element), NULL); \
121 if (NULL == (child)) { \
122 error = HTTP_ERROR_SERVER; \
127 /* Insert dmStatus or similar subtree
128 * @parent is element to insert to
129 * @dm is true for dmStatus, otherwise dbStatus
130 * @code is stautus code as string
131 * @message is UTF-8 encoded message
132 * @db_ref_number is optinal reference number propagated if not @dm
133 * @return 0 on success, otherwise non-0. */
134 static http_error
insert_isds_status(xmlNodePtr parent
, _Bool dm
,
135 const xmlChar
*code
, const xmlChar
*message
,
136 const xmlChar
*db_ref_number
) {
137 http_error error
= HTTP_ERROR_SUCCESS
;
140 if (NULL
== code
|| NULL
== message
) {
141 error
= HTTP_ERROR_SERVER
;
145 INSERT_ELEMENT(status
, parent
, (dm
) ? "dmStatus" : "dbStatus");
146 INSERT_STRING(status
, (dm
) ? "dmStatusCode" : "dbStatusCode", code
);
147 INSERT_STRING(status
, (dm
) ? "dmStatusMessage" : "dbStatusMessage", message
);
148 if (!dm
&& NULL
!= db_ref_number
) {
149 INSERT_STRING(status
, "dbStatusRefNumber", db_ref_number
);
157 /* Implement DummyOperation */
158 static http_error
service_DummyOperation(
159 const struct http_connection
*connection
, const xmlDocPtr soap_request
,
160 xmlXPathContextPtr xpath_ctx
, xmlNodePtr isds_request
,
161 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
162 const void *arguments
) {
163 return insert_isds_status(isds_response
, 1, BAD_CAST
"0000",
164 BAD_CAST
"Success", NULL
);
168 /* Implement EraseMessage.
169 * @arguments is pointer to struct arguments_DS_DsManage_ChangeISDSPassword */
170 static http_error
service_EraseMessage(const struct http_connection
*connection
,
171 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
172 const xmlNodePtr isds_request
,
173 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
174 const void *arguments
) {
175 http_error error
= HTTP_ERROR_SUCCESS
;
176 char *code
= "9999", *message
= NULL
;
177 const struct arguments_DS_Dx_EraseMessage
*configuration
=
178 (const struct arguments_DS_Dx_EraseMessage
*)arguments
;
179 char *message_id
= NULL
;
180 _Bool
*incoming
= NULL
;
182 if (NULL
== configuration
|| NULL
== configuration
->message_id
) {
183 error
= HTTP_ERROR_SERVER
;
187 EXTRACT_STRING("isds:dmID", message_id
);
188 if (NULL
== message_id
) {
189 message
= strdup("Missing isds:dmID");
190 error
= HTTP_ERROR_CLIENT
;
193 EXTRACT_BOOLEAN("isds:dmIncoming", incoming
);
194 if (NULL
== incoming
) {
195 message
= strdup("Missing isds:dmIncoming");
196 error
= HTTP_ERROR_CLIENT
;
200 if (xmlStrcmp((const xmlChar
*) configuration
->message_id
,
201 (const xmlChar
*) message_id
)) {
203 message
= strdup("Message is not in the long term storage");
204 error
= HTTP_ERROR_CLIENT
;
207 if (configuration
->incoming
!= *incoming
) {
209 message
= strdup("Message direction mismatches");
210 error
= HTTP_ERROR_CLIENT
;
215 message
= strdup("Success");
217 if (HTTP_ERROR_SERVER
!= error
) {
218 http_error next_error
= insert_isds_status(isds_response
, 1,
219 BAD_CAST code
, BAD_CAST message
, NULL
);
220 if (HTTP_ERROR_SUCCESS
!= next_error
) error
= next_error
;
229 /* Common part for ChangeISDSPassword and ChangePasswordOTP.
230 * @code is output pointer to static string
231 * @pass_message is output pointer to auto-allocated string
232 * @arguments is pointer to struct arguments_DS_DsManage_ChangeISDSPassword */
233 static http_error
check_passwd(
234 const char *username
, const char *current_password
,
235 xmlXPathContextPtr xpath_ctx
,
236 char **code
, char **pass_message
) {
237 http_error error
= HTTP_ERROR_SUCCESS
;
238 char *message
= NULL
;
239 char *old_password
= NULL
, *new_password
= NULL
;
242 if (NULL
== username
|| NULL
== current_password
||
243 NULL
== code
|| NULL
== pass_message
) {
244 error
= HTTP_ERROR_SERVER
;
252 EXTRACT_STRING("isds:dbOldPassword", old_password
);
253 if (NULL
== old_password
) {
254 message
= strdup("Empty isds:dbOldPassword");
255 error
= HTTP_ERROR_CLIENT
;
258 EXTRACT_STRING("isds:dbNewPassword", new_password
);
259 if (NULL
== new_password
) {
260 message
= strdup("Empty isds:dbOldPassword");
261 error
= HTTP_ERROR_CLIENT
;
265 /* Check defined cases */
266 if (strcmp(current_password
, old_password
)) {
268 message
= strdup("Bad current password");
269 error
= HTTP_ERROR_CLIENT
;
273 length
= strlen(new_password
);
275 if (length
< 8 || length
> 32) {
277 message
= strdup("Too short or too long");
278 error
= HTTP_ERROR_CLIENT
;
283 const char lower
[] = "abcdefghijklmnopqrstuvwxyz";
284 const char upper
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
285 const char digit
[] = "0123456789";
286 const char special
[] = "!#$%&()*+,-.:=?@[]_{}|~";
287 _Bool has_lower
= 0, has_upper
= 0, has_digit
=0;
289 for (int i
= 0; i
< length
; i
++) {
290 if (NULL
!= strchr(lower
, new_password
[i
]))
292 else if (NULL
!= strchr(upper
, new_password
[i
]))
294 else if (NULL
!= strchr(digit
, new_password
[i
]))
296 else if (NULL
== strchr(special
, new_password
[i
])) {
298 message
= strdup("Password contains forbidden character");
299 error
= HTTP_ERROR_CLIENT
;
304 if (!has_lower
|| !has_upper
|| !has_digit
) {
306 message
= strdup("Password does not contain lower cased letter, "
307 "upper cased letter and a digit");
308 error
= HTTP_ERROR_CLIENT
;
313 if (!strcmp(old_password
, new_password
)) {
315 message
= strdup("New password same as current one");
316 error
= HTTP_ERROR_CLIENT
;
320 if (NULL
!= strstr(new_password
, username
)) {
322 message
= strdup("New password contains user ID");
323 error
= HTTP_ERROR_CLIENT
;
327 for (int i
= 0; i
< length
- 2; i
++) {
328 if (new_password
[i
] == new_password
[i
+1] &&
329 new_password
[i
] == new_password
[i
+2]) {
331 message
= strdup("Password contains sequence "
332 "of three identical characters");
333 error
= HTTP_ERROR_CLIENT
;
339 const char *forbidden_prefix
[] = { "qwert", "asdgf", "12345" };
340 for (int i
= 0; i
< sizeof(forbidden_prefix
)/sizeof(*forbidden_prefix
);
342 if (!strncmp(new_password
, forbidden_prefix
[i
],
343 strlen(forbidden_prefix
[i
]))) {
345 message
= strdup("Password has forbidden prefix");
346 error
= HTTP_ERROR_CLIENT
;
353 message
= strdup("Success");
357 *pass_message
= message
;
362 /* Implement ChangeISDSPassword.
363 * @arguments is pointer to struct arguments_DS_DsManage_ChangeISDSPassword */
364 static http_error
service_ChangeISDSPassword(
365 const struct http_connection
*connection
,
366 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
367 const xmlNodePtr isds_request
,
368 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
369 const void *arguments
) {
370 http_error error
= HTTP_ERROR_SUCCESS
;
371 char *code
= "9999", *message
= NULL
;
372 const struct arguments_DS_DsManage_ChangeISDSPassword
*configuration
=
373 (const struct arguments_DS_DsManage_ChangeISDSPassword
*)arguments
;
375 if (NULL
== configuration
|| NULL
== configuration
->username
||
376 NULL
== configuration
->current_password
) {
377 error
= HTTP_ERROR_SERVER
;
381 /* Check for common password rules */
382 error
= check_passwd(
383 configuration
->username
, configuration
->current_password
,
384 xpath_ctx
, &code
, &message
);
387 if (HTTP_ERROR_SERVER
!= error
) {
388 http_error next_error
= insert_isds_status(isds_response
, 0,
389 BAD_CAST code
, BAD_CAST message
, NULL
);
390 if (HTTP_ERROR_SUCCESS
!= next_error
) error
= next_error
;
397 /* Implement ChangePasswordOTP.
398 * @arguments is pointer to struct
399 * arguments_asws_changePassword_ChangePasswordOTP */
400 static http_error
service_ChangePasswordOTP(
401 const struct http_connection
*connection
,
402 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
403 const xmlNodePtr isds_request
,
404 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
405 const void *arguments
) {
406 http_error error
= HTTP_ERROR_SUCCESS
;
407 char *code
= "9999", *message
= NULL
;
408 const struct arguments_asws_changePassword_ChangePasswordOTP
*configuration
409 = (const struct arguments_asws_changePassword_ChangePasswordOTP
*)
413 if (NULL
== configuration
|| NULL
== configuration
->username
||
414 NULL
== configuration
->current_password
) {
415 error
= HTTP_ERROR_SERVER
;
419 /* Chek for OTP method */
420 EXTRACT_STRING("isds:dbOTPType", method
);
421 if (NULL
== method
) {
422 message
= strdup("Empty isds:dbOTPType");
423 error
= HTTP_ERROR_CLIENT
;
426 if ((configuration
->method
== AUTH_OTP_HMAC
&& strcmp(method
, "HOTP")) ||
427 (configuration
->method
== AUTH_OTP_TIME
&& strcmp(method
, "TOTP"))) {
428 message
= strdup("isds:dbOTPType does not match OTP method");
429 error
= HTTP_ERROR_CLIENT
;
433 /* Check for common password rules */
434 error
= check_passwd(
435 configuration
->username
, configuration
->current_password
,
436 xpath_ctx
, &code
, &message
);
439 if (HTTP_ERROR_SERVER
!= error
) {
440 http_error next_error
= insert_isds_status(isds_response
, 0,
441 BAD_CAST code
, BAD_CAST message
,
442 BAD_CAST configuration
->reference_number
);
443 if (HTTP_ERROR_SUCCESS
!= next_error
) error
= next_error
;
451 /* Implement SendSMSCode.
452 * @arguments is pointer to struct arguments_asws_changePassword_SendSMSCode */
453 static http_error
service_SendSMSCode(
454 const struct http_connection
*connection
,
455 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
456 const xmlNodePtr isds_request
,
457 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
458 const void *arguments
) {
459 const struct arguments_asws_changePassword_SendSMSCode
*configuration
460 = (const struct arguments_asws_changePassword_SendSMSCode
*)
463 if (NULL
== configuration
|| NULL
== configuration
->status_code
||
464 NULL
== configuration
->status_message
) {
465 return HTTP_ERROR_SERVER
;
468 return insert_isds_status(isds_response
, 0,
469 BAD_CAST configuration
->status_code
,
470 BAD_CAST configuration
->status_message
,
471 BAD_CAST configuration
->reference_number
);
475 /* List of implemented services */
476 static struct service services
[] = {
477 { SERVICE_DS_Dz_DummyOperation
,
478 "DS/dz", BAD_CAST ISDS_NS
, BAD_CAST
"DummyOperation",
479 service_DummyOperation
},
480 { SERVICE_DS_DsManage_ChangeISDSPassword
,
481 "DS/DsManage", BAD_CAST ISDS_NS
, BAD_CAST
"ChangeISDSPassword",
482 service_ChangeISDSPassword
},
483 { SERVICE_DS_Dx_EraseMessage
,
484 "DS/dx", BAD_CAST ISDS_NS
, BAD_CAST
"EraseMessage",
485 service_EraseMessage
},
486 { SERVICE_asws_changePassword_ChangePasswordOTP
,
487 "/asws/changePassword", BAD_CAST OISDS_NS
, BAD_CAST
"ChangePasswordOTP",
488 service_ChangePasswordOTP
},
489 { SERVICE_asws_changePassword_SendSMSCode
,
490 "/asws/changePassword", BAD_CAST OISDS_NS
, BAD_CAST
"SendSMSCode",
491 service_SendSMSCode
},
495 /* Makes known all relevant namespaces to given XPath context
496 * @xpath_ctx is XPath context
497 * @otp_ns selects name space for the request and response know as "isds".
498 * Use true for OTP-authenticated password change services, otherwise false.
499 * @message_ns selects proper message name space. Unsigned and signed
500 * messages and delivery info's differ in prefix and URI.
501 * @return 0 in success, otherwise not 0. */
502 static int register_namespaces(xmlXPathContextPtr xpath_ctx
,
503 const _Bool otp_ns
, const message_ns_type message_ns
) {
504 const xmlChar
*service_namespace
= NULL
;
505 const xmlChar
*message_namespace
= NULL
;
507 if (!xpath_ctx
) return -1;
510 service_namespace
= BAD_CAST OISDS_NS
;
512 service_namespace
= BAD_CAST ISDS_NS
;
517 message_namespace
= BAD_CAST ISDS1_NS
; break;
518 case MESSAGE_NS_UNSIGNED
:
519 message_namespace
= BAD_CAST ISDS_NS
; break;
520 case MESSAGE_NS_SIGNED_INCOMING
:
521 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
522 case MESSAGE_NS_SIGNED_OUTGOING
:
523 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
524 case MESSAGE_NS_SIGNED_DELIVERY
:
525 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
530 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
532 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", service_namespace
))
534 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
536 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))
538 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"deposit", BAD_CAST DEPOSIT_NS
))
544 /* Parse soap request, pass it to service endpoint and respond to it.
545 * It sends final HTTP response. */
546 void soap(const struct http_connection
*connection
,
547 const struct service_configuration
*configuration
,
548 const void *request
, size_t request_length
, const char *end_point
) {
549 xmlDocPtr request_doc
= NULL
;
550 xmlXPathContextPtr xpath_ctx
= NULL
;
551 xmlXPathObjectPtr request_soap_body
= NULL
;
552 xmlNodePtr isds_request
= NULL
; /* pointer only */
553 _Bool service_handled
= 0, service_passed
= 0;
554 xmlDocPtr response_doc
= NULL
;
555 xmlNodePtr response_soap_envelope
= NULL
, response_soap_body
= NULL
,
556 isds_response
= NULL
;
557 xmlNsPtr soap_ns
= NULL
, isds_ns
= NULL
;
558 char *response_name
= NULL
;
559 xmlBufferPtr http_response_body
= NULL
;
560 xmlSaveCtxtPtr save_ctx
= NULL
;
563 if (NULL
== configuration
) {
564 http_send_response_500(connection
,
565 "Second argument of soap() is NULL");
569 if (NULL
== request
|| request_length
== 0) {
570 http_send_response_400(connection
, "Client sent empty body");
574 request_doc
= xmlParseMemory(request
, request_length
);
575 if (NULL
== request_doc
) {
576 http_send_response_400(connection
, "Client sent invalid XML document");
580 xpath_ctx
= xmlXPathNewContext(request_doc
);
581 if (NULL
== xpath_ctx
) {
582 xmlFreeDoc(request_doc
);
583 http_send_response_500(connection
, "Could not create XPath context");
587 if (register_namespaces(xpath_ctx
, 0, MESSAGE_NS_UNSIGNED
)) {
588 xmlXPathFreeContext(xpath_ctx
);
589 xmlFreeDoc(request_doc
);
590 http_send_response_500(connection
,
591 "Could not register name spaces to the XPath context");
596 request_soap_body
= xmlXPathEvalExpression(
597 BAD_CAST
"/soap:Envelope/soap:Body", xpath_ctx
);
598 if (NULL
== request_soap_body
) {
599 xmlXPathFreeContext(xpath_ctx
);
600 xmlFreeDoc(request_doc
);
601 http_send_response_400(connection
, "Client sent invalid SOAP request");
604 if (xmlXPathNodeSetIsEmpty(request_soap_body
->nodesetval
)) {
605 xmlXPathFreeObject(request_soap_body
);
606 xmlXPathFreeContext(xpath_ctx
);
607 xmlFreeDoc(request_doc
);
608 http_send_response_400(connection
,
609 "SOAP request does not contain SOAP Body element");
612 if (request_soap_body
->nodesetval
->nodeNr
> 1) {
613 xmlXPathFreeObject(request_soap_body
);
614 xmlXPathFreeContext(xpath_ctx
);
615 xmlFreeDoc(request_doc
);
616 http_send_response_400(connection
,
617 "SOAP response has more than one Body element");
620 isds_request
= request_soap_body
->nodesetval
->nodeTab
[0]->children
;
621 if (isds_request
->next
!= NULL
) {
622 xmlXPathFreeObject(request_soap_body
);
623 xmlXPathFreeContext(xpath_ctx
);
624 xmlFreeDoc(request_doc
);
625 http_send_response_400(connection
, "SOAP body has more than one child");
628 if (isds_request
->type
!= XML_ELEMENT_NODE
|| isds_request
->ns
== NULL
||
629 NULL
== isds_request
->ns
->href
) {
630 xmlXPathFreeObject(request_soap_body
);
631 xmlXPathFreeContext(xpath_ctx
);
632 xmlFreeDoc(request_doc
);
633 http_send_response_400(connection
,
634 "SOAP body does not contain a name-space-qualified element");
638 /* Build SOAP response envelope */
639 response_doc
= xmlNewDoc(BAD_CAST
"1.0");
641 http_send_response_500(connection
,
642 "Could not build SOAP response document");
645 response_soap_envelope
= xmlNewNode(NULL
, BAD_CAST
"Envelope");
646 if (!response_soap_envelope
) {
647 http_send_response_500(connection
,
648 "Could not build SOAP response envelope");
651 xmlDocSetRootElement(response_doc
, response_soap_envelope
);
652 /* Only this way we get namespace definition as @xmlns:soap,
653 * otherwise we get namespace prefix without definition */
654 soap_ns
= xmlNewNs(response_soap_envelope
, BAD_CAST SOAP_NS
, NULL
);
655 if(NULL
== soap_ns
) {
656 http_send_response_500(connection
, "Could not create SOAP name space");
659 xmlSetNs(response_soap_envelope
, soap_ns
);
660 response_soap_body
= xmlNewChild(response_soap_envelope
, NULL
,
661 BAD_CAST
"Body", NULL
);
662 if (!response_soap_body
) {
663 http_send_response_500(connection
,
664 "Could not add Body to SOAP response envelope");
667 /* Append ISDS response element */
668 if (-1 == test_asprintf(&response_name
, "%s%s", isds_request
->name
,
670 http_send_response_500(connection
,
671 "Could not buld ISDS resposne element name");
674 isds_response
= xmlNewChild(response_soap_body
, NULL
,
675 BAD_CAST response_name
, NULL
);
677 if (NULL
== isds_response
) {
678 http_send_response_500(connection
,
679 "Could not add ISDS response element to SOAP response body");
682 isds_ns
= xmlNewNs(isds_response
, isds_request
->ns
->href
, NULL
);
683 if(NULL
== isds_ns
) {
684 http_send_response_500(connection
,
685 "Could not create a name space for the response body");
688 xmlSetNs(isds_response
, isds_ns
);
690 /* Dispatch request to service */
691 for (int i
= 0; i
< sizeof(services
)/sizeof(services
[0]); i
++) {
692 if (!strcmp(services
[i
].end_point
, end_point
) &&
693 !xmlStrcmp(services
[i
].name_space
, isds_request
->ns
->href
) &&
694 !xmlStrcmp(services
[i
].name
, isds_request
->name
)) {
695 /* Check if the configuration is enabled and find configuration */
696 for (const struct service_configuration
*service
= configuration
;
697 service
->name
!= SERVICE_END
; service
++) {
698 if (service
->name
== services
[i
].id
) {
700 if (!xmlStrcmp(services
[i
].name_space
, BAD_CAST OISDS_NS
)) {
701 /* Alias "isds" XPath identifier to OISDS_NS */
702 if (register_namespaces(xpath_ctx
, 1,
703 MESSAGE_NS_UNSIGNED
)) {
704 http_send_response_500(connection
,
705 "Could not register name spaces to the "
710 xpath_ctx
->node
= isds_request
;
711 if (HTTP_ERROR_SERVER
!= services
[i
].function(connection
,
712 request_doc
, xpath_ctx
, isds_request
,
713 response_doc
, isds_response
,
714 service
->arguments
)) {
717 http_send_response_500(connection
,
718 "Internal server error while processing "
728 if (service_passed
) {
729 /* Serialize the SOAP response */
730 http_response_body
= xmlBufferCreate();
731 if (NULL
== http_response_body
) {
732 http_send_response_500(connection
,
733 "Could not create xmlBuffer for response serialization");
736 /* Last argument 1 means format the XML tree. This is pretty but it breaks
737 * XML document transport as it adds text nodes (indentiation) between
739 save_ctx
= xmlSaveToBuffer(http_response_body
, "UTF-8", 0);
740 if (NULL
== save_ctx
) {
741 http_send_response_500(connection
, "Could not create XML serializer");
744 /* XXX: According LibXML documentation, this function does not return
745 * meaningful value yet */
746 xmlSaveDoc(save_ctx
, response_doc
);
747 if (-1 == xmlSaveFlush(save_ctx
)) {
748 http_send_response_500(connection
,
749 "Could not serialize SOAP response");
753 http_send_response_200(connection
, http_response_body
->content
,
754 http_response_body
->use
, soap_mime_type
);
758 xmlSaveClose(save_ctx
);
759 xmlBufferFree(http_response_body
);
761 xmlFreeDoc(response_doc
);
763 xmlXPathFreeObject(request_soap_body
);
764 xmlXPathFreeContext(xpath_ctx
);
765 xmlFreeDoc(request_doc
);
767 if (!service_handled
) {
768 http_send_response_500(connection
,
769 "Requested ISDS service not implemented");