3 #include <libxml/parser.h>
4 #include <libxml/xpath.h>
5 #include <libxml/xpathInternals.h>
7 static const char *soap_mime_type
= "text/xml"; /* SOAP/1.1 requires text/xml */
8 /* DummyOperation response */
9 static const char *pong
= "<?xml version='1.0' encoding='utf-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SOAP-ENV:Body><q:DummyOperationResponse xmlns:q=\"http://isds.czechpoint.cz/v20\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><q:dmStatus><q:dmStatusCode>0000</q:dmStatusCode><q:dmStatusMessage>Provedeno úspěšně.</q:dmStatusMessage></q:dmStatus></q:DummyOperationResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>";
11 /* Used to choose proper name space for message elements.
12 * See _isds_register_namespaces(). */
16 MESSAGE_NS_SIGNED_INCOMING
,
17 MESSAGE_NS_SIGNED_OUTGOING
,
18 MESSAGE_NS_SIGNED_DELIVERY
21 #define SOAP_NS "http://schemas.xmlsoap.org/soap/envelope/"
22 #define SOAP2_NS "http://www.w3.org/2003/05/soap-envelope"
23 #define ISDS1_NS "http://isds.czechpoint.cz"
24 #define ISDS_NS "http://isds.czechpoint.cz/v20"
25 #define SISDS_INCOMING_NS "http://isds.czechpoint.cz/v20/message"
26 #define SISDS_OUTGOING_NS "http://isds.czechpoint.cz/v20/SentMessage"
27 #define SISDS_DELIVERY_NS "http://isds.czechpoint.cz/v20/delivery"
28 #define SCHEMA_NS "http://www.w3.org/2001/XMLSchema"
29 #define DEPOSIT_NS "urn:uschovnaWSDL"
33 const char *end_point
;
35 void (*function
) (int, xmlDocPtr
, xmlXPathContextPtr
, xmlNodePtr
);
38 /* Parse and respond to DummyOperation */
39 static void service_DummyOperation(int socket
, const xmlDocPtr soap_request
,
40 xmlXPathContextPtr xpath_ctx
, xmlNodePtr isds_request
) {
41 http_send_response_200(socket
, pong
, strlen(pong
), soap_mime_type
);
45 /* List of implemented services */
46 static struct service services
[] = {
47 { "dz", BAD_CAST
"DummyOperation", service_DummyOperation
},
51 /* Makes known all relevant namespaces to given XPath context
52 * @xpath_ctx is XPath context
53 * @message_ns selects proper message name space. Unsigned and signed
54 * messages and delivery info's differ in prefix and URI.
55 * @return 0 in success, otherwise not 0. */
56 static int register_namespaces(xmlXPathContextPtr xpath_ctx
,
57 const message_ns_type message_ns
) {
58 const xmlChar
*message_namespace
= NULL
;
60 if (!xpath_ctx
) return -1;
64 message_namespace
= BAD_CAST ISDS1_NS
; break;
65 case MESSAGE_NS_UNSIGNED
:
66 message_namespace
= BAD_CAST ISDS_NS
; break;
67 case MESSAGE_NS_SIGNED_INCOMING
:
68 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
69 case MESSAGE_NS_SIGNED_OUTGOING
:
70 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
71 case MESSAGE_NS_SIGNED_DELIVERY
:
72 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
77 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
79 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
81 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
83 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))
85 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"deposit", BAD_CAST DEPOSIT_NS
))
91 /* Parse soap request, pass it to service endpoint and respond to it.
92 * It sends final HTTP response. */
93 void soap(int socket
, const void *request
, size_t request_length
) {
94 xmlDocPtr request_doc
= NULL
;
95 xmlXPathContextPtr xpath_ctx
= NULL
;
96 xmlXPathObjectPtr request_soap_body
= NULL
;
97 xmlNodePtr isds_request
= NULL
; /* pointer only */
98 _Bool service_handled
= 0;
100 if (NULL
== request
|| request_length
== 0) {
101 http_send_response_400(socket
, "Client sent empty body");
105 request_doc
= xmlParseMemory(request
, request_length
);
106 if (NULL
== request_doc
) {
107 http_send_response_400(socket
, "Client sent invalid XML document");
111 xpath_ctx
= xmlXPathNewContext(request_doc
);
112 if (NULL
== xpath_ctx
) {
113 xmlFreeDoc(request_doc
);
114 http_send_response_500(socket
, "Could not create XPath context");
118 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
119 xmlXPathFreeContext(xpath_ctx
);
120 xmlFreeDoc(request_doc
);
121 http_send_response_500(socket
,
122 "Could not register name spaces to the XPath context");
127 request_soap_body
= xmlXPathEvalExpression(
128 BAD_CAST
"/soap:Envelope/soap:Body", xpath_ctx
);
129 if (NULL
== request_soap_body
) {
130 xmlXPathFreeContext(xpath_ctx
);
131 xmlFreeDoc(request_doc
);
132 http_send_response_400(socket
, "Client sent invalid SOAP request");
135 if (xmlXPathNodeSetIsEmpty(request_soap_body
->nodesetval
)) {
136 xmlXPathFreeObject(request_soap_body
);
137 xmlXPathFreeContext(xpath_ctx
);
138 xmlFreeDoc(request_doc
);
139 http_send_response_400(socket
,
140 "SOAP request does not contain SOAP Body element");
143 if (request_soap_body
->nodesetval
->nodeNr
> 1) {
144 xmlXPathFreeObject(request_soap_body
);
145 xmlXPathFreeContext(xpath_ctx
);
146 xmlFreeDoc(request_doc
);
147 http_send_response_400(socket
,
148 "SOAP response has more than one Body element");
151 isds_request
= request_soap_body
->nodesetval
->nodeTab
[0]->children
;
152 if (isds_request
->next
!= NULL
) {
153 xmlXPathFreeObject(request_soap_body
);
154 xmlXPathFreeContext(xpath_ctx
);
155 xmlFreeDoc(request_doc
);
156 http_send_response_400(socket
, "SOAP body has more than one child");
159 if (isds_request
->type
!= XML_ELEMENT_NODE
|| isds_request
->ns
== NULL
||
160 xmlStrcmp(isds_request
->ns
->href
, BAD_CAST ISDS_NS
)) {
161 xmlXPathFreeObject(request_soap_body
);
162 xmlXPathFreeContext(xpath_ctx
);
163 xmlFreeDoc(request_doc
);
164 http_send_response_400(socket
,
165 "SOAP body does not contain an ISDS elment");
170 /* Dispatch request to service */
171 /* TODO: Use end point */
172 for (int i
= 0; i
< sizeof(services
)/sizeof(services
[0]); i
++) {
173 if (!xmlStrcmp(services
[i
].name
, isds_request
->name
)) {
174 services
[i
].function(socket
, request_doc
, xpath_ctx
, isds_request
);
180 xmlXPathFreeObject(request_soap_body
);
181 xmlXPathFreeContext(xpath_ctx
);
182 xmlFreeDoc(request_doc
);
184 if (service_handled
) {
185 http_send_response_500(socket
,
186 "Requested ISDS service not implemented");