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
) (int, xmlDocPtr
, xmlXPathContextPtr
, xmlNodePtr
,
42 xmlDocPtr
, xmlNodePtr
, const void *arguments
);
45 /* Following EXTRACT_* macros expect @xpath_ctx, @message, and leave label */
46 #define EXTRACT_STRING(element, string) { \
47 xmlXPathObjectPtr result = NULL; \
48 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
49 if (NULL == result) { \
50 error = HTTP_ERROR_SERVER; \
53 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
54 if (result->nodesetval->nodeNr > 1) { \
55 xmlXPathFreeObject(result); \
56 test_asprintf(&message, "Multiple %s element", element); \
57 error = HTTP_ERROR_CLIENT; \
61 xmlXPathCastNodeSetToString(result->nodesetval); \
63 xmlXPathFreeObject(result); \
64 error = HTTP_ERROR_SERVER; \
68 xmlXPathFreeObject(result); \
71 #define EXTRACT_BOOLEAN(element, booleanPtr) { \
72 char *string = NULL; \
73 EXTRACT_STRING(element, string); \
75 if (NULL != string) { \
76 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
77 if (NULL == (booleanPtr)) { \
79 error = HTTP_ERROR_SERVER; \
83 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
84 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
86 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
87 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
90 test_asprintf(&message, \
91 "%s value is not valid boolean: %s", \
94 error = HTTP_ERROR_CLIENT; \
103 /* Following INSERT_* macros expect @error and leave label */
104 #define INSERT_STRING_WITH_NS(parent, ns, element, string) \
106 xmlNodePtr node = xmlNewTextChild(parent, ns, BAD_CAST (element), \
107 (xmlChar *) (string)); \
108 if (NULL == node) { \
109 error = HTTP_ERROR_SERVER; \
114 #define INSERT_STRING(parent, element, string) \
115 { INSERT_STRING_WITH_NS(parent, NULL, element, string) }
117 #define INSERT_ELEMENT(child, parent, element) \
119 (child) = xmlNewChild((parent), NULL, BAD_CAST (element), NULL); \
120 if (NULL == (child)) { \
121 error = HTTP_ERROR_SERVER; \
126 /* Insert dmStatus or similar subtree
127 * @parent is element to insert to
128 * @dm is true for dmStatus, otherwise dbStatus
129 * @code is stautus code as string
130 * @message is UTF-8 encoded message
131 * @db_ref_number is optinal reference number propagated if not @dm
132 * @return 0 on success, otherwise non-0. */
133 static http_error
insert_isds_status(xmlNodePtr parent
, _Bool dm
,
134 const xmlChar
*code
, const xmlChar
*message
,
135 const xmlChar
*db_ref_number
) {
136 http_error error
= HTTP_ERROR_SUCCESS
;
139 if (NULL
== code
|| NULL
== message
) {
140 error
= HTTP_ERROR_SERVER
;
144 INSERT_ELEMENT(status
, parent
, (dm
) ? "dmStatus" : "dbStatus");
145 INSERT_STRING(status
, (dm
) ? "dmStatusCode" : "dbStatusCode", code
);
146 INSERT_STRING(status
, (dm
) ? "dmStatusMessage" : "dbStatusMessage", message
);
147 if (!dm
&& NULL
!= db_ref_number
) {
148 INSERT_STRING(status
, "dbStatusRefNumber", db_ref_number
);
156 /* Implement DummyOperation */
157 static http_error
service_DummyOperation(int socket
, const xmlDocPtr soap_request
,
158 xmlXPathContextPtr xpath_ctx
, xmlNodePtr isds_request
,
159 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
160 const void *arguments
) {
161 return insert_isds_status(isds_response
, 1, BAD_CAST
"0000",
162 BAD_CAST
"Success", NULL
);
166 /* Implement EraseMessage.
167 * @arguments is pointer to struct arguments_DS_DsManage_ChangeISDSPassword */
168 static http_error
service_EraseMessage(int socket
,
169 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
170 const xmlNodePtr isds_request
,
171 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
172 const void *arguments
) {
173 http_error error
= HTTP_ERROR_SUCCESS
;
174 char *code
= "9999", *message
= NULL
;
175 const struct arguments_DS_Dx_EraseMessage
*configuration
=
176 (const struct arguments_DS_Dx_EraseMessage
*)arguments
;
177 char *message_id
= NULL
;
178 _Bool
*incoming
= NULL
;
180 if (NULL
== configuration
|| NULL
== configuration
->message_id
) {
181 error
= HTTP_ERROR_SERVER
;
185 EXTRACT_STRING("isds:dmID", message_id
);
186 if (NULL
== message_id
) {
187 message
= strdup("Missing isds:dmID");
188 error
= HTTP_ERROR_CLIENT
;
191 EXTRACT_BOOLEAN("isds:dmIncoming", incoming
);
192 if (NULL
== incoming
) {
193 message
= strdup("Missing isds:dmIncoming");
194 error
= HTTP_ERROR_CLIENT
;
198 if (xmlStrcmp((const xmlChar
*) configuration
->message_id
,
199 (const xmlChar
*) message_id
)) {
201 message
= strdup("Message is not in the long term storage");
202 error
= HTTP_ERROR_CLIENT
;
205 if (configuration
->incoming
!= *incoming
) {
207 message
= strdup("Message direction mismatches");
208 error
= HTTP_ERROR_CLIENT
;
213 message
= strdup("Success");
215 if (HTTP_ERROR_SERVER
!= error
) {
216 http_error next_error
= insert_isds_status(isds_response
, 1,
217 BAD_CAST code
, BAD_CAST message
, NULL
);
218 if (HTTP_ERROR_SUCCESS
!= next_error
) error
= next_error
;
227 /* Common part for ChangeISDSPassword and ChangePasswordOTP.
228 * @code is output pointer to static string
229 * @pass_message is output pointer to auto-allocated string
230 * @arguments is pointer to struct arguments_DS_DsManage_ChangeISDSPassword */
231 static http_error
check_passwd(
232 const char *username
, const char *current_password
,
233 xmlXPathContextPtr xpath_ctx
,
234 char **code
, char **pass_message
) {
235 http_error error
= HTTP_ERROR_SUCCESS
;
236 char *message
= NULL
;
237 char *old_password
= NULL
, *new_password
= NULL
;
240 if (NULL
== username
|| NULL
== current_password
||
241 NULL
== code
|| NULL
== pass_message
) {
242 error
= HTTP_ERROR_SERVER
;
250 EXTRACT_STRING("isds:dbOldPassword", old_password
);
251 if (NULL
== old_password
) {
252 message
= strdup("Empty isds:dbOldPassword");
253 error
= HTTP_ERROR_CLIENT
;
256 EXTRACT_STRING("isds:dbNewPassword", new_password
);
257 if (NULL
== new_password
) {
258 message
= strdup("Empty isds:dbOldPassword");
259 error
= HTTP_ERROR_CLIENT
;
263 /* Check defined cases */
264 if (strcmp(current_password
, old_password
)) {
266 message
= strdup("Bad current password");
267 error
= HTTP_ERROR_CLIENT
;
271 length
= strlen(new_password
);
273 if (length
< 8 || length
> 32) {
275 message
= strdup("Too short or too long");
276 error
= HTTP_ERROR_CLIENT
;
281 const char lower
[] = "abcdefghijklmnopqrstuvwxyz";
282 const char upper
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
283 const char digit
[] = "0123456789";
284 const char special
[] = "!#$%&()*+,-.:=?@[]_{}|~";
285 _Bool has_lower
= 0, has_upper
= 0, has_digit
=0;
287 for (int i
= 0; i
< length
; i
++) {
288 if (NULL
!= strchr(lower
, new_password
[i
]))
290 else if (NULL
!= strchr(upper
, new_password
[i
]))
292 else if (NULL
!= strchr(digit
, new_password
[i
]))
294 else if (NULL
== strchr(special
, new_password
[i
])) {
296 message
= strdup("Password contains forbidden character");
297 error
= HTTP_ERROR_CLIENT
;
302 if (!has_lower
|| !has_upper
|| !has_digit
) {
304 message
= strdup("Password does not contain lower cased letter, "
305 "upper cased letter and a digit");
306 error
= HTTP_ERROR_CLIENT
;
311 if (!strcmp(old_password
, new_password
)) {
313 message
= strdup("New password same as current one");
314 error
= HTTP_ERROR_CLIENT
;
318 if (NULL
!= strstr(new_password
, username
)) {
320 message
= strdup("New password contains user ID");
321 error
= HTTP_ERROR_CLIENT
;
325 for (int i
= 0; i
< length
- 2; i
++) {
326 if (new_password
[i
] == new_password
[i
+1] &&
327 new_password
[i
] == new_password
[i
+2]) {
329 message
= strdup("Password contains sequence "
330 "of three identical characters");
331 error
= HTTP_ERROR_CLIENT
;
337 const char *forbidden_prefix
[] = { "qwert", "asdgf", "12345" };
338 for (int i
= 0; i
< sizeof(forbidden_prefix
)/sizeof(*forbidden_prefix
);
340 if (!strncmp(new_password
, forbidden_prefix
[i
],
341 strlen(forbidden_prefix
[i
]))) {
343 message
= strdup("Password has forbidden prefix");
344 error
= HTTP_ERROR_CLIENT
;
351 message
= strdup("Success");
355 *pass_message
= message
;
360 /* Implement ChangeISDSPassword.
361 * @arguments is pointer to struct arguments_DS_DsManage_ChangeISDSPassword */
362 static http_error
service_ChangeISDSPassword(int socket
,
363 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
364 const xmlNodePtr isds_request
,
365 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
366 const void *arguments
) {
367 http_error error
= HTTP_ERROR_SUCCESS
;
368 char *code
= "9999", *message
= NULL
;
369 const struct arguments_DS_DsManage_ChangeISDSPassword
*configuration
=
370 (const struct arguments_DS_DsManage_ChangeISDSPassword
*)arguments
;
372 if (NULL
== configuration
|| NULL
== configuration
->username
||
373 NULL
== configuration
->current_password
) {
374 error
= HTTP_ERROR_SERVER
;
378 /* Check for common password rules */
379 error
= check_passwd(
380 configuration
->username
, configuration
->current_password
,
381 xpath_ctx
, &code
, &message
);
384 if (HTTP_ERROR_SERVER
!= error
) {
385 http_error next_error
= insert_isds_status(isds_response
, 0,
386 BAD_CAST code
, BAD_CAST message
, NULL
);
387 if (HTTP_ERROR_SUCCESS
!= next_error
) error
= next_error
;
394 /* Implement ChangePasswordOTP.
395 * @arguments is pointer to struct
396 * arguments_asws_changePassword_ChangePasswordOTP */
397 static http_error
service_ChangePasswordOTP(int socket
,
398 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
399 const xmlNodePtr isds_request
,
400 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
401 const void *arguments
) {
402 http_error error
= HTTP_ERROR_SUCCESS
;
403 char *code
= "9999", *message
= NULL
;
404 const struct arguments_asws_changePassword_ChangePasswordOTP
*configuration
405 = (const struct arguments_asws_changePassword_ChangePasswordOTP
*)
409 if (NULL
== configuration
|| NULL
== configuration
->username
||
410 NULL
== configuration
->current_password
) {
411 error
= HTTP_ERROR_SERVER
;
415 /* Chek for OTP method */
416 EXTRACT_STRING("isds:dbOTPType", method
);
417 if (NULL
== method
) {
418 message
= strdup("Empty isds:dbOTPType");
419 error
= HTTP_ERROR_CLIENT
;
422 if ((configuration
->method
== AUTH_OTP_HMAC
&& strcmp(method
, "HOTP")) ||
423 (configuration
->method
== AUTH_OTP_TIME
&& strcmp(method
, "TOTP"))) {
424 message
= strdup("isds:dbOTPType does not match OTP method");
425 error
= HTTP_ERROR_CLIENT
;
429 /* Check for common password rules */
430 error
= check_passwd(
431 configuration
->username
, configuration
->current_password
,
432 xpath_ctx
, &code
, &message
);
435 if (HTTP_ERROR_SERVER
!= error
) {
436 http_error next_error
= insert_isds_status(isds_response
, 0,
437 BAD_CAST code
, BAD_CAST message
,
438 BAD_CAST configuration
->reference_number
);
439 if (HTTP_ERROR_SUCCESS
!= next_error
) error
= next_error
;
447 /* Implement SendSMSCode.
448 * @arguments is pointer to struct arguments_asws_changePassword_SendSMSCode */
449 static http_error
service_SendSMSCode(int socket
,
450 const xmlDocPtr soap_request
, xmlXPathContextPtr xpath_ctx
,
451 const xmlNodePtr isds_request
,
452 xmlDocPtr soap_response
, xmlNodePtr isds_response
,
453 const void *arguments
) {
454 const struct arguments_asws_changePassword_SendSMSCode
*configuration
455 = (const struct arguments_asws_changePassword_SendSMSCode
*)
458 if (NULL
== configuration
|| NULL
== configuration
->status_code
||
459 NULL
== configuration
->status_message
) {
460 return HTTP_ERROR_SERVER
;
463 return insert_isds_status(isds_response
, 0,
464 BAD_CAST configuration
->status_code
,
465 BAD_CAST configuration
->status_message
,
466 BAD_CAST configuration
->reference_number
);
470 /* List of implemented services */
471 static struct service services
[] = {
472 { SERVICE_DS_Dz_DummyOperation
,
473 "DS/dz", BAD_CAST ISDS_NS
, BAD_CAST
"DummyOperation",
474 service_DummyOperation
},
475 { SERVICE_DS_DsManage_ChangeISDSPassword
,
476 "DS/DsManage", BAD_CAST ISDS_NS
, BAD_CAST
"ChangeISDSPassword",
477 service_ChangeISDSPassword
},
478 { SERVICE_DS_Dx_EraseMessage
,
479 "DS/dx", BAD_CAST ISDS_NS
, BAD_CAST
"EraseMessage",
480 service_EraseMessage
},
481 { SERVICE_asws_changePassword_ChangePasswordOTP
,
482 "/asws/changePassword", BAD_CAST OISDS_NS
, BAD_CAST
"ChangePasswordOTP",
483 service_ChangePasswordOTP
},
484 { SERVICE_asws_changePassword_SendSMSCode
,
485 "/asws/changePassword", BAD_CAST OISDS_NS
, BAD_CAST
"SendSMSCode",
486 service_SendSMSCode
},
490 /* Makes known all relevant namespaces to given XPath context
491 * @xpath_ctx is XPath context
492 * @otp_ns selects name space for the request and response know as "isds".
493 * Use true for OTP-authenticated password change services, otherwise false.
494 * @message_ns selects proper message name space. Unsigned and signed
495 * messages and delivery info's differ in prefix and URI.
496 * @return 0 in success, otherwise not 0. */
497 static int register_namespaces(xmlXPathContextPtr xpath_ctx
,
498 const _Bool otp_ns
, const message_ns_type message_ns
) {
499 const xmlChar
*service_namespace
= NULL
;
500 const xmlChar
*message_namespace
= NULL
;
502 if (!xpath_ctx
) return -1;
505 service_namespace
= BAD_CAST OISDS_NS
;
507 service_namespace
= BAD_CAST ISDS_NS
;
512 message_namespace
= BAD_CAST ISDS1_NS
; break;
513 case MESSAGE_NS_UNSIGNED
:
514 message_namespace
= BAD_CAST ISDS_NS
; break;
515 case MESSAGE_NS_SIGNED_INCOMING
:
516 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
517 case MESSAGE_NS_SIGNED_OUTGOING
:
518 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
519 case MESSAGE_NS_SIGNED_DELIVERY
:
520 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
525 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
527 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", service_namespace
))
529 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
531 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))
533 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"deposit", BAD_CAST DEPOSIT_NS
))
539 /* Parse soap request, pass it to service endpoint and respond to it.
540 * It sends final HTTP response. */
541 void soap(int socket
, const struct service_configuration
*configuration
,
542 const void *request
, size_t request_length
, const char *end_point
) {
543 xmlDocPtr request_doc
= NULL
;
544 xmlXPathContextPtr xpath_ctx
= NULL
;
545 xmlXPathObjectPtr request_soap_body
= NULL
;
546 xmlNodePtr isds_request
= NULL
; /* pointer only */
547 _Bool service_handled
= 0, service_passed
= 0;
548 xmlDocPtr response_doc
= NULL
;
549 xmlNodePtr response_soap_envelope
= NULL
, response_soap_body
= NULL
,
550 isds_response
= NULL
;
551 xmlNsPtr soap_ns
= NULL
, isds_ns
= NULL
;
552 char *response_name
= NULL
;
553 xmlBufferPtr http_response_body
= NULL
;
554 xmlSaveCtxtPtr save_ctx
= NULL
;
557 if (NULL
== configuration
) {
558 http_send_response_500(socket
, "Second argument of soap() is NULL");
562 if (NULL
== request
|| request_length
== 0) {
563 http_send_response_400(socket
, "Client sent empty body");
567 request_doc
= xmlParseMemory(request
, request_length
);
568 if (NULL
== request_doc
) {
569 http_send_response_400(socket
, "Client sent invalid XML document");
573 xpath_ctx
= xmlXPathNewContext(request_doc
);
574 if (NULL
== xpath_ctx
) {
575 xmlFreeDoc(request_doc
);
576 http_send_response_500(socket
, "Could not create XPath context");
580 if (register_namespaces(xpath_ctx
, 0, MESSAGE_NS_UNSIGNED
)) {
581 xmlXPathFreeContext(xpath_ctx
);
582 xmlFreeDoc(request_doc
);
583 http_send_response_500(socket
,
584 "Could not register name spaces to the XPath context");
589 request_soap_body
= xmlXPathEvalExpression(
590 BAD_CAST
"/soap:Envelope/soap:Body", xpath_ctx
);
591 if (NULL
== request_soap_body
) {
592 xmlXPathFreeContext(xpath_ctx
);
593 xmlFreeDoc(request_doc
);
594 http_send_response_400(socket
, "Client sent invalid SOAP request");
597 if (xmlXPathNodeSetIsEmpty(request_soap_body
->nodesetval
)) {
598 xmlXPathFreeObject(request_soap_body
);
599 xmlXPathFreeContext(xpath_ctx
);
600 xmlFreeDoc(request_doc
);
601 http_send_response_400(socket
,
602 "SOAP request does not contain SOAP Body element");
605 if (request_soap_body
->nodesetval
->nodeNr
> 1) {
606 xmlXPathFreeObject(request_soap_body
);
607 xmlXPathFreeContext(xpath_ctx
);
608 xmlFreeDoc(request_doc
);
609 http_send_response_400(socket
,
610 "SOAP response has more than one Body element");
613 isds_request
= request_soap_body
->nodesetval
->nodeTab
[0]->children
;
614 if (isds_request
->next
!= NULL
) {
615 xmlXPathFreeObject(request_soap_body
);
616 xmlXPathFreeContext(xpath_ctx
);
617 xmlFreeDoc(request_doc
);
618 http_send_response_400(socket
, "SOAP body has more than one child");
621 if (isds_request
->type
!= XML_ELEMENT_NODE
|| isds_request
->ns
== NULL
||
622 NULL
== isds_request
->ns
->href
) {
623 xmlXPathFreeObject(request_soap_body
);
624 xmlXPathFreeContext(xpath_ctx
);
625 xmlFreeDoc(request_doc
);
626 http_send_response_400(socket
,
627 "SOAP body does not contain a name-space-qualified element");
631 /* Build SOAP response envelope */
632 response_doc
= xmlNewDoc(BAD_CAST
"1.0");
634 http_send_response_500(socket
, "Could not build SOAP response document");
637 response_soap_envelope
= xmlNewNode(NULL
, BAD_CAST
"Envelope");
638 if (!response_soap_envelope
) {
639 http_send_response_500(socket
, "Could not build SOAP response envelope");
642 xmlDocSetRootElement(response_doc
, response_soap_envelope
);
643 /* Only this way we get namespace definition as @xmlns:soap,
644 * otherwise we get namespace prefix without definition */
645 soap_ns
= xmlNewNs(response_soap_envelope
, BAD_CAST SOAP_NS
, NULL
);
646 if(NULL
== soap_ns
) {
647 http_send_response_500(socket
, "Could not create SOAP name space");
650 xmlSetNs(response_soap_envelope
, soap_ns
);
651 response_soap_body
= xmlNewChild(response_soap_envelope
, NULL
,
652 BAD_CAST
"Body", NULL
);
653 if (!response_soap_body
) {
654 http_send_response_500(socket
,
655 "Could not add Body to SOAP response envelope");
658 /* Append ISDS response element */
659 if (-1 == test_asprintf(&response_name
, "%s%s", isds_request
->name
,
661 http_send_response_500(socket
,
662 "Could not buld ISDS resposne element name");
665 isds_response
= xmlNewChild(response_soap_body
, NULL
,
666 BAD_CAST response_name
, NULL
);
668 if (NULL
== isds_response
) {
669 http_send_response_500(socket
,
670 "Could not add ISDS response element to SOAP response body");
673 isds_ns
= xmlNewNs(isds_response
, isds_request
->ns
->href
, NULL
);
674 if(NULL
== isds_ns
) {
675 http_send_response_500(socket
,
676 "Could not create a name space for the response body");
679 xmlSetNs(isds_response
, isds_ns
);
681 /* Dispatch request to service */
682 for (int i
= 0; i
< sizeof(services
)/sizeof(services
[0]); i
++) {
683 if (!strcmp(services
[i
].end_point
, end_point
) &&
684 !xmlStrcmp(services
[i
].name_space
, isds_request
->ns
->href
) &&
685 !xmlStrcmp(services
[i
].name
, isds_request
->name
)) {
686 /* Check if the configuration is enabled and find configuration */
687 for (const struct service_configuration
*service
= configuration
;
688 service
->name
!= SERVICE_END
; service
++) {
689 if (service
->name
== services
[i
].id
) {
691 if (!xmlStrcmp(services
[i
].name_space
, BAD_CAST OISDS_NS
)) {
692 /* Alias "isds" XPath identifier to OISDS_NS */
693 if (register_namespaces(xpath_ctx
, 1,
694 MESSAGE_NS_UNSIGNED
)) {
695 http_send_response_500(socket
,
696 "Could not register name spaces to the "
701 xpath_ctx
->node
= isds_request
;
702 if (HTTP_ERROR_SERVER
!= services
[i
].function(socket
,
703 request_doc
, xpath_ctx
, isds_request
,
704 response_doc
, isds_response
,
705 service
->arguments
)) {
708 http_send_response_500(socket
,
709 "Internal server error while processing "
719 if (service_passed
) {
720 /* Serialize the SOAP response */
721 http_response_body
= xmlBufferCreate();
722 if (NULL
== http_response_body
) {
723 http_send_response_500(socket
,
724 "Could not create xmlBuffer for response serialization");
727 /* Last argument 1 means format the XML tree. This is pretty but it breaks
728 * XML document transport as it adds text nodes (indentiation) between
730 save_ctx
= xmlSaveToBuffer(http_response_body
, "UTF-8", 0);
731 if (NULL
== save_ctx
) {
732 http_send_response_500(socket
, "Could not create XML serializer");
735 /* XXX: According LibXML documentation, this function does not return
736 * meaningful value yet */
737 xmlSaveDoc(save_ctx
, response_doc
);
738 if (-1 == xmlSaveFlush(save_ctx
)) {
739 http_send_response_500(socket
,
740 "Could not serialize SOAP response");
744 http_send_response_200(socket
, http_response_body
->content
,
745 http_response_body
->use
, soap_mime_type
);
749 xmlSaveClose(save_ctx
);
750 xmlBufferFree(http_response_body
);
752 xmlFreeDoc(response_doc
);
754 xmlXPathFreeObject(request_soap_body
);
755 xmlXPathFreeContext(xpath_ctx
);
756 xmlFreeDoc(request_doc
);
758 if (!service_handled
) {
759 http_send_response_500(socket
,
760 "Requested ISDS service not implemented");