New tests.
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / HttpChannelListener.cs
index 8711e3713bde6d18e6047714d9e66806b3e371ca..988d431c508e8402f8023c85f9eca6361bb680ee 100644 (file)
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Linq;
 using System.Net;
 using System.Net.Security;
 using System.ServiceModel;
 using System.ServiceModel.Description;
+using System.ServiceModel.Dispatcher;
 using System.ServiceModel.Security;
 using System.Text;
 
@@ -40,43 +42,32 @@ namespace System.ServiceModel.Channels
        internal class HttpSimpleChannelListener<TChannel> : HttpChannelListenerBase<TChannel>
                where TChannel : class, IChannel
        {
-               HttpListenerManager<TChannel> httpChannelManager;
-
                public HttpSimpleChannelListener (HttpTransportBindingElement source,
                        BindingContext context)
                        : base (source, context)
                {
                }
 
-               public HttpListener Http {
-                       get {  return httpChannelManager.HttpListener; }
-               }
+               object creator_lock = new object ();
 
                protected override TChannel CreateChannel (TimeSpan timeout)
                {
-                       if (typeof (TChannel) == typeof (IReplyChannel))
-                               return (TChannel) (object) new HttpSimpleReplyChannel ((HttpSimpleChannelListener<IReplyChannel>) (object) this);
-
-                       // FIXME: implement more
-                       throw new NotImplementedException ();
+                       lock (creator_lock) {
+                               return CreateChannelCore (timeout);
+                       }
                }
 
-               protected override void OnOpen (TimeSpan timeout)
+               TChannel CreateChannelCore (TimeSpan timeout)
                {
-                       base.OnOpen (timeout);
-                       StartListening (timeout);
-               }
+                       if (typeof (TChannel) == typeof (IReplyChannel))
+                               return (TChannel) (object) new HttpSimpleReplyChannel ((HttpSimpleChannelListener<IReplyChannel>) (object) this);
 
-               protected override void OnClose (TimeSpan timeout)
-               {
-                       base.OnClose (timeout);
-                       httpChannelManager.Stop ();
+                       throw new NotSupportedException (String.Format ("Channel type {0} is not supported", typeof (TChannel)));
                }
 
-               void StartListening (TimeSpan timeout)
+               protected override HttpListenerManager CreateListenerManager ()
                {
-                       httpChannelManager = new HttpListenerManager<TChannel> (this);
-                       httpChannelManager.Open (timeout);
+                       return new HttpSimpleListenerManager (this, Source, SecurityTokenManager, ChannelDispatcher);
                }
        }
 
@@ -94,30 +85,37 @@ namespace System.ServiceModel.Channels
                        if (typeof (TChannel) == typeof (IReplyChannel))
                                return (TChannel) (object) new AspNetReplyChannel ((AspNetChannelListener<IReplyChannel>) (object) this);
 
-                       // FIXME: implement more
-                       throw new NotImplementedException ();
+                       throw new NotSupportedException (String.Format ("Channel type {0} is not supported", typeof (TChannel)));
+               }
+
+               protected override HttpListenerManager CreateListenerManager ()
+               {
+                       return new AspNetListenerManager (this, Source, SecurityTokenManager, ChannelDispatcher);
                }
        }
 
-       internal abstract class HttpChannelListenerBase<TChannel> : ChannelListenerBase<TChannel>
+       internal abstract class HttpChannelListenerBase<TChannel> : InternalChannelListenerBase<TChannel>
                where TChannel : class, IChannel
        {
-               HttpTransportBindingElement source;
-               BindingContext context;
-               Uri listen_uri;
                List<TChannel> channels = new List<TChannel> ();
                MessageEncoder encoder;
+               HttpListenerManager httpChannelManager;
+
+               internal static HttpChannelListenerBase<TChannel>CurrentHttpChannelListener;
 
                public HttpChannelListenerBase (HttpTransportBindingElement source,
                        BindingContext context)
-                       : base (context.Binding)
+                       : base (context)
                {
-                       accept_channel_delegate = new Func<TimeSpan,TChannel> (OnAcceptChannel);
+                       if (ServiceHostBase.CurrentServiceHostHack != null)
+                               DispatcherBuilder.ChannelDispatcherSetter = delegate (ChannelDispatcher cd) { this.ChannelDispatcher = cd; };
+
+                       this.Source = source;
+                       // The null Uri check looks weird, but it seems the listener can be built without it.
+                       // See HttpTransportBindingElementTest.BuildChannelListenerWithoutListenUri().
+                       if (Uri != null && source.Scheme != Uri.Scheme)
+                               throw new ArgumentException (String.Format ("Requested listen uri scheme must be {0}, but was {1}.", source.Scheme, Uri.Scheme));
 
-                       // FIXME: consider ListenUriMode
-                       // FIXME: there should be some way to post-provide Uri in case of null listenerUri in context.
-                       listen_uri = context.ListenUriBaseAddress != null ?
-                               new Uri (context.ListenUriBaseAddress, context.ListenUriRelativeAddress) : null;
                        foreach (BindingElement be in context.RemainingBindingElements) {
                                MessageEncodingBindingElement mbe = be as MessageEncodingBindingElement;
                                if (mbe != null) {
@@ -127,96 +125,60 @@ namespace System.ServiceModel.Channels
                        }
                        if (encoder == null)
                                encoder = new TextMessageEncoder (MessageVersion.Default, Encoding.UTF8);
-               }
 
-               public MessageEncoder MessageEncoder {
-                       get { return encoder; }
+                       if (context.BindingParameters.Contains (typeof (ServiceCredentials)))
+                               SecurityTokenManager = new ServiceCredentialsSecurityTokenManager ((ServiceCredentials) context.BindingParameters [typeof (ServiceCredentials)]);
                }
 
-               public override Uri Uri {
-                       get { return listen_uri; }
+               internal ChannelDispatcher ChannelDispatcher { get; set; }
+
+               public HttpTransportBindingElement Source { get; private set; }
+
+               public HttpListenerManager ListenerManager {
+                       get {  return httpChannelManager; }
                }
 
-               protected IList<TChannel> Channels {
-                       get { return channels; }
+               public MessageEncoder MessageEncoder {
+                       get { return encoder; }
                }
 
+               public ServiceCredentialsSecurityTokenManager SecurityTokenManager { get; private set; }
+
                protected override TChannel OnAcceptChannel (TimeSpan timeout)
                {
                        TChannel ch = CreateChannel (timeout);
-                       Channels.Add (ch);
                        return ch;
                }
 
                protected abstract TChannel CreateChannel (TimeSpan timeout);
 
-               Func<TimeSpan,TChannel> accept_channel_delegate;
-
-               protected override IAsyncResult OnBeginAcceptChannel (
-                       TimeSpan timeout, AsyncCallback callback,
-                       object asyncState)
-               {
-                       return accept_channel_delegate.BeginInvoke (timeout, callback, asyncState);
-               }
-
-               protected override TChannel OnEndAcceptChannel (IAsyncResult result)
-               {
-                       return accept_channel_delegate.EndInvoke (result);
-               }
-
-               protected override IAsyncResult OnBeginWaitForChannel (
-                       TimeSpan timeout, AsyncCallback callback, object state)
-               {
-                       throw new NotImplementedException ();
-               }
-
-               protected override bool OnEndWaitForChannel (IAsyncResult result)
-               {
-                       throw new NotImplementedException ();
-               }
-
                protected override bool OnWaitForChannel (TimeSpan timeout)
                {
                        throw new NotImplementedException ();
                }
 
-               protected override IAsyncResult OnBeginOpen (TimeSpan timeout,
-                       AsyncCallback callback, object state)
-               {
-                       throw new NotImplementedException ();
-               }
+               protected abstract HttpListenerManager CreateListenerManager ();
 
-               protected override void OnEndOpen (IAsyncResult result)
-               {
-                       throw new NotImplementedException ();
-               }
-
-               [MonoTODO]
-               protected override IAsyncResult OnBeginClose (TimeSpan timeout,
-                       AsyncCallback callback, object state)
-               {
-                       throw new NotImplementedException ();
-               }
-
-               [MonoTODO]
-               protected override void OnEndClose (IAsyncResult result)
+               protected override void OnOpen (TimeSpan timeout)
                {
-                       throw new NotImplementedException ();
+                       httpChannelManager = CreateListenerManager ();
+                       Properties.Add (httpChannelManager);
+                       httpChannelManager.Open (timeout);
                }
 
-               [MonoTODO ("find out what to do here.")]
                protected override void OnAbort ()
                {
-               }
-
-               protected override void OnOpen (TimeSpan timeout)
-               {
+                       httpChannelManager.Stop (true);
                }
 
                protected override void OnClose (TimeSpan timeout)
                {
-                       foreach (TChannel ch in Channels)
-                               ch.Close(timeout);
+                       if (State == CommunicationState.Closed)
+                               return;
+                       base.OnClose (timeout);
+                       // The channels are kept open when the creator channel listener is closed.
+                       // http://blogs.msdn.com/drnick/archive/2006/03/22/557642.aspx
+                       httpChannelManager.Stop (false);
                }
        }
 }