MCC_Status MCC_SOAP_Client::process(Message& inmsg,Message& outmsg) { // Extracting payload if(!inmsg.Payload()) return make_soap_fault(outmsg,true,"No message to send"); PayloadSOAP* inpayload = NULL; try { inpayload = dynamic_cast<PayloadSOAP*>(inmsg.Payload()); } catch(std::exception& e) { }; if(!inpayload) return make_soap_fault(outmsg,true,"No SOAP message to send"); //Checking authentication and authorization; if(!ProcessSecHandlers(inmsg,"outgoing")) { logger.msg(ERROR, "Security check failed in SOAP MCC for outgoing message"); return make_soap_fault(outmsg,true,"Security check failed for outgoing SOAP message"); }; // Converting payload to Raw PayloadRaw nextpayload; std::string xml; inpayload->GetXML(xml); nextpayload.Insert(xml.c_str()); // Creating message to pass to next MCC and setting new payload.. Message nextinmsg = inmsg; nextinmsg.Payload(&nextpayload); // Specifying attributes for binding to underlying protocols - HTTP so far std::string soap_action; bool soap_action_defined = inmsg.Attributes()->count("SOAP:ACTION") > 0; if(soap_action_defined) { soap_action=inmsg.Attributes()->get("SOAP:ACTION"); } else { soap_action_defined=true; //WSAHeader(*inpayload).hasAction(); - SOAPAction must be always present soap_action=WSAHeader(*inpayload).Action(); }; if(inpayload->Version() == SOAPEnvelope::Version_1_2) { std::string mime_type("application/soap+xml"); if(soap_action_defined) mime_type+=" ;action=\""+soap_action+"\""; nextinmsg.Attributes()->set("HTTP:Content-Type",mime_type); } else { nextinmsg.Attributes()->set("HTTP:Content-Type","text/xml"); if(soap_action_defined) nextinmsg.Attributes()->set("HTTP:SOAPAction","\""+soap_action+"\""); }; // Call next MCC MCCInterface* next = Next(); if(!next) return make_soap_fault(outmsg,true,"Internal chain failure: no next component"); Message nextoutmsg = outmsg; nextoutmsg.Payload(NULL); MCC_Status ret = next->process(nextinmsg,nextoutmsg); // Do checks and create SOAP response // TODO: pass SOAP action from HTTP header to SOAP:ACTION attribute if(!ret) { std::string errstr = "Failed to send SOAP message: "+(std::string)ret; return make_soap_fault(outmsg,nextoutmsg,false,errstr.c_str()); }; if(!nextoutmsg.Payload()) { return make_soap_fault(outmsg,nextoutmsg,false,"No response for SOAP message recieved"); }; MessagePayload* retpayload = nextoutmsg.Payload(); if(!retpayload) return make_soap_fault(outmsg,nextoutmsg,false,"No valid response for SOAP message recieved"); PayloadSOAP* outpayload = new PayloadSOAP(*retpayload); if(!outpayload) { return make_soap_fault(outmsg,nextoutmsg,false,"Response is not SOAP"); }; if(!(*outpayload)) { delete outpayload; return make_soap_fault(outmsg,nextoutmsg,false,"Response is not valid SOAP"); }; outmsg = nextoutmsg; outmsg.Payload(outpayload); delete nextoutmsg.Payload(); nextoutmsg.Payload(NULL); //Checking authentication and authorization; if(!ProcessSecHandlers(outmsg,"incoming")) { logger.msg(ERROR, "Security check failed in SOAP MCC for incoming message"); delete outpayload; return make_soap_fault(outmsg,false,"Security check failed for incoming SOAP message"); }; return MCC_Status(STATUS_OK); }
MCC_Status MCC_SOAP_Service::process(Message& inmsg,Message& outmsg) { // Extracting payload MessagePayload* inpayload = inmsg.Payload(); if(!inpayload) { logger.msg(WARNING, "empty input payload"); return make_raw_fault(outmsg,"Missing incoming request"); } // Converting payload to SOAP PayloadSOAP nextpayload(*inpayload); if(!nextpayload) { logger.msg(WARNING, "incoming message is not SOAP"); return make_raw_fault(outmsg,"Incoming request is not SOAP"); } // Creating message to pass to next MCC and setting new payload.. // Using separate message. But could also use same inmsg. // Just trying to keep it intact as much as possible. Message nextinmsg = inmsg; nextinmsg.Payload(&nextpayload); if(WSAHeader::Check(nextpayload)) { std::string endpoint_attr = WSAHeader(nextpayload).To(); nextinmsg.Attributes()->set("SOAP:ENDPOINT",endpoint_attr); nextinmsg.Attributes()->set("ENDPOINT",endpoint_attr); }; SOAPSecAttr* sattr = new SOAPSecAttr(nextpayload); nextinmsg.Auth()->set("SOAP",sattr); // Checking authentication and authorization; if(!ProcessSecHandlers(nextinmsg,"incoming")) { logger.msg(ERROR, "Security check failed in SOAP MCC for incoming message"); return make_raw_fault(outmsg, "Security check failed for SOAP request"); }; // TODO: pass SOAP action from HTTP header to SOAP:ACTION attribute // Call next MCC MCCInterface* next = Next(); if(!next) { logger.msg(WARNING, "empty next chain element"); return make_raw_fault(outmsg,"Internal error"); } Message nextoutmsg = outmsg; nextoutmsg.Payload(NULL); MCC_Status ret = next->process(nextinmsg,nextoutmsg); // Do checks and extract SOAP response if(!ret) { if(nextoutmsg.Payload()) delete nextoutmsg.Payload(); logger.msg(WARNING, "next element of the chain returned error status: %s",(std::string)ret); if(ret.getKind() == UNKNOWN_SERVICE_ERROR) { return make_raw_fault(outmsg,"No requested service found"); } else { return make_raw_fault(outmsg,"Internal error"); } } if(!nextoutmsg.Payload()) { logger.msg(WARNING, "next element of the chain returned empty payload"); return make_raw_fault(outmsg,"There is no response"); } PayloadSOAP* retpayload = NULL; try { retpayload = dynamic_cast<PayloadSOAP*>(nextoutmsg.Payload()); } catch(std::exception& e) { }; if(!retpayload) { // There is a chance that next MCC decided to return pre-rendered SOAP // or otherwise valid non-SOAP response. For that case we simply pass // it back to previous MCC and let it decide. logger.msg(INFO, "next element of the chain returned unknown payload - passing through"); //Checking authentication and authorization; if(!ProcessSecHandlers(nextoutmsg,"outgoing")) { logger.msg(ERROR, "Security check failed in SOAP MCC for outgoing message"); delete nextoutmsg.Payload(); return make_raw_fault(outmsg,"Security check failed for SOAP response"); }; outmsg = nextoutmsg; return MCC_Status(STATUS_OK); }; if(!(*retpayload)) { delete retpayload; return make_raw_fault(outmsg,"There is no valid SOAP response"); }; //Checking authentication and authorization; if(!ProcessSecHandlers(nextoutmsg,"outgoing")) { logger.msg(ERROR, "Security check failed in SOAP MCC for outgoing message"); delete retpayload; return make_raw_fault(outmsg,"Security check failed for SOAP response"); }; // Convert to Raw - TODO: more efficient conversion PayloadRaw* outpayload = new PayloadRaw; std::string xml; retpayload->GetXML(xml); outpayload->Insert(xml.c_str()); outmsg = nextoutmsg; outmsg.Payload(NULL); // Specifying attributes for binding to underlying protocols - HTTP so far std::string soap_action; bool soap_action_defined = nextoutmsg.Attributes()->count("SOAP:ACTION") > 0; if(soap_action_defined) { soap_action=nextoutmsg.Attributes()->get("SOAP:ACTION"); } else { soap_action_defined=WSAHeader(*retpayload).hasAction(); soap_action=WSAHeader(*retpayload).Action(); }; if(retpayload->Version() == SOAPEnvelope::Version_1_2) { // TODO: For SOAP 1.2 Content-Type is not sent in case of error - probably harmless std::string mime_type("application/soap+xml"); if(soap_action_defined) mime_type+=" ;action=\""+soap_action+"\""; outmsg.Attributes()->set("HTTP:Content-Type",mime_type); } else { outmsg.Attributes()->set("HTTP:Content-Type","text/xml"); if(soap_action_defined) outmsg.Attributes()->set("HTTP:SOAPAction",soap_action); }; if(retpayload->Fault() != NULL) { // Maybe MCC_Status should be used instead ? outmsg.Attributes()->set("HTTP:CODE","500"); // TODO: For SOAP 1.2 :Sender fault must generate 400 outmsg.Attributes()->set("HTTP:REASON","SOAP FAULT"); // CONFUSED: SOAP 1.2 says that SOAP message is sent in response only if // HTTP code is 200 "Only if status line is 200, the SOAP message serialized according // to the rules for carrying SOAP messages in the media type given by the Content-Type // header field ...". But it also associates SOAP faults with HTTP error codes. So it // looks like in case of SOAP fault SOAP fault messages is not sent. That sounds // stupid - not implementing. }; delete retpayload; outmsg.Payload(outpayload); return MCC_Status(STATUS_OK); }