Fix HttpHandler, HttpHandlerFactory and HttpServerChannel to work properly with a...
[mono.git] / mcs / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Http / HttpClientChannel.cs
index de690e721cc174d29bec75c0798b4f66e68d6fb3..e92b059b435b8b9422ea9ea54fae9aa88efa52dc 100644 (file)
 // (C) 2003 Martin Willemoes Hansen
 //
 
+//
+// 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.Collections;
 using System.IO;
@@ -28,7 +49,7 @@ using System.Text;
 
 namespace System.Runtime.Remoting.Channels.Http
 {
-       public class HttpClientChannel : IChannelSender,IChannel
+       public class HttpClientChannel : BaseChannelWithProperties, IChannelSender,IChannel
        {
                // Property Keys (purposely all lower-case)
                private const String ProxyNameKey = "proxyname";
@@ -47,28 +68,20 @@ namespace System.Runtime.Remoting.Channels.Http
                private int _clientConnectionLimit = 0; // bump connection limit to at least this number (only meaningful if > 0)
                private bool _bUseDefaultCredentials = false; // should default credentials be used?
         
-               private IClientChannelSinkProvider _sinkProvider = null; // sink chain provider         
-        
-               private IMessageSink _msgSink;
-
-
+               private IClientChannelSinkProvider _sinkProvider = null; // sink chain provider
 
                public HttpClientChannel()
                {
-                       
-                       SetupProvider(_sinkProvider);
+                       SetupProvider (null,null);
                } 
-
-
                
                public HttpClientChannel(String name, IClientChannelSinkProvider sinkProvider)
                {
                        if(name != null)
                                _channelName = name;
                        
-                       SetupProvider(sinkProvider);
+                       SetupProvider (sinkProvider, null);
                }
-       
 
                // constructor used by config file
                public HttpClientChannel(IDictionary properties, IClientChannelSinkProvider sinkProvider)
@@ -101,11 +114,9 @@ namespace System.Runtime.Remoting.Channels.Http
                                }
                        }
                        
-                       SetupProvider (sinkProvider);
-
+                       SetupProvider (sinkProvider, properties);
                } 
         
-               
                public int ChannelPriority
                {
                        get { return _channelPriority; }    
@@ -134,7 +145,7 @@ namespace System.Runtime.Remoting.Channels.Http
 
                public virtual IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI)
                {
-                       if (url == null && remoteChannelData != null && remoteChannelData as IChannelDataStore != null )
+                       if ((url == null || !HttpHelper.StartsWithHttp (url)) && remoteChannelData != null && remoteChannelData as IChannelDataStore != null )
                        {
                                IChannelDataStore ds = (IChannelDataStore) remoteChannelData;
                                url = ds.ChannelUris[0];
@@ -143,19 +154,18 @@ namespace System.Runtime.Remoting.Channels.Http
                        if(url != null && HttpHelper.StartsWithHttp(url))
                        {
                                HttpHelper.Parse(url, out objectURI);
-                               _msgSink = (IMessageSink) _sinkProvider.CreateSink(this,url,remoteChannelData); 
+                               IMessageSink msgSink = (IMessageSink) _sinkProvider.CreateSink(this,url,remoteChannelData); 
                                
-                               if(_msgSink !=null )
+                               if(msgSink !=null )
                                        SetServicePoint(url);
 
-                               return _msgSink;
+                               return msgSink;
                        }
                        else
                        {
                                objectURI = null;
                                return null;
                        }
-
                }
 
                private void UpdateProxy()
@@ -182,12 +192,16 @@ namespace System.Runtime.Remoting.Channels.Http
                internal IWebProxy ProxyObject { get { return _proxyObject; } }
                internal bool UseDefaultCredentials { get { return _bUseDefaultCredentials; } }
 
-               private void SetupProvider(IClientChannelSinkProvider sinkProvider)
+               private void SetupProvider (IClientChannelSinkProvider sinkProvider, IDictionary properties)
                {
+                       if (properties == null) properties = new Hashtable ();
+                       HttpClientTransportSinkProvider httpSink = new HttpClientTransportSinkProvider (properties);
+                       SinksWithProperties = httpSink;
+                       
                        if(sinkProvider == null)
                        {
                                _sinkProvider = new SoapClientFormatterSinkProvider();
-                               _sinkProvider.Next = new HttpClientTransportSinkProvider();
+                               _sinkProvider.Next = httpSink;
                        }
                        else
                        {
@@ -199,17 +213,30 @@ namespace System.Runtime.Remoting.Channels.Http
                                        dummySinkProvider = dummySinkProvider.Next;
                                }
 
-                               dummySinkProvider.Next = new HttpClientTransportSinkProvider();
+                               dummySinkProvider.Next = httpSink;
                        } 
-                       
+               }
+               
+               public override object this [object key]
+               {
+                       get { return Properties[key]; }
+                       set { Properties[key] = value; }
+               }
+               
+               public override ICollection Keys 
+               {
+                       get { return Properties.Keys; }
                }
        } 
 
 
-       internal class HttpClientTransportSinkProvider : IClientChannelSinkProvider
+       internal class HttpClientTransportSinkProvider : IClientChannelSinkProvider, IChannelSinkBase
        {
-               internal HttpClientTransportSinkProvider()
+               IDictionary _properties;
+               
+               internal HttpClientTransportSinkProvider (IDictionary properties)
                {
+                       _properties = properties;
                }    
    
                public IClientChannelSink CreateSink(IChannelSender channel, String url, 
@@ -224,6 +251,12 @@ namespace System.Runtime.Remoting.Channels.Http
                        get { return null; }
                        set { throw new NotSupportedException(); }
                }
+               
+               public IDictionary Properties
+               {
+                       get { return _properties; }
+               }
+               
        } // class HttpClientTransportSinkProvider
 
 
@@ -289,12 +322,13 @@ namespace System.Runtime.Remoting.Channels.Http
                        out ITransportHeaders responseHeaders, out Stream responseStream)
                {
                        string url = null;
-                       string uri = (string)requestHeaders[CommonTransportKeys.RequestUri];
+                       string uri = ((IMethodCallMessage)msg).Uri;
+                       requestHeaders [CommonTransportKeys.RequestUri] = uri;
                        CreateUrl(uri,out url);
 
-                       HttpWebRequest httpWebRequest = CreateWebRequest(url,requestHeaders,requestStream);
+                       HttpWebRequest httpWebRequest = CreateWebRequest (url,requestHeaders,requestStream);
 
-                       SendAndRecieve(httpWebRequest,out responseHeaders,out responseStream);
+                       SendAndRecieve (httpWebRequest,out responseHeaders,out responseStream);
                }
 
 
@@ -302,7 +336,8 @@ namespace System.Runtime.Remoting.Channels.Http
                        ITransportHeaders headers, Stream stream)
                {
                        string url = null;
-                       string uri = (string)headers[CommonTransportKeys.RequestUri];
+                       string uri = ((IMethodCallMessage)msg).Uri;
+                       headers [CommonTransportKeys.RequestUri] = uri;
                        CreateUrl(uri,out url);
 
                        HttpWebRequest httpWebRequest = CreateWebRequest(url,headers,stream);
@@ -532,15 +567,11 @@ namespace System.Runtime.Remoting.Channels.Http
                        }
 
                        Stream reqStream = request.GetRequestStream();
-                       if (requestStream is MemoryStream)
-                       {
-                               MemoryStream memStream = (MemoryStream)requestStream;
-                               reqStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
-                       }
-                       else
+                       try {
                                HttpHelper.CopyStream(requestStream, reqStream);
-
-                       reqStream.Close();
+                       } finally {
+                               reqStream.Close();
+                       }
                        
                        return request;
                }       
@@ -558,7 +589,7 @@ namespace System.Runtime.Remoting.Channels.Http
                        catch (WebException ex)
                        {
                                httpWebResponse = ex.Response as HttpWebResponse;
-                               if (httpWebResponse == null) throw ex;
+                               if (httpWebResponse == null || httpWebResponse.StatusCode == HttpStatusCode.InternalServerError) throw ex;
                        }
 
                        ReceiveResponse (httpWebResponse, out responseHeaders, out responseStream);
@@ -567,17 +598,19 @@ namespace System.Runtime.Remoting.Channels.Http
                private void ReceiveResponse (HttpWebResponse httpWebResponse, out ITransportHeaders responseHeaders, out Stream responseStream)
                {
                        responseHeaders = new TransportHeaders();
+                       Stream webStream = httpWebResponse.GetResponseStream();
 
                        try
                        {
-                               Stream webStream = httpWebResponse.GetResponseStream();
-
                                if (httpWebResponse.ContentLength != -1)
                                {
                                        byte[] buffer = new byte [httpWebResponse.ContentLength];
                                        int nr = 0;
-                                       while (nr < buffer.Length)
-                                               nr += webStream.Read (buffer, nr, buffer.Length - nr);
+                                       while (nr < buffer.Length) {
+                                               int pr = webStream.Read (buffer, nr, buffer.Length - nr);
+                                               if (pr == 0) throw new RemotingException ("Connection closed");
+                                               nr += pr;
+                                       }
                                        responseStream = new MemoryStream (buffer);
                                }
                                else
@@ -597,8 +630,8 @@ namespace System.Runtime.Remoting.Channels.Http
                        }
                        finally
                        {
-                               if(httpWebResponse!=null)
-                                       httpWebResponse.Close();
+                               webStream.Close ();
+                               httpWebResponse.Close();
                        }
                }