Пример #1
0
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);
}