123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #pragma warning( disable : 4786)
- #include "esphttp.hpp"
- #include <stdlib.h>
- //ESP Bindings
- #include "espcontext.hpp"
- #include "http/client/httpclient.hpp"
- #include "SOAP/client/soapclient.hpp"
- #include "bindutil.hpp"
- #include <memory>
- 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<CEnvelope> req_envelope;
- req_envelope.setown(new CEnvelope(req_header, req_body));
- Owned<CMimeMultiPart> 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());
- }
- Owned<CSoapRequest> 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<CSoapResponse> soap_response;
- soap_response.setown(new CSoapResponse);
- //Send request and get response
- if(m_transportclient.get() == NULL)
- {
- Owned<IHttpClientContext> httpctx = getHttpClientContext();
- Owned<IHttpClient> httpclient = httpctx->createHttpClient(call->getProxy(), call->get_url());
- 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());
- }
- if (m_connectTimeoutMs)
- httpclient->setConnectTimeOutMs(m_connectTimeoutMs);
- if (m_readTimeoutSecs)
- httpclient->setTimeOut(m_readTimeoutSecs);
- m_transportclient.setown(httpclient.getClear());
- }
- if (!soap_request.get() || !soap_response.get())
- throw MakeStringException(-1, "request or response is NULL");
- 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)
- {
- if (retstatus == SOAP_SERVER_ERROR) //check for special case of VERY ugly soapfault string
- {
- const char *faultString = strstr(errText, "string=[");
- if (faultString)
- {
- faultString += 8;
- const char *endString = strchr(faultString, ']');
- if (endString)
- {
- errmsg.clear().append(endString-faultString, faultString);
- errText = nullptr;
- }
- }
- }
- if (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<CMimeMultiPart> 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());
- std::unique_ptr<XmlPullParser> xpp(new XmlPullParser());
- int bufSize = responsebuf.length();
- xpp->setSupportNamespaces(true);
- xpp->setInput(responsebuf.str(), bufSize);
- int type;
- StartTag stag;
- EndTag etag;
- Owned<CEnvelope> 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<CEnvelope> req_envelope;
- req_envelope.setown(new CEnvelope(req_header, req_body));
- Owned<CMimeMultiPart> 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<CSoapRequest> 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<CSoapResponse> soap_response = new CSoapResponse();
- //Send request and get response
- if(m_transportclient.get() == NULL)
- {
- Owned<IHttpClientContext> 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());
- }
- }
- if (!soap_request.get() || !soap_response.get())
- throw MakeStringException(-1, "request or response is NULL");
- 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;
- }
|