bool UNICOREClient::submit(const JobDescription& jobdesc, XMLNode& id, bool delegate) { std::string faultstring; logger.msg(INFO, "Creating and sending request"); // Create job request /* bes-factory:CreateActivity bes-factory:ActivityDocument jsdl:JobDefinition */ PayloadSOAP req(unicore_ns); XMLNode op = req.NewChild("bes-factory:CreateActivity"); XMLNode act_doc = op.NewChild("bes-factory:ActivityDocument"); set_bes_factory_action(req, "CreateActivity"); WSAHeader(req).To(rurl.str()); //XMLNode proxyHeader = req.Header().NewChild("u6:Proxy"); if (true) { std::string pem_str; std::ifstream proxy_file(proxyPath.c_str()/*, ifstream::in*/); std::getline<char>(proxy_file, pem_str, 0); req.Header().NewChild("u6:Proxy") = pem_str; //std::cout << "\n----\n" << "pem_str = " << pem_str << "\n----\n"; //debug code, remove! } //std::string jsdl_str; //std::getline<char>(jsdl_file, jsdl_str, 0); std::string jsdl_str; if (!jobdesc.UnParse(jsdl_str, "nordugrid:jsdl")) { logger.msg(INFO, "Unable to submit job. Job description is not valid in the %s format", "nordugrid:jsdl"); return false; } XMLNode jsdl_doc = act_doc.NewChild(XMLNode(jsdl_str)); //std::cout << "\n----\n" << jsdl_str << "\n----\n"; //Debug line to verify the activity document jsdl_doc.Namespaces(unicore_ns); // Unify namespaces PayloadSOAP *resp = NULL; XMLNode ds = act_doc["jsdl:JobDefinition"]["jsdl:JobDescription"]["jsdl:DataStaging"]; for (; (bool)ds; ds = ds[1]) { // FilesystemName - ignore // CreationFlag - ignore // DeleteOnTermination - ignore XMLNode source = ds["jsdl:Source"]; XMLNode target = ds["jsdl:Target"]; if ((bool)source) { std::string s_name = ds["jsdl:FileName"]; if (!s_name.empty()) { XMLNode x_url = source["jsdl:URI"]; std::string s_url = x_url; if (s_url.empty()) s_url = "./" + s_name; else { URL u_url(s_url); if (!u_url) { if (s_url[0] != '/') s_url = "./" + s_url; } else { if (u_url.Protocol() == "file") { s_url = u_url.Path(); if (s_url[0] != '/') s_url = "./" + s_url; } else s_url.resize(0); } } if (!s_url.empty()) x_url.Destroy(); } } } act_doc.GetXML(jsdl_str); logger.msg(DEBUG, "Job description to be sent: %s", jsdl_str); // Try to figure out which credentials are used // TODO: Method used is unstable beacuse it assumes some predefined // structure of configuration file. Maybe there should be some // special methods of ClientTCP class introduced. std::string deleg_cert; std::string deleg_key; if (delegate) { client->Load(); // Make sure chain is ready XMLNode tls_cfg = find_xml_node((client->GetConfig())["Chain"], "Component", "name", "tls.client"); if (tls_cfg) { deleg_cert = (std::string)(tls_cfg["ProxyPath"]); if (deleg_cert.empty()) { deleg_cert = (std::string)(tls_cfg["CertificatePath"]); deleg_key = (std::string)(tls_cfg["KeyPath"]); } else deleg_key = deleg_cert; } if (deleg_cert.empty() || deleg_key.empty()) { logger.msg(ERROR, "Failed to find delegation credentials in " "client configuration"); return false; } } // Send job request + delegation if (client) { if (delegate) { DelegationProviderSOAP deleg(deleg_cert, deleg_key); logger.msg(INFO, "Initiating delegation procedure"); if (!deleg.DelegateCredentialsInit(*(client->GetEntry()), &(client->GetContext()))) { logger.msg(ERROR, "Failed to initiate delegation"); return false; } deleg.DelegatedToken(op); } MCC_Status status = client->process("http://schemas.ggf.org/bes/2006/08/bes-factory/" "BESFactoryPortType/CreateActivity", &req, &resp); if (!status) { logger.msg(ERROR, "Submission request failed"); return false; } if (resp == NULL) { logger.msg(VERBOSE, "There was no SOAP response"); return false; } } else if (client_entry) { Message reqmsg; Message repmsg; MessageAttributes attributes_req; attributes_req.set("SOAP:ACTION", "http://schemas.ggf.org/bes/2006/08/" "bes-factory/BESFactoryPortType/CreateActivity"); MessageAttributes attributes_rep; MessageContext context; if (delegate) { DelegationProviderSOAP deleg(deleg_cert, deleg_key); logger.msg(INFO, "Initiating delegation procedure"); if (!deleg.DelegateCredentialsInit(*client_entry, &context)) { logger.msg(ERROR, "Failed to initiate delegation"); return false; } deleg.DelegatedToken(op); } reqmsg.Payload(&req); reqmsg.Attributes(&attributes_req); reqmsg.Context(&context); repmsg.Attributes(&attributes_rep); repmsg.Context(&context); MCC_Status status = client_entry->process(reqmsg, repmsg); if (!status) { logger.msg(ERROR, "Submission request failed"); return false; } logger.msg(INFO, "Submission request succeed"); if (repmsg.Payload() == NULL) { logger.msg(VERBOSE, "There was no response to a submission request"); return false; } try { resp = dynamic_cast<PayloadSOAP*>(repmsg.Payload()); } catch (std::exception&) {} if (resp == NULL) { logger.msg(ERROR, "A response to a submission request was not " "a SOAP message"); delete repmsg.Payload(); return false; } } else { logger.msg(ERROR, "There is no connection chain configured"); return false; } //XMLNode id; SOAPFault fs(*resp); if (!fs) { (*resp)["CreateActivityResponse"]["ActivityIdentifier"].New(id); //id.GetDoc(jobid); //std::cout << "\n---\nActivityIdentifier:\n" << (std::string)((*resp)["CreateActivityResponse"]["ActivityIdentifier"]) << "\n---\n";//debug code delete resp; UNICOREClient luc((std::string)id["Address"], client_config); //local unicore client //std::cout << "\n---\nid element containing (?) Job Address:\n" << (std::string)id << "\n---\n";//debug code return luc.uasStartJob(); //return true; } else { faultstring = fs.Reason(); std::string s; resp->GetXML(s); delete resp; logger.msg(DEBUG, "Submission returned failure: %s", s); logger.msg(ERROR, "Submission failed, service returned: %s", faultstring); return false; } }
bool UNICOREClient::kill(const std::string& jobid) { std::string result, faultstring; logger.msg(INFO, "Creating and sending request to terminate a job"); PayloadSOAP req(unicore_ns); XMLNode jobref = req.NewChild("bes-factory:TerminateActivities"). NewChild(XMLNode(jobid)); set_bes_factory_action(req, "TerminateActivities"); WSAHeader(req).To(rurl.str()); // Send kill request PayloadSOAP *resp = NULL; if (client) { MCC_Status status = client->process("http://schemas.ggf.org/bes/2006/08/bes-factory/" "BESFactoryPortType/TerminateActivities", &req, &resp); if (resp == NULL) { logger.msg(VERBOSE, "There was no SOAP response"); return false; } } else if (client_entry) { Message reqmsg; Message repmsg; MessageAttributes attributes_req; attributes_req.set("SOAP:ACTION", "http://schemas.ggf.org/bes/2006/08/" "bes-factory/BESFactoryPortType/TerminateActivities"); MessageAttributes attributes_rep; MessageContext context; reqmsg.Payload(&req); reqmsg.Attributes(&attributes_req); reqmsg.Context(&context); repmsg.Attributes(&attributes_rep); repmsg.Context(&context); MCC_Status status = client_entry->process(reqmsg, repmsg); if (!status) { logger.msg(ERROR, "A job termination request failed"); return false; } logger.msg(INFO, "A job termination request succeed"); if (repmsg.Payload() == NULL) { logger.msg(VERBOSE, "There was no response to a job termination request"); return false; } try { resp = dynamic_cast<PayloadSOAP*>(repmsg.Payload()); } catch (std::exception&) {} if (resp == NULL) { logger.msg(ERROR, "The response of a job termination request was " "not a SOAP message"); delete repmsg.Payload(); return false; } } else { logger.msg(ERROR, "There is no connection chain configured"); return false; } XMLNode cancelled, fs; (*resp)["TerminateActivitiesResponse"] ["Response"]["Cancelled"].New(cancelled); result = (std::string)cancelled; (*resp)["Fault"]["faultstring"].New(fs); faultstring = (std::string)fs; delete resp; if (faultstring != "") { logger.msg(ERROR, faultstring); return false; } if (result != "true") { logger.msg(ERROR, "Job termination failed"); return false; } return true; }
bool UNICOREClient::clean(const std::string& jobid) { std::string result, faultstring; logger.msg(INFO, "Creating and sending request to terminate a job"); PayloadSOAP req(unicore_ns); XMLNode op = req.NewChild("a-rex:ChangeActivityStatus"); XMLNode jobref = op.NewChild(XMLNode(jobid)); XMLNode jobstate = op.NewChild("a-rex:NewStatus"); jobstate.NewAttribute("bes-factory:state") = "Finished"; jobstate.NewChild("a-rex:state") = "Deleted"; // Send clean request PayloadSOAP *resp = NULL; if (client) { MCC_Status status = client->process("", &req, &resp); if (resp == NULL) { logger.msg(VERBOSE, "There was no SOAP response"); return false; } } else if (client_entry) { Message reqmsg; Message repmsg; MessageAttributes attributes_req; MessageAttributes attributes_rep; MessageContext context; reqmsg.Payload(&req); reqmsg.Attributes(&attributes_req); reqmsg.Context(&context); repmsg.Attributes(&attributes_rep); repmsg.Context(&context); MCC_Status status = client_entry->process(reqmsg, repmsg); if (!status) { logger.msg(ERROR, "A job cleaning request failed"); return false; } logger.msg(INFO, "A job cleaning request succeed"); if (repmsg.Payload() == NULL) { logger.msg(VERBOSE, "There was no response to a job cleaning request"); return false; } try { resp = dynamic_cast<PayloadSOAP*>(repmsg.Payload()); } catch (std::exception&) {} if (resp == NULL) { logger.msg(ERROR, "The response of a job cleaning request was not " "a SOAP message"); delete repmsg.Payload(); return false; } } else { logger.msg(ERROR, "There is no connection chain configured"); return false; } if (!((*resp)["ChangeActivityStatusResponse"])) { delete resp; XMLNode fs; (*resp)["Fault"]["faultstring"].New(fs); faultstring = (std::string)fs; if (faultstring != "") { logger.msg(ERROR, faultstring); return false; } if (result != "true") { logger.msg(ERROR, "Job termination failed"); return false; } } delete resp; return true; }
bool UNICOREClient::sstat(std::string& status) { std::string state, faultstring; logger.msg(INFO, "Creating and sending a service status request"); PayloadSOAP req(unicore_ns); XMLNode jobref = req.NewChild("bes-factory:GetFactoryAttributesDocument"); set_bes_factory_action(req, "GetFactoryAttributesDocument"); WSAHeader(req).To(rurl.str()); // Send status request PayloadSOAP *resp = NULL; if (client) { MCC_Status status = client->process("http://schemas.ggf.org/bes/2006/08/bes-factory/" "BESFactoryPortType/GetFactoryAttributesDocument", &req, &resp); if (resp == NULL) { logger.msg(VERBOSE, "There was no SOAP response"); return false; } } else if (client_entry) { Message reqmsg; Message repmsg; MessageAttributes attributes_req; attributes_req.set("SOAP:ACTION", "http://schemas.ggf.org/bes/2006/08/" "bes-factory/BESFactoryPortType/" "GetFactoryAttributesDocument"); MessageAttributes attributes_rep; MessageContext context; reqmsg.Payload(&req); reqmsg.Attributes(&attributes_req); reqmsg.Context(&context); repmsg.Attributes(&attributes_rep); repmsg.Context(&context); MCC_Status status = client_entry->process(reqmsg, repmsg); if (!status) { logger.msg(ERROR, "A service status request failed"); return false; } logger.msg(INFO, "A service status request succeeded"); if (repmsg.Payload() == NULL) { logger.msg(VERBOSE, "There was no response to a service status request"); return false; } try { resp = dynamic_cast<PayloadSOAP*>(repmsg.Payload()); } catch (std::exception&) {} if (resp == NULL) { logger.msg(ERROR, "The response of a service status request was " "not a SOAP message"); delete repmsg.Payload(); return false; } } else { logger.msg(ERROR, "There is no connection chain configured"); return false; } XMLNode st; logger.msg(DEBUG, "Response:\n%s", (std::string)(*resp)); (*resp)["GetFactoryAttributesDocumentResponse"] ["FactoryResourceAttributesDocument"].New(st); st.GetDoc(state, true); delete resp; if (state == "") { logger.msg(ERROR, "The service status could not be retrieved"); return false; } else { status = state; return true; } }
bool UNICOREClient::stat(const std::string& jobid, std::string& status) { std::string state, substate, faultstring; logger.msg(INFO, "Creating and sending a status request"); PayloadSOAP req(unicore_ns); XMLNode jobref = req.NewChild("bes-factory:GetActivityStatuses"). NewChild(XMLNode(jobid)); set_bes_factory_action(req, "GetActivityStatuses"); WSAHeader(req).To(rurl.str()); // Send status request PayloadSOAP *resp = NULL; if (client) { MCC_Status status = client->process("http://schemas.ggf.org/bes/2006/08/bes-factory/" "BESFactoryPortType/GetActivityStatuses", &req, &resp); if (resp == NULL) { logger.msg(VERBOSE, "There was no SOAP response"); return false; } } else if (client_entry) { Message reqmsg; Message repmsg; MessageAttributes attributes_req; attributes_req.set("SOAP:ACTION", "http://schemas.ggf.org/bes/2006/08/" "bes-factory/BESFactoryPortType/GetActivityStatuses"); MessageAttributes attributes_rep; MessageContext context; reqmsg.Payload(&req); reqmsg.Attributes(&attributes_req); reqmsg.Context(&context); repmsg.Attributes(&attributes_rep); repmsg.Context(&context); MCC_Status status = client_entry->process(reqmsg, repmsg); if (!status) { logger.msg(ERROR, "A status request failed"); return false; } logger.msg(INFO, "A status request succeed"); if (repmsg.Payload() == NULL) { logger.msg(VERBOSE, "There was no response to a status request"); return false; } try { resp = dynamic_cast<PayloadSOAP*>(repmsg.Payload()); } catch (std::exception&) {} if (resp == NULL) { logger.msg(ERROR, "The response of a status request was not a SOAP message"); delete repmsg.Payload(); return false; } } else { logger.msg(ERROR, "There is no connection chain configured"); return false; } XMLNode st, fs; (*resp)["GetActivityStatusesResponse"]["Response"] ["ActivityStatus"].New(st); state = (std::string)st.Attribute("state"); XMLNode sst; (*resp)["GetActivityStatusesResponse"]["Response"] ["ActivityStatus"]["state"].New(sst); substate = (std::string)sst; (*resp)["Fault"]["faultstring"].New(fs); faultstring = (std::string)fs; delete resp; if (faultstring != "") { logger.msg(ERROR, faultstring); return false; } else if (state == "") { logger.msg(ERROR, "The job status could not be retrieved"); return false; } else { status = state + "/" + substate; return true; } }
bool UNICOREClient::uasStartJob(){ std::string state, faultstring; logger.msg(INFO, "Creating and sending a start job request"); PayloadSOAP req(unicore_ns); XMLNode SOAPMethod = req.NewChild("jms:Start"); WSAHeader(req).To(rurl.str()); WSAHeader(req).Action("http://schemas.ggf.org/bes/2006/08/bes-activity/BESActivityPortType/StartRequest"); // Send status request PayloadSOAP *resp = NULL; if (client) { MCC_Status status = client->process("http://schemas.ggf.org/bes/2006/08/bes-activity/BESActivityPortType/StartRequest", &req, &resp); if (resp == NULL) { logger.msg(VERBOSE, "There was no SOAP response"); return false; } } else if (client_entry) { Message reqmsg; Message repmsg; MessageAttributes attributes_req; attributes_req.set("SOAP:ACTION", "http://schemas.ggf.org/bes/2006/08/bes-activity/BESActivityPortType/StartRequest"); MessageAttributes attributes_rep; MessageContext context; reqmsg.Payload(&req); reqmsg.Attributes(&attributes_req); reqmsg.Context(&context); repmsg.Attributes(&attributes_rep); repmsg.Context(&context); MCC_Status status = client_entry->process(reqmsg, repmsg); if (!status) { logger.msg(ERROR, "A start job request failed"); return false; } logger.msg(INFO, "A start job request succeeded"); if (repmsg.Payload() == NULL) { logger.msg(VERBOSE, "There was no response to a start job request"); return false; } try { resp = dynamic_cast<PayloadSOAP*>(repmsg.Payload()); } catch (std::exception&) {} if (resp == NULL) { logger.msg(ERROR, "The response of a start job request was " "not a SOAP message"); delete repmsg.Payload(); return false; } } else { logger.msg(ERROR, "There is no connection chain configured"); return false; } SOAPFault fs(*resp); if (!fs) { return true; } else { faultstring = fs.Reason(); std::string s; resp->GetXML(s); delete resp; logger.msg(DEBUG, "Submission returned failure: %s", s); logger.msg(ERROR, "Submission failed, service returned: %s", faultstring); return false; } }
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); }