private void CheckSOAPHeaders(SoapMessage message) { // We want to check the following: // // - no SOAP Actor attribute exists // - no SOAP headers can have a must_understand attribute set to true // // Go through each header in our message // foreach (SoapHeader header in message.Headers) { if (header.MustUnderstand) { // // No headers can have this attribute set. // DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_SOAP_MUSTUNDERSTANDATT")); return; } if (header.Actor.Length > 0) { // // Can't have a SOAP Actor attribute set, generate a SOAP fault with // no detail element and a 'Client' fault code // DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_SOAP_ACTORATT")); return; } } }
// // TODO: see if there is a way to better modularize this method and rename it. // private void CheckForSingleRequest(Stream stream) { try { // // Move to the start of our stream // stream.Position = 0; XmlTextReader requestReader = new XmlTextReader(oldStream); requestReader.MoveToContent(); // // TODO: should not hard-code SOAP names and namespaces // // // Move to the beginning of the SOAP envelope // requestReader.ReadStartElement("Envelope", "http://schemas.xmlsoap.org/soap/envelope/"); // // Move to the SOAP body // while (!requestReader.IsStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/") && !requestReader.EOF) { requestReader.Skip(); } // // Advance the current node to the first child of Body. This is presumably the UDDI message // requestReader.ReadStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/"); requestReader.MoveToContent(); // // This element MUST have a UDDI namespace // string uddiNamespace = requestReader.LookupNamespace(requestReader.Prefix); switch (uddiNamespace) { case "urn:uddi-org:api": { Context.ApiVersionMajor = 1; break; } case "urn:uddi-org:api_v2": { Context.ApiVersionMajor = 2; break; } case "urn:uddi-microsoft-com:api_v2_extensions": { Context.ApiVersionMajor = 2; break; } case "urn:uddi-org:repl": { Context.ApiVersionMajor = 2; break; } default: { // // This is a problem, we don't have a UDDI namespace. Throw an exception and get out of here. The // exception will be caught in our outer catch and sent to our client using DispositionReport.ThrowFinal. // throw new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_MISSINGUDDINS"); } } // // Skip the children of this node // requestReader.Skip(); requestReader.MoveToContent(); // // Reset our stream so someone else can use it. // stream.Position = 0; // // If we are not at the end of the Body tag, then we have multiple requests, we should reject the message. // if (false == requestReader.LocalName.Equals("Body")) { DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_SOAP_MULTIPLEREQUEST")); } } catch (UDDIException uddiException) { DispositionReport.ThrowFinal(uddiException); } catch { // // We'll get this exception if the message contains any invalid elements // DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_SOAP_INVALIDELEMENT")); } }
public override void ProcessMessage(SoapMessage message) { try { switch (message.Stage) { case SoapMessageStage.BeforeDeserialize: // // Check to see if the server has been manually stopped. // if (0 == Config.GetInt("Run", 1)) { DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_busy, "UDDI_ERROR_BUSY_SERVICENOTAVAILABLE")); // // DispositionReport.ThrowFinal will close the HTTP stream so there is no point going on in this method // return; } try { // // Validate against the UDDI schemas // SchemaCollection.Validate(oldStream); } catch (Exception e) { DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_SCHEMAVALIDATIONFAILED", e.Message)); // // DispositionReport.ThrowFinal will close the HTTP stream so there is no point going on in this method // return; } // // Make sure we only have 1 UDDI request in the SOAP body. This method will also set the versionMajor // member. // CheckForSingleRequest(oldStream); // // If this is a v1 message, we'll first map it to the v2 // namespace so that it can be processed by the new // library. // if (1 == Context.ApiVersionMajor || 2 == Context.ApiVersionMajor) { TextReader reader = new StreamReader(oldStream); TextWriter writer = new StreamWriter(newStream, new System.Text.UTF8Encoding(false)); string xml = reader.ReadToEnd(); if (1 == Context.ApiVersionMajor) { xml = xml.Replace("=\"urn:uddi-org:api\"", "=\"urn:uddi-org:api_v2\""); xml = xml.Replace("='urn:uddi-org:api'", "=\"urn:uddi-org:api_v2\""); } writer.Write(xml); writer.Flush(); newStream.Position = 0; } break; case SoapMessageStage.AfterDeserialize: // // After the message is deserialized is the earliest place where we // have access to our SOAP headers. // CheckSOAPHeaders(message); // // Now that the message has been deserialized, make // sure that the generic and xmlns attributes agree. // IMessage obj = message.GetInParameterValue(0) as IMessage; if (null != obj) { // // We only need to do this if the deserialized object supports IMessage // string expected = Context.ApiVersionMajor + ".0"; string actual = obj.Generic.Trim(); if (expected != actual) { throw new UDDIException(ErrorType.E_unrecognizedVersion, "UDDI_ERROR_UNKNOWNVERSION_GENERICNAMESPACEMISMATCH"); } } break; case SoapMessageStage.BeforeSerialize: break; case SoapMessageStage.AfterSerialize: // // There may have been exceptions thrown during serialization. // if (null != message.Exception && (null == message.Exception.Detail || 0 == message.Exception.Detail.ChildNodes.Count)) { DispositionReport.ThrowFinal(new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_FAILEDDESERIALIZATION")); // // DispositionReport.ThrowFinal will close the HTTP stream so there is no point going on in this method // return; } // // If the original request was v1, then we'll need to // remap the output to use the v1 namespace. // if (1 == Context.ApiVersionMajor || 2 == Context.ApiVersionMajor) { newStream.Position = 0; TextReader reader = new StreamReader(newStream); TextWriter writer = new StreamWriter(oldStream, new System.Text.UTF8Encoding(false)); string xml = reader.ReadToEnd(); // // We don't have to use the same 'loose' replacement as we did on the incoming request // because our response will be serialized such that the default namespace is our UDDI // namespace. // if (1 == Context.ApiVersionMajor) { xml = xml.Replace("xmlns=\"urn:uddi-org:api_v2\"", "xmlns=\"urn:uddi-org:api\""); xml = xml.Replace("generic=\"2.0\"", "generic=\"1.0\""); } writer.Write(xml); writer.Flush(); } break; default: throw new UDDIException(ErrorType.E_fatalError, "UDDI_ERROR_FATALERROR_UNKNOWNEXTSTAGE"); } } catch (Exception e) { DispositionReport.Throw(e); } }