2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Protocols / SoapHttpClientProtocol.cs
index 79abb369cf464af26e8936615895ed464ab45783..143432a50207121a1ecfd279bc44f86b28837f2a 100644 (file)
@@ -9,6 +9,27 @@
 // Copyright (C) Tim Coleman, 2002\r
 // Copyright (C) Ximian, Inc, 2003\r
 //\r
+
+//
+// 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.
+//
 \r
 using System.IO;\r
 using System.Net;\r
@@ -20,79 +41,33 @@ using System.Web.Services;
 using System.Diagnostics;\r
 using System.Runtime.CompilerServices;\r
 using System.Web.Services.Description;\r
+using System.Web.Services.Discovery;\r
 using System.Xml.Serialization;\r
 using System.Xml.Schema;\r
 using System.Collections;\r
 using System.Threading;\r
 \r
-namespace System.Web.Services.Protocols {\r
-       public class SoapHttpClientProtocol : HttpWebClientProtocol {\r
+namespace System.Web.Services.Protocols \r
+{\r
+       public class SoapHttpClientProtocol : HttpWebClientProtocol \r
+       {\r
                SoapTypeStubInfo type_info;\r
+#if NET_2_0\r
+               WsiClaims conformanceClaims;\r
+               SoapProtocolVersion soapVersion;\r
+#endif\r
 \r
-               #region AsyncInfo class\r
+               #region SoapWebClientAsyncResult class\r
 \r
-               internal class AsyncInfo: IAsyncResult\r
+               internal class SoapWebClientAsyncResult: WebClientAsyncResult\r
                {\r
-                       bool _completedSynchronously;\r
-                       bool _done;\r
-                       ManualResetEvent _waitHandle;\r
-\r
-                       public object AsyncState \r
-                       {\r
-                               get { return InternalAsyncState; }\r
-                       }\r
-\r
-                       public WaitHandle AsyncWaitHandle \r
-                       {\r
-                               get\r
-                               {\r
-                                       lock (this) {\r
-                                               if (_waitHandle != null) return _waitHandle;\r
-                                               _waitHandle = new ManualResetEvent (_done);\r
-                                               return _waitHandle;\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       public bool CompletedSynchronously \r
+                       public SoapWebClientAsyncResult (WebRequest request, AsyncCallback callback, object asyncState)\r
+                       : base (request, callback, asyncState)\r
                        {\r
-                               get { return _completedSynchronously; }\r
-                       }\r
-\r
-                       public bool IsCompleted \r
-                       {\r
-                               get { lock (this) { return _done; } }\r
-                       }\r
-\r
-                       internal void SetCompleted (object[] result, Exception exception, bool async)\r
-                       {\r
-                               lock (this)\r
-                               {\r
-                                       Exception = exception;\r
-                                       Result = result;\r
-                                       _done = true;\r
-                                       _completedSynchronously = async;\r
-                                       if (_waitHandle != null) _waitHandle.Set ();\r
-                                       Monitor.PulseAll (this);\r
-                               }\r
-                               if (Callback != null) Callback (this);\r
-                       }\r
-\r
-                       internal void WaitForComplete ()\r
-                       {\r
-                               lock (this)\r
-                               {\r
-                                       Monitor.Wait (this);\r
-                               }\r
                        }\r
-\r
-                       internal object InternalAsyncState;\r
-                       internal AsyncCallback Callback;\r
-                       internal SoapClientMessage Message;\r
-                       internal SoapExtension[] Extensions;\r
-                       internal WebRequest Request;\r
-                       internal object[] Result;\r
-                       internal Exception Exception;\r
+               \r
+                       public SoapClientMessage Message;\r
+                       public SoapExtension[] Extensions;\r
                }\r
                #endregion\r
 \r
@@ -100,7 +75,7 @@ namespace System.Web.Services.Protocols {
 \r
                public SoapHttpClientProtocol () \r
                {\r
-                       type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), typeof(SoapTypeStubInfo));\r
+                       type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), "Soap");\r
                }\r
 \r
                #endregion // Constructors\r
@@ -109,23 +84,26 @@ namespace System.Web.Services.Protocols {
 \r
                protected IAsyncResult BeginInvoke (string methodName, object[] parameters, AsyncCallback callback, object asyncState)\r
                {\r
-                       AsyncInfo ainfo = new AsyncInfo ();\r
-\r
                        SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (methodName);\r
-                       ainfo.Message = new SoapClientMessage (this, msi, Url, parameters);\r
-                       ainfo.Message.CollectHeaders (this, ainfo.Message.MethodStubInfo.Headers, SoapHeaderDirection.In);\r
-                       ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);\r
-                       ainfo.InternalAsyncState = asyncState;\r
-                       ainfo.Callback = callback;\r
 \r
+                       SoapWebClientAsyncResult ainfo = null;\r
                        try\r
                        {\r
-                               ainfo.Request = GetRequestForMessage (uri, ainfo.Message);\r
+                               SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);\r
+                               message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);\r
+                               \r
+                               WebRequest request = GetRequestForMessage (uri, message);\r
+                               \r
+                               ainfo = new SoapWebClientAsyncResult (request, callback, asyncState);\r
+                               ainfo.Message = message;\r
+                               ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);\r
+\r
                                ainfo.Request.BeginGetRequestStream (new AsyncCallback (AsyncGetRequestStreamDone), ainfo);\r
                        }\r
                        catch (Exception ex)\r
                        {\r
-                               ainfo.SetCompleted (null, ex, false);\r
+                               if (ainfo != null)\r
+                                       ainfo.SetCompleted (null, ex, false);\r
                        }\r
 \r
                        return ainfo;\r
@@ -133,11 +111,10 @@ namespace System.Web.Services.Protocols {
 \r
                void AsyncGetRequestStreamDone (IAsyncResult ar)\r
                {\r
-                       AsyncInfo ainfo = (AsyncInfo) ar.AsyncState;\r
+                       SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;\r
                        try\r
                        {\r
                                SendRequest (ainfo.Request.EndGetRequestStream (ar), ainfo.Message, ainfo.Extensions);\r
-\r
                                ainfo.Request.BeginGetResponse (new AsyncCallback (AsyncGetResponseDone), ainfo);\r
                        }\r
                        catch (Exception ex)\r
@@ -148,7 +125,7 @@ namespace System.Web.Services.Protocols {
 \r
                void AsyncGetResponseDone (IAsyncResult ar)\r
                {\r
-                       AsyncInfo ainfo = (AsyncInfo) ar.AsyncState;\r
+                       SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;\r
                        WebResponse response = null;\r
 \r
                        try {\r
@@ -178,21 +155,35 @@ namespace System.Web.Services.Protocols {
 \r
                protected object[] EndInvoke (IAsyncResult asyncResult)\r
                {\r
-                       if (!(asyncResult is AsyncInfo)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");\r
+                       if (!(asyncResult is SoapWebClientAsyncResult)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");\r
 \r
-                       AsyncInfo ainfo = (AsyncInfo) asyncResult;\r
+                       SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) asyncResult;\r
                        lock (ainfo)\r
                        {\r
                                if (!ainfo.IsCompleted) ainfo.WaitForComplete ();\r
                                if (ainfo.Exception != null) throw ainfo.Exception;\r
-                               else return ainfo.Result;\r
+                               else return (object[]) ainfo.Result;\r
                        }\r
                }\r
 \r
-               [MonoTODO]\r
                public void Discover ()\r
                {\r
-                       throw new NotImplementedException ();\r
+                       BindingInfo bnd = (BindingInfo) type_info.Bindings [0];\r
+                       \r
+                       DiscoveryClientProtocol discoverer = new DiscoveryClientProtocol ();\r
+                       discoverer.Discover (Url);\r
+                       \r
+                       foreach (object info in discoverer.AdditionalInformation)\r
+                       {\r
+                               System.Web.Services.Discovery.SoapBinding sb = info as System.Web.Services.Discovery.SoapBinding;\r
+                               if (sb != null && sb.Binding.Name == bnd.Name && sb.Binding.Namespace == bnd.Namespace) {\r
+                                       Url = sb.Address;\r
+                                       return;\r
+                               }\r
+                       }\r
+                       \r
+                       string msg = string.Format ("The binding named '{0}' from namespace '{1}' was not found in the discovery document at '{2}'", bnd.Name, bnd.Namespace, Url);\r
+                       throw new Exception (msg);\r
                }\r
 \r
                protected override WebRequest GetWebRequest (Uri uri)\r
@@ -200,25 +191,12 @@ namespace System.Web.Services.Protocols {
                        return base.GetWebRequest (uri);\r
                }\r
 \r
-               //\r
-               // Just for debugging\r
-               //\r
-               void DumpStackFrames ()\r
-               {\r
-                       StackTrace st = new StackTrace ();\r
-\r
-                       for (int i = 0; i < st.FrameCount; i++){\r
-                               StackFrame sf = st.GetFrame (i);\r
-                               Console.WriteLine ("At frame: {0} {1}", i, sf.GetMethod ().Name);\r
-                       }\r
-               }\r
-\r
                WebRequest GetRequestForMessage (Uri uri, SoapClientMessage message)\r
                {\r
                        WebRequest request = GetWebRequest (uri);\r
                        request.Method = "POST";\r
                        WebHeaderCollection headers = request.Headers;\r
-                       headers.Add ("SOAPAction", message.Action);\r
+                       headers.Add ("SOAPAction", "\"" + message.Action + "\"");\r
                        request.ContentType = message.ContentType + "; charset=utf-8";\r
                        return request;\r
                }\r
@@ -233,11 +211,9 @@ namespace System.Web.Services.Protocols {
                                        SoapExtension.ExecuteProcessMessage (extensions, message, true);
                                }
 \r
-                               // What a waste of UTF8encoders, but it has to be thread safe.\r
-                               XmlTextWriter xtw = new XmlTextWriter (s, new UTF8Encoding (false));\r
-                               xtw.Formatting = Formatting.Indented;\r
-\r
-                               WebServiceHelper.WriteSoapMessage (xtw, type_info, message.MethodStubInfo.RequestSerializer, message.Parameters, message.Headers);\r
+                               XmlTextWriter xtw = WebServiceHelper.CreateXmlWriter (s);\r
+                               \r
+                               WebServiceHelper.WriteSoapMessage (xtw, type_info, message.MethodStubInfo.Use, message.MethodStubInfo.RequestSerializer, message.Parameters, message.Headers);\r
 \r
                                if (extensions != null) {\r
                                        message.SetStage (SoapMessageStage.AfterSerialize);\r
@@ -256,18 +232,36 @@ namespace System.Web.Services.Protocols {
                //    \r
                object [] ReceiveResponse (WebResponse response, SoapClientMessage message, SoapExtension[] extensions)\r
                {\r
-                       HttpWebResponse http_response = (HttpWebResponse) response;\r
-                       HttpStatusCode code = http_response.StatusCode;\r
                        SoapMethodStubInfo msi = message.MethodStubInfo;\r
-\r
-                       if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError))\r
-                               throw new Exception ("Return code was: " + http_response.StatusCode);\r
-\r
+                       HttpWebResponse http_response = response as HttpWebResponse;\r
+                       \r
+                       if (http_response != null)\r
+                       {\r
+                               HttpStatusCode code = http_response.StatusCode;\r
+       \r
+                               if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError)) {\r
+                                       string msg = "The request failed with HTTP status {0}: {1}";\r
+                                       msg = String.Format (msg, (int) code, code);\r
+                                       throw new WebException (msg, null, WebExceptionStatus.ProtocolError, http_response);\r
+                               }\r
+                               if (response.ContentLength == 0 && (code == HttpStatusCode.Accepted || code == HttpStatusCode.OK)) {\r
+                                       return new object[0];\r
+                               }\r
+                       }\r
+                       \r
                        //\r
                        // Remove optional encoding\r
                        //\r
-                       Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType);\r
-\r
+                       string ctype;
+                       Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType, out ctype);\r
+                       if (ctype != "text/xml")
+                               WebServiceHelper.InvalidOperation (
+                                       "Content is not 'text/xml' but '" + response.ContentType + "'",
+                                       response, encoding);
+\r
+                       message.ContentType = ctype;\r
+                       message.ContentEncoding = encoding.WebName;\r
+                       \r
                        Stream stream = response.GetResponseStream ();\r
 \r
                        if (extensions != null) {\r
@@ -278,24 +272,26 @@ namespace System.Web.Services.Protocols {
                        \r
                        // Deserialize the response\r
 \r
-                       StreamReader reader = new StreamReader (stream, encoding, false);\r
-                       XmlTextReader xml_reader = new XmlTextReader (reader);\r
-\r
-                       bool isSuccessful = (code != HttpStatusCode.InternalServerError);\r
                        SoapHeaderCollection headers;\r
                        object content;\r
 \r
-                       if (isSuccessful) {\r
-                               WebServiceHelper.ReadSoapMessage (xml_reader, type_info, msi.ResponseSerializer, out content, out headers);\r
-                               message.OutParameters = (object[]) content;\r
-                       }\r
-                       else {\r
-                               WebServiceHelper.ReadSoapMessage (xml_reader, type_info, type_info.FaultSerializer, out content, out headers);\r
+                       using (StreamReader reader = new StreamReader (stream, encoding, false)) {
+                               XmlTextReader xml_reader = new XmlTextReader (reader);
+
+                               WebServiceHelper.ReadSoapMessage (xml_reader, type_info, msi.Use, msi.ResponseSerializer,
+                                                               out content, out headers);
+                       }
+
+                       \r
+                       if (content is Fault)\r
+                       {\r
                                Fault fault = (Fault) content;\r
                                SoapException ex = new SoapException (fault.faultstring, fault.faultcode, fault.faultactor, fault.detail);\r
                                message.SetException (ex);\r
                        }\r
-\r
+                       else\r
+                               message.OutParameters = (object[]) content;\r
+                       \r
                        message.SetHeaders (headers);\r
                        message.UpdateHeaderValues (this, message.MethodStubInfo.Headers);\r
 \r
@@ -304,7 +300,7 @@ namespace System.Web.Services.Protocols {
                                SoapExtension.ExecuteProcessMessage (extensions, message, false);
                        }
 \r
-                       if (isSuccessful)\r
+                       if (message.Exception == null)\r
                                return message.OutParameters;\r
                        else\r
                                throw message.Exception;\r
@@ -336,7 +332,49 @@ namespace System.Web.Services.Protocols {
 \r
                        return ReceiveResponse (response, message, extensions);\r
                }\r
+               \r
+#if NET_2_0\r
+\r
+               [MonoTODO ("Do something with this")]\r
+               [System.Runtime.InteropServices.ComVisible(false)]\r
+               [Obsolete]\r
+               public WsiClaims ConformanceClaims {\r
+                       get { return conformanceClaims; }\r
+                       set { conformanceClaims = value; }\r
+               }\r
+               \r
+               [MonoTODO ("Do something with this")]\r
+               [System.Runtime.InteropServices.ComVisible(false)]\r
+               public SoapProtocolVersion SoapVersion {\r
+                       get { return soapVersion; }\r
+                       set { soapVersion = value; }\r
+               }\r
+               \r
+               protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback)\r
+               {\r
+                       InvokeAsync (methodName, parameters, callback, null);\r
+               }\r
+\r
+               protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback, object userState)\r
+               {\r
+                       InvokeAsyncInfo info = new InvokeAsyncInfo (callback, userState);\r
+                       BeginInvoke (methodName, parameters, new AsyncCallback (InvokeAsyncCallback), info);\r
+               }\r
+               \r
+               void InvokeAsyncCallback (IAsyncResult ar)\r
+               {\r
+                       InvokeAsyncInfo info = (InvokeAsyncInfo) ar.AsyncState;\r
+                       SoapWebClientAsyncResult sar = (SoapWebClientAsyncResult) ar;\r
+                       InvokeCompletedEventArgs args = new InvokeCompletedEventArgs (sar.Exception, false, info.UserState, (object[]) sar.Result);\r
+                       if (info.Context != null)\r
+                               info.Context.SendOrPost (info.Callback, args);\r
+                       else\r
+                               info.Callback (args);\r
+               }\r
+\r
+#endif\r
 \r
                #endregion // Methods\r
        }\r
 }
+\r