/*############################################################################## Copyright (C) 2011 HPCC Systems. All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . ############################################################################## */ #pragma warning( disable : 4786) #ifdef WIN32 #ifdef ESPHTTP_EXPORTS #define esp_http_decl __declspec(dllexport) #endif #endif #include //ESP Bindings #include "espcontext.hpp" #include "http/client/httpclient.hpp" #include "SOAP/client/soapclient.hpp" #include "bindutil.hpp" #include int CSoapClient::setUsernameToken(const char* username, const char* password, const char* realm) { m_username.set(username); m_password.set(password); m_realm.set(realm); return 0; } // Under most cases, use this one int CSoapClient::postRequest(IRpcMessage& rpccall, IRpcMessage& rpcresponse) { return postRequest(NULL, NULL, rpccall, rpcresponse); } // If you want to set a soapaction http header, use this one. int CSoapClient::postRequest(const char* soapaction, IRpcMessage& rpccall, StringBuffer& resp) { return postRequest(NULL, soapaction, rpccall, resp); } // If you want to set a soapaction http header, use this one. int CSoapClient::postRequest(const char* soapaction, IRpcMessage& rpccall, StringBuffer& resp, IRpcMessageArray *headers) { return postRequest(NULL, soapaction, rpccall, resp, headers); } int CSoapClient::postRequest(const char* soapaction, IRpcMessage& rpccall, IRpcMessage& rpcresponse) { return postRequest(NULL, soapaction, rpccall, rpcresponse); } // If you want a content-type that is different from "soap/application", use this one. This should not be necessary // unless the server side doesn't follow the standard. int CSoapClient::postRequest(const char* contenttype, const char* soapaction, IRpcMessage& rpccall, StringBuffer& responsebuf) { return postRequest(contenttype, soapaction, rpccall, responsebuf, NULL, NULL); } int CSoapClient::postRequest(const char* contenttype, const char* soapaction, IRpcMessage& rpccall, StringBuffer& responsebuf, IRpcMessageArray *headers) { return postRequest(contenttype, soapaction, rpccall, responsebuf, NULL, headers); } int CSoapClient::postRequest(const char* contenttype, const char* soapaction, IRpcMessage& rpccall, StringBuffer& responsebuf, CMimeMultiPart* resp_multipart, IRpcMessageArray *headers) { CRpcCall* call = (CRpcCall *)&rpccall; CBody* req_body = new CBody; req_body->add_rpcmessage(call); CHeader* req_header = NULL; if(m_username.length() > 0) { req_header = new CHeader; IRpcMessage* oneblock = new CRpcMessage("Security"); oneblock->set_ns("wsse"); oneblock->add_value("", "wsse", "UsernameToken", "", ""); oneblock->add_value("UsernameToken", "wsse", "Username", "", m_username.get()); oneblock->add_value("UsernameToken", "wsse", "Password", "", m_password.get()); oneblock->add_value("RealmToken", "wsse", "Realm", "", m_realm.get()); req_header->addHeaderBlock(oneblock); } if (headers) { if (!req_header) req_header = new CHeader; ForEachItemIn(idx, *headers) { req_header->addHeaderBlock(&headers->item(idx)); headers->remove(idx, true); } } // Form request Owned req_envelope; req_envelope.setown(new CEnvelope(req_header, req_body)); Owned multipart; multipart.setown(new CMimeMultiPart("1.0", "", "MIME_boundary", "text/xml", "soaproot")); req_envelope->marshall(multipart); StringBuffer requeststr; StringBuffer contenttypestr; if(multipart->getBodyCount() == 1) { CMimeBodyPart* rootpart = multipart->queryRootPart(); rootpart->getContent(requeststr); } else { multipart->serialize(contenttypestr, requeststr); } if (getEspLogLevel(rpccall.queryContext())>LogNormal) { DBGLOG("Content type: %s", contenttypestr.str()); DBGLOG("Request content: %s", requeststr.str()); } Owned soap_request; soap_request.setown(new CSoapRequest); //Use the provided contenttype to overwrite the default content type. if(contenttype != NULL && strlen(contenttype) > 0) soap_request->set_content_type(contenttype); else soap_request->set_content_type(contenttypestr.str()); soap_request->set_text(requeststr.str()); if(soapaction != NULL && strlen(soapaction) > 0) soap_request->set_soapaction(soapaction); Owned soap_response; soap_response.setown(new CSoapResponse); //Send request and get response if(m_transportclient.get() == NULL) { Owned httpctx = getHttpClientContext(); IHttpClient* httpclient = httpctx->createHttpClient(call->getProxy(), call->get_url()); m_transportclient.setown(httpclient); if (m_disableKeepAlive) httpclient->disableKeepAlive(); if(m_username.length() > 0) { httpclient->setUserID(m_username.get()); httpclient->setPassword(m_password.get()); } if(m_realm.length() > 0) { httpclient->setRealm(m_realm.get()); } } m_transportclient->postRequest(*soap_request.get(), *soap_response.get()); int retstatus = soap_response->get_status(); if(retstatus != SOAP_OK) { StringBuffer errmsg = "SOAP error"; if(retstatus == SOAP_CLIENT_ERROR) errmsg = "SOAP client error"; else if(retstatus == SOAP_SERVER_ERROR) errmsg = "SOAP server error"; else if(retstatus == SOAP_RPC_ERROR) errmsg = "SOAP rpc error"; else if(retstatus == SOAP_CONNECTION_ERROR) errmsg = "SOAP Connection error"; else if(retstatus == SOAP_REQUEST_TYPE_ERROR) errmsg = "SOAP request type error"; else if(retstatus == SOAP_AUTHENTICATION_ERROR) errmsg = "SOAP authentication error"; const char *errText = soap_response->get_err(); if (errText && *errText) errmsg.appendf("[%s]", errText); throw MakeStringException(retstatus, "%s", errmsg.str()); } #if defined(DEBUG_HTTP_) DBGLOG("response content type = %s", soap_response->get_content_type()); #endif if(!Utils::strncasecmp(soap_response->get_content_type(), "application/soap", strlen("application/soap")) || !Utils::strncasecmp(soap_response->get_content_type(), "text/xml", strlen("text/xml"))) { responsebuf.append(soap_response->get_text()); } else if(!Utils::strncasecmp(soap_response->get_content_type(), "Multipart/Related", strlen("Multipart/Related"))) { CMimeMultiPart* parts = resp_multipart ? resp_multipart : new CMimeMultiPart("1.0", "Multipart/Related", "", "", ""); parts->unserialize(soap_response->get_content_type(), soap_response->get_text_length(), soap_response->get_text()); CMimeBodyPart* rootpart = parts->queryRootPart(); rootpart->getContent(responsebuf); if (!resp_multipart) delete parts; } else { DBGLOG("SOAP Response type %s not supported", soap_response->get_content_type()); return SOAP_REQUEST_TYPE_ERROR; } if(responsebuf.length() == 0) { throw MakeStringException(-1, "Empty SOAP message received"); } return SOAP_OK; } int CSoapClient::postRequest(const char* contenttype, const char* soapaction, IRpcMessage& rpccall, IRpcMessage& rpcresponse) { StringBuffer responsebuf; Owned parts = new CMimeMultiPart("1.0", "Multipart/Related", "", "", ""); int rt = postRequest(contenttype, soapaction, rpccall, responsebuf, parts); if (rt != SOAP_OK) return rt; // DBGLOG("response SoapClient got from soap server = \n%s", responsebuf.str()); auto_ptr xpp(new XmlPullParser()); int bufSize = responsebuf.length(); xpp->setSupportNamespaces(true); xpp->setInput(responsebuf.str(), bufSize); int type; StartTag stag; EndTag etag; Owned res_envelope; res_envelope.setown(new CEnvelope); while((type = xpp->next()) != XmlPullParser::END_DOCUMENT) { if(type == XmlPullParser::START_TAG) { xpp->readStartTag(stag); if(!stricmp(stag.getLocalName(), SOAP_ENVELOPE_NAME)) { res_envelope->unmarshall(xpp.get()); break; } } } CBody* res_body = res_envelope->get_body(); CRpcResponse* response = (CRpcResponse *)&rpcresponse; res_body->nextRpcMessage(response); response->unmarshall(xpp.get(), parts.get()); return SOAP_OK; } int CSoapClient::postRequest(IRpcMessage & rpccall, StringBuffer & responsebuf) { return postRequest(rpccall, responsebuf, NULL); } int CSoapClient::postRequest(IRpcMessage & rpccall, StringBuffer & responsebuf, IRpcMessageArray *headers) { CRpcCall* call = (CRpcCall *)&rpccall; CBody* req_body = new CBody; req_body->add_rpcmessage(call); CHeader* req_header = NULL; if(m_username.length() > 0) { req_header = new CHeader; IRpcMessage* oneblock = new CRpcMessage("Security"); oneblock->set_ns("wsse"); oneblock->add_value("", "wsse", "UsernameToken", "", ""); oneblock->add_value("UsernameToken", "wsse", "Username", "", m_username.get()); oneblock->add_value("UsernameToken", "wsse", "Password", "", m_password.get()); oneblock->add_value("RealmToken", "wsse", "Realm", "", m_realm.get()); req_header->addHeaderBlock(oneblock); } if (headers) { if (!req_header) req_header = new CHeader; ForEachItemIn(idx, *headers) { req_header->addHeaderBlock(&headers->item(idx)); headers->remove(idx, true); } } // Form request Owned req_envelope; req_envelope.setown(new CEnvelope(req_header, req_body)); Owned multipart; multipart.setown(new CMimeMultiPart("1.0", "", "MIME_boundary", "text/xml", "soaproot")); req_envelope->marshall(multipart); StringBuffer requeststr; StringBuffer contenttypestr; if(multipart->getBodyCount() == 1) { CMimeBodyPart* rootpart = multipart->queryRootPart(); rootpart->getContent(requeststr); } else { multipart->serialize(contenttypestr, requeststr); } Owned soap_request = new CSoapRequest(); soap_request->set_content_type(contenttypestr.str()); soap_request->set_text(requeststr.str()); #if defined(DEBUG_HTTP_) DBGLOG("SOAP Request content: %s", requeststr.str()); #endif Owned soap_response = new CSoapResponse(); //Send request and get response if(m_transportclient.get() == NULL) { Owned httpctx = getHttpClientContext(); IHttpClient* httpclient = httpctx->createHttpClient(call->getProxy(), call->get_url()); m_transportclient.setown(httpclient); if (m_disableKeepAlive) httpclient->disableKeepAlive(); if(m_username.length() > 0) { httpclient->setUserID(m_username.get()); httpclient->setPassword(m_password.get()); } if(m_realm.length() > 0) { httpclient->setRealm(m_realm.get()); } } m_transportclient->postRequest(*soap_request.get(), *soap_response.get()); int retstatus = soap_response->get_status(); if(retstatus != SOAP_OK) { const char* errmsg = "SOAP error"; if(retstatus == SOAP_CLIENT_ERROR) errmsg = "SOAP client error"; else if(retstatus == SOAP_SERVER_ERROR) errmsg = "SOAP server error"; else if(retstatus == SOAP_RPC_ERROR) errmsg = "SOAP rpc error"; else if(retstatus == SOAP_CONNECTION_ERROR) errmsg = "SOAP Connection error"; else if(retstatus == SOAP_REQUEST_TYPE_ERROR) errmsg = "SOAP request type error"; else if(retstatus == SOAP_AUTHENTICATION_ERROR) errmsg = "SOAP authentication error"; throw MakeStringException(retstatus, "%s", errmsg); } if(soap_response->get_text_length() == 0) { throw MakeStringException(-1, "Empty SOAP message received"); } StringBuffer& resptext = soap_response->query_text(); responsebuf.swapWith(resptext); return SOAP_OK; }