X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web.Services%2FSystem.Web.Services.Protocols%2FWebServiceHelper.cs;h=1861fd6b594697d693c1daf2db0220607edc0f86;hb=a57c3b9782ca02e4f060ac37dac5b2a20f16772a;hp=5887d2fcbd4a16429bedb6ce7079b91a87a360b8;hpb=3f5448730cfbefebe08e550a98d97a69c353fbdc;p=mono.git diff --git a/mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHelper.cs b/mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHelper.cs old mode 100755 new mode 100644 index 5887d2fcbd4..1861fd6b594 --- a/mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHelper.cs +++ b/mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHelper.cs @@ -7,29 +7,79 @@ // Copyright (C) Ximian, Inc. 2003 // +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + using System; +using System.IO; +using System.Net; using System.Text; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; +using System.Web.Services.Description; namespace System.Web.Services.Protocols { internal class WebServiceHelper { public const string SoapEnvelopeNamespace = "http://schemas.xmlsoap.org/soap/envelope/"; - - public static Encoding GetContentEncoding (string cts) + public const string Soap12EnvelopeNamespace = "http://www.w3.org/2003/05/soap-envelope"; + public const string SoapEncodingNamespace = "http://schemas.xmlsoap.org/soap/encoding/"; + public const string Soap12EncodingNamespace = "http://www.w3.org/2003/05/soap-encoding"; + static readonly char [] trimChars = { '"', '\'' }; + static readonly bool prettyXml; + + static WebServiceHelper () + { + string pxml = Environment.GetEnvironmentVariable ("MONO_WEBSERVICES_PRETTYXML"); + prettyXml = (pxml != null && pxml != "no"); + } + + public static XmlTextWriter CreateXmlWriter (Stream s) + { + // What a waste of UTF8encoders, but it has to be thread safe. + XmlTextWriter xtw = new XmlTextWriter (s, new UTF8Encoding (false)); + + if (prettyXml) + xtw.Formatting = Formatting.Indented; + + return xtw; + } + + public static Encoding GetContentEncoding (string cts, out string content_type) { string encoding; - string content_type; + if (cts == null) cts = ""; + encoding = "utf-8"; int start = 0; int idx = cts.IndexOf (';'); if (idx == -1) - encoding = cts; - content_type = cts.Substring (0, idx); + content_type = cts; + else + content_type = cts.Substring (0, idx); + + content_type = content_type.Trim (); for (start = idx + 1; idx != -1;) { idx = cts.IndexOf (";", start); @@ -38,42 +88,56 @@ namespace System.Web.Services.Protocols body = cts.Substring (start); else { - body = cts.Substring (start, idx); + body = cts.Substring (start, idx - start); start = idx + 1; } + body = body.Trim (); if (body.StartsWith ("charset=")) { encoding = body.Substring (8); + encoding = encoding.TrimStart (trimChars).TrimEnd (trimChars); } } - if (content_type != "text/xml") - throw new Exception ("Content is not XML: " + content_type); - return Encoding.GetEncoding (encoding); } - public static void WriteSoapMessage (XmlTextWriter xtw, TypeStubInfo info, XmlSerializer bodySerializer, object bodyContent, SoapHeaderCollection headers) + public static void WriteSoapMessage (XmlTextWriter xtw, SoapMethodStubInfo method, SoapHeaderDirection dir, object bodyContent, SoapHeaderCollection headers, bool soap12) { + SoapBindingUse methodUse = dir == SoapHeaderDirection.Fault ? SoapBindingUse.Literal : method.Use; + XmlSerializer bodySerializer = method.GetBodySerializer (dir, soap12); + XmlSerializer headerSerializer = method.GetHeaderSerializer (dir); + object[] headerArray = method.GetHeaderValueArray (dir, headers); + WriteSoapMessage (xtw, methodUse, bodySerializer, headerSerializer, bodyContent, headerArray, soap12); + } + + public static void WriteSoapMessage (XmlTextWriter xtw, SoapBindingUse methodUse, XmlSerializer bodySerializer, XmlSerializer headerSerializer, object bodyContent, object[] headers, bool soap12) + { + string ns = soap12 ? + WebServiceHelper.Soap12EnvelopeNamespace : + WebServiceHelper.SoapEnvelopeNamespace; + string encNS = soap12 ? + WebServiceHelper.Soap12EncodingNamespace : + WebServiceHelper.SoapEncodingNamespace; xtw.WriteStartDocument (); - xtw.WriteStartElement ("soap", "Envelope", WebServiceHelper.SoapEnvelopeNamespace); + xtw.WriteStartElement ("soap", "Envelope", ns); xtw.WriteAttributeString ("xmlns", "xsi", null, XmlSchema.InstanceNamespace); xtw.WriteAttributeString ("xmlns", "xsd", null, XmlSchema.Namespace); // Serialize headers if (headers != null) { - foreach (SoapHeader header in headers) - { - XmlSerializer ser = info.GetHeaderSerializer (header.GetType()); - xtw.WriteStartElement ("soap", "Header", WebServiceHelper.SoapEnvelopeNamespace); - ser.Serialize (xtw, header); - xtw.WriteEndElement (); - } + xtw.WriteStartElement ("soap", "Header", ns); + headerSerializer.Serialize (xtw, headers); + xtw.WriteEndElement (); } // Serialize body - xtw.WriteStartElement ("soap", "Body", WebServiceHelper.SoapEnvelopeNamespace); + xtw.WriteStartElement ("soap", "Body", ns); + + if (methodUse == SoapBindingUse.Encoded) + xtw.WriteAttributeString ("encodingStyle", ns, encNS); + bodySerializer.Serialize (xtw, bodyContent); xtw.WriteEndElement (); @@ -81,47 +145,180 @@ namespace System.Web.Services.Protocols xtw.Flush (); } - public static void ReadSoapMessage (XmlTextReader xmlReader, TypeStubInfo typeStubInfo, XmlSerializer bodySerializer, out object body, out SoapHeaderCollection headers) + public static void ReadSoapMessage (XmlTextReader xmlReader, SoapMethodStubInfo method, SoapHeaderDirection dir, bool soap12, out object body, out SoapHeaderCollection headers) { - xmlReader.MoveToContent (); - xmlReader.ReadStartElement ("Envelope", WebServiceHelper.SoapEnvelopeNamespace); - - headers = ReadHeaders (typeStubInfo, xmlReader); - - xmlReader.MoveToContent (); - xmlReader.ReadStartElement ("Body", WebServiceHelper.SoapEnvelopeNamespace); - xmlReader.MoveToContent (); - - body = bodySerializer.Deserialize (xmlReader); + XmlSerializer bodySerializer = method.GetBodySerializer (dir, false);// no need to worry about soap12 arg since no call for Fault anyways here. + XmlSerializer headerSerializer = method.GetHeaderSerializer (dir); + ReadSoapMessage (xmlReader, bodySerializer, headerSerializer, soap12, out body, out headers); } + + public static void ReadSoapMessage (XmlTextReader xmlReader, XmlSerializer bodySerializer, XmlSerializer headerSerializer, bool soap12, out object body, out SoapHeaderCollection headers) + { + xmlReader.MoveToContent (); + string ns = xmlReader.NamespaceURI; + switch (ns) { +#if NET_2_0 + case WebServiceHelper.Soap12EnvelopeNamespace: +#endif + case WebServiceHelper.SoapEnvelopeNamespace: + break; + default: + throw new SoapException (String.Format ("SOAP version mismatch. Namespace '{0}' is not supported in this runtime profile.", ns), VersionMismatchFaultCode (soap12)); + } + xmlReader.ReadStartElement ("Envelope", ns); + + headers = ReadHeaders (xmlReader, headerSerializer, ns); + + xmlReader.MoveToContent (); + xmlReader.ReadStartElement ("Body", ns); + xmlReader.MoveToContent (); + + if (xmlReader.LocalName == "Fault" && xmlReader.NamespaceURI == ns) + bodySerializer = ns == Soap12EnvelopeNamespace ? Soap12Fault.Serializer : Fault.Serializer; - static SoapHeaderCollection ReadHeaders (TypeStubInfo typeStubInfo, XmlTextReader xmlReader) + body = bodySerializer.Deserialize (xmlReader); + } + + static SoapHeaderCollection ReadHeaders (XmlTextReader xmlReader, XmlSerializer headerSerializer, string ns) { - SoapHeaderCollection headers = new SoapHeaderCollection (); - while (! (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace)) + SoapHeaderCollection headers = null; + while (! (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == ns)) { - if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace) + if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" + && xmlReader.NamespaceURI == ns && !xmlReader.IsEmptyElement + && headerSerializer != null) { xmlReader.ReadStartElement (); xmlReader.MoveToContent (); - XmlQualifiedName qname = new XmlQualifiedName (xmlReader.LocalName, xmlReader.NamespaceURI); - XmlSerializer headerSerializer = typeStubInfo.GetHeaderSerializer (qname); - if (headerSerializer != null) - { - SoapHeader header = (SoapHeader) headerSerializer.Deserialize (xmlReader); - headers.Add (header); - } - else - { - while (xmlReader.NodeType == XmlNodeType.EndElement) - xmlReader.Skip (); // TODO: Check if the header has mustUnderstand=true + + HeaderSerializationHelper uh = new HeaderSerializationHelper (headerSerializer); + headers = uh.Deserialize (xmlReader); + + while (xmlReader.NodeType != XmlNodeType.EndElement) xmlReader.Skip (); - } + + xmlReader.ReadEndElement (); } else xmlReader.Skip (); } - return headers; + if (headers != null) + return headers; + else + return new SoapHeaderCollection (); + } + + class HeaderSerializationHelper + { + SoapHeaderCollection headers; + XmlSerializer headerSerializer; + + public HeaderSerializationHelper (XmlSerializer headerSerializer) + { + this.headers = new SoapHeaderCollection (); + this.headerSerializer = headerSerializer; + } + + public SoapHeaderCollection Deserialize (XmlTextReader xmlReader) + { + try { + headerSerializer.UnknownElement += new XmlElementEventHandler (OnAddUnknownHeader); + object[] headerArray = (object[]) headerSerializer.Deserialize (xmlReader); + foreach (SoapHeader h in headerArray) + if (h != null) headers.Add (h); + return headers; + } finally { + headerSerializer.UnknownElement -= new XmlElementEventHandler (OnAddUnknownHeader); + } + } + + void OnAddUnknownHeader (object sender, XmlElementEventArgs e) + { + headers.Add (new SoapUnknownHeader (e.Element)); + } + } + +#if NET_2_0 + public static SoapException Soap12FaultToSoapException (Soap12Fault fault) + { + Soap12FaultReasonText text = + fault.Reason != null && + fault.Reason.Texts != null && + fault.Reason.Texts.Length > 0 ? + fault.Reason.Texts [fault.Reason.Texts.Length - 1] : null; + XmlNode detail = (fault.Detail == null) ? null : + (fault.Detail.Children != null && + fault.Detail.Children.Length > 0) ? + (XmlNode) fault.Detail.Children [0] : + (fault.Detail.Attributes != null && + fault.Detail.Attributes.Length > 0) ? + fault.Detail.Attributes [0] : null; + SoapFaultSubCode subcode = Soap12Fault.GetSoapFaultSubCode (fault.Code.Subcode); + return new SoapException ( + text != null ? text.Value : null, + fault.Code.Value, null, fault.Role, + text != null ? text.XmlLang : null, + detail, subcode, null); + } +#endif + + public static XmlQualifiedName ClientFaultCode (bool soap12) + { +#if NET_2_0 + return soap12 ? Soap12FaultCodes.SenderFaultCode : SoapException.ClientFaultCode; +#else + return SoapException.ClientFaultCode; +#endif + } + + public static XmlQualifiedName ServerFaultCode (bool soap12) + { +#if NET_2_0 + return soap12 ? Soap12FaultCodes.ReceiverFaultCode : SoapException.ServerFaultCode; +#else + return SoapException.ServerFaultCode; +#endif + } + + public static XmlQualifiedName MustUnderstandFaultCode (bool soap12) + { +#if NET_2_0 + return soap12 ? Soap12FaultCodes.ReceiverFaultCode : SoapException.MustUnderstandFaultCode; +#else + return SoapException.MustUnderstandFaultCode; +#endif + } + + public static XmlQualifiedName VersionMismatchFaultCode (bool soap12) + { +#if NET_2_0 + return soap12 ? Soap12FaultCodes.VersionMismatchFaultCode : SoapException.VersionMismatchFaultCode; +#else + return SoapException.VersionMismatchFaultCode; +#endif + } + + public static void InvalidOperation (string message, WebResponse response, Encoding enc) + { + if (response == null) + throw new InvalidOperationException (message); + + if (enc == null) + enc = Encoding.UTF8; + + StringBuilder sb = new StringBuilder (); + sb.Append (message); + if (response.ContentLength > 0) { + sb.Append ("\r\nResponse error message:\r\n--\r\n"); + + try { + StreamReader resp = new StreamReader (response.GetResponseStream (), enc); + sb.Append (resp.ReadToEnd ()); + } catch (Exception) { + } + } + + throw new InvalidOperationException (sb.ToString ()); } } }