2009-10-22 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Thu, 22 Oct 2009 07:01:40 +0000 (07:01 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Thu, 22 Oct 2009 07:01:40 +0000 (07:01 -0000)
* SvcHttpHandler.cs, HttpReplyChannel.cs, AspNetReplyChannel.cs,
  HttpChannelListener.cs, HttpListenerManager.cs :
  Similar refactoring on ASP.NET side to the previous one.
  Added ASP.NET implementation of HttpListenerManager and use some
  part of it in SvcHttpHandler (ASP.NET stack does not fully make use
  of the manager yet).
  Rewrote AspNetReplyChannel to become almost the same as
  HttpSimpleReplyChannel, to hopefully unify them later.
  Now it dispatches requests to *.svc for wsdl, help and SOAP as long
  as ServiceThrottle has MaxConcurrentSessions=1. Also REST calls
  are still broken.

svn path=/trunk/mcs/; revision=144605

mcs/class/System.ServiceModel/System.ServiceModel.Channels/AspNetReplyChannel.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpChannelListener.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpListenerManager.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpReplyChannel.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs

index f72e420b231d643f3d8d424edf928ed7eb334454..e859f31063c7bbcc3946d3316f38c5127359b384 100644 (file)
@@ -38,8 +38,10 @@ namespace System.ServiceModel.Channels
 {
        internal class AspNetReplyChannel : HttpReplyChannel
        {
-               HttpContext http_context;
                AspNetChannelListener<IReplyChannel> listener;
+               List<HttpContext> waiting = new List<HttpContext> ();
+               HttpContext http_context;
+               AutoResetEvent wait;
 
                public AspNetReplyChannel (AspNetChannelListener<IReplyChannel> listener)
                        : base (listener)
@@ -58,28 +60,28 @@ namespace System.ServiceModel.Channels
                        }
                }
 
+               void ShutdownPendingRequests ()
+               {
+                       lock (waiting)
+                               foreach (HttpContext ctx in waiting)
+                                       try {
+                                               listener.HttpHandler.EndRequest (listener, ctx);
+                                       } catch {
+                                       }
+               }
+
                protected override void OnAbort ()
                {
-                       if (http_context == null)
-                               return;
-                       try {
-                               listener.HttpHandler.EndRequest (listener, http_context);
-                       } finally {
-                               http_context = null;
-                       }
+                       ShutdownPendingRequests ();
+                       CloseContext ();
                }
 
                protected override void OnClose (TimeSpan timeout)
                {
                        base.OnClose (timeout);
 
-                       if (http_context == null)
-                               return;
-                       try {
-                               listener.HttpHandler.EndRequest (listener, http_context);
-                       } finally {
-                               http_context = null;
-                       }
+                       ShutdownPendingRequests ();
+                       CloseContext ();
                }
 
                public override bool TryReceiveRequest (TimeSpan timeout, out RequestContext context)
@@ -96,14 +98,23 @@ namespace System.ServiceModel.Channels
                bool TryReceiveRequestCore (TimeSpan timeout, out RequestContext context)
                {
                        context = null;
-                       if (!WaitForRequest (timeout))
+                       if (waiting.Count == 0 && !WaitForRequest (timeout))
+                               return false;
+                       lock (waiting) {
+                               if (waiting.Count > 0) {
+                                       http_context = waiting [0];
+                                       waiting.RemoveAt (0);
+                               }
+                       }
+                       if (http_context == null) 
+                               // Though as long as this instance is used
+                               // synchronously, it should not happen.
                                return false;
 
                        Message msg;
                        var req = http_context.Request;
                        if (req.HttpMethod == "GET") {
                                msg = Message.CreateMessage (Encoder.MessageVersion, null);
-                               msg.Headers.To = req.Url;
                        } else {
                                //FIXME: Do above stuff for HttpContext ?
                                int maxSizeOfHeaders = 0x10000;
@@ -119,6 +130,7 @@ namespace System.ServiceModel.Channels
                        }
 
                        // FIXME: prop.SuppressEntityBody
+                       msg.Headers.To = req.Url;
                        msg.Properties.Add ("Via", LocalAddress.Uri);
                        msg.Properties.Add (HttpRequestMessageProperty.Name, CreateRequestProperty (req.HttpMethod, req.Url.Query, req.Headers));
 
@@ -127,11 +139,44 @@ namespace System.ServiceModel.Channels
                        return true;
                }
 
+               /*
                public override bool WaitForRequest (TimeSpan timeout)
                {
                        if (http_context == null)
                                http_context = listener.HttpHandler.WaitForRequest (listener, timeout);
                        return http_context != null;
                }
+               */
+
+               public override bool WaitForRequest (TimeSpan timeout)
+               {
+Console.WriteLine ("Enter AspNetReplyChannel.WaitForRequest");
+                       if (wait != null)
+                               throw new InvalidOperationException ("Another wait operation is in progress");
+                       try {
+                               wait = new AutoResetEvent (false);
+                               listener.ListenerManager.GetHttpContextAsync (timeout, HttpContextAcquired);
+                               if (wait != null) // in case callback is done before WaitOne() here.
+                                       return wait.WaitOne (timeout, false);
+Console.WriteLine ("Exit AspNetReplyChannel.WaitForRequest");
+                               return waiting.Count > 0;
+                       } finally {
+                               wait = null;
+                       }
+               }
+
+               void HttpContextAcquired (HttpContextInfo ctx)
+               {
+Console.WriteLine ("Enter HttpContextAcquired: {0}", ctx != null ? ctx.RequestUrl : null);
+                       if (wait == null)
+                               throw new InvalidOperationException ("WaitForRequest operation has not started");
+                       var sctx = (AspNetHttpContextInfo) ctx;
+                       if (State == CommunicationState.Opened && ctx != null)
+                               waiting.Add (sctx.Source);
+                       var wait_ = wait;
+                       wait = null;
+                       wait_.Set ();
+Console.WriteLine ("Exit HttpContextAcquired: {0}", ctx != null ? ctx.RequestUrl : null);
+               }
        }
 }
index 779e4352ea295de61b9dded26ae8722a6770baab..2cd1c5a0a789d5371766e1fee6c97c7e104a0911 100755 (executable)
@@ -1,3 +1,17 @@
+2009-10-22  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * SvcHttpHandler.cs, HttpReplyChannel.cs, AspNetReplyChannel.cs,
+         HttpChannelListener.cs, HttpListenerManager.cs :
+         Similar refactoring on ASP.NET side to the previous one.
+         Added ASP.NET implementation of HttpListenerManager and use some
+         part of it in SvcHttpHandler (ASP.NET stack does not fully make use
+         of the manager yet).
+         Rewrote AspNetReplyChannel to become almost the same as
+         HttpSimpleReplyChannel, to hopefully unify them later.
+         Now it dispatches requests to *.svc for wsdl, help and SOAP as long
+         as ServiceThrottle has MaxConcurrentSessions=1. Also REST calls
+         are still broken.
+
 2009-10-20  Atsushi Enomoto  <atsushi@ximian.com>
 
        * HttpReplyChannel.cs, HttpChannelListener.cs, HttpListenerManager.cs:
index 04be1d010eef7c0a1fceb29abda30d5660e902d5..b2524cb7231406488e50663936fad8fb0e614d07 100644 (file)
@@ -41,18 +41,12 @@ 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 HttpListenerManager<TChannel> ListenerManager {
-                       get {  return httpChannelManager; }
-               }
-
                object creator_lock = new object ();
 
                protected override TChannel CreateChannel (TimeSpan timeout)
@@ -70,31 +64,9 @@ namespace System.ServiceModel.Channels
                        throw new NotSupportedException (String.Format ("Channel type {0} is not supported", typeof (TChannel)));
                }
 
-               protected override void OnOpen (TimeSpan timeout)
-               {
-                       base.OnOpen (timeout);
-                       StartListening (timeout);
-               }
-
-               protected override void OnAbort ()
-               {
-                       httpChannelManager.Stop (true);
-               }
-
-               protected override void OnClose (TimeSpan timeout)
+               protected override HttpListenerManager CreateListenerManager ()
                {
-                       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);
-               }
-
-               void StartListening (TimeSpan timeout)
-               {
-                       httpChannelManager = new HttpListenerManager<TChannel> (this);
-                       httpChannelManager.Open (timeout);
+                       return new HttpSimpleListenerManager (this);
                }
        }
 
@@ -107,13 +79,8 @@ namespace System.ServiceModel.Channels
                {
                }
 
-               SvcHttpHandler http_handler;
                internal SvcHttpHandler HttpHandler {
-                       get {
-                               if (http_handler == null)
-                                       http_handler = SvcHttpHandlerFactory.GetHandlerForListener (this);
-                               return http_handler;
-                       }
+                       get { return ((AspNetListenerManager) ListenerManager).Source; }
                }
 
                protected override TChannel CreateChannel (TimeSpan timeout)
@@ -124,21 +91,9 @@ namespace System.ServiceModel.Channels
                        throw new NotSupportedException (String.Format ("Channel type {0} is not supported", typeof (TChannel)));
                }
 
-               protected override void OnAbort ()
+               protected override HttpListenerManager CreateListenerManager ()
                {
-                       HttpHandler.UnregisterListener (this);
-               }
-
-               protected override void OnOpen (TimeSpan timeout)
-               {
-                       base.OnOpen (timeout);
-                       HttpHandler.RegisterListener (this);
-               }
-
-               protected override void OnClose (TimeSpan timeout)
-               {
-                       HttpHandler.UnregisterListener (this);
-                       base.OnClose (timeout);
+                       return new AspNetListenerManager (this);
                }
        }
 
@@ -149,6 +104,7 @@ namespace System.ServiceModel.Channels
                BindingContext context;
                List<TChannel> channels = new List<TChannel> ();
                MessageEncoder encoder;
+               HttpListenerManager httpChannelManager;
 
                public HttpChannelListenerBase (HttpTransportBindingElement source,
                        BindingContext context)
@@ -165,6 +121,10 @@ namespace System.ServiceModel.Channels
                                encoder = new TextMessageEncoder (MessageVersion.Default, Encoding.UTF8);
                }
 
+               public HttpListenerManager ListenerManager {
+                       get {  return httpChannelManager; }
+               }
+
                public MessageEncoder MessageEncoder {
                        get { return encoder; }
                }
@@ -182,19 +142,28 @@ namespace System.ServiceModel.Channels
                        throw new NotImplementedException ();
                }
 
-               protected override void OnAbort ()
+               protected abstract HttpListenerManager CreateListenerManager ();
+
+               protected override void OnOpen (TimeSpan timeout)
                {
-                       OnClose (TimeSpan.Zero);
+                       httpChannelManager = CreateListenerManager ();
+                       Properties.Add (httpChannelManager);
+                       httpChannelManager.Open (timeout);
                }
 
-               protected override void OnOpen (TimeSpan timeout)
+               protected override void OnAbort ()
                {
+                       httpChannelManager.Stop (true);
                }
 
                protected override void OnClose (TimeSpan timeout)
                {
-                       DateTime start = DateTime.Now;
-                       base.OnClose (timeout - (DateTime.Now - start));
+                       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);
                }
        }
 }
index da7923573a140c6d35293417c9f2998b2b7d06da..46a6d124c5f0a5ef7020e67a176335a3ec938e58 100644 (file)
 //
 using System;
 using System.Collections.Generic;
+using System.Collections.Specialized;
 using System.ServiceModel.Description;
 using System.Text;
 using System.Threading;
 using System.Net;
+using System.Web;
 
 namespace System.ServiceModel.Channels
 {
-       internal class HttpListenerManager<TChannel> where TChannel : class, IChannel
+       abstract class HttpContextInfo
+       {
+               public abstract NameValueCollection QueryString { get; }
+               public abstract Uri RequestUrl { get; }
+               public abstract string HttpMethod { get; }
+               public abstract void Abort ();
+       }
+
+       class HttpListenerContextInfo : HttpContextInfo
+       {
+               public HttpListenerContextInfo (HttpListenerContext ctx)
+               {
+                       this.ctx = ctx;
+               }
+               
+               HttpListenerContext ctx;
+
+               public HttpListenerContext Source {
+                       get { return ctx; }
+               }
+
+               public override NameValueCollection QueryString {
+                       get { return ctx.Request.QueryString; }
+               }
+               public override Uri RequestUrl {
+                       get { return ctx.Request.Url; }
+               }
+               public override string HttpMethod {
+                       get { return ctx.Request.HttpMethod; }
+               }
+               public override void Abort ()
+               {
+                       ctx.Response.Abort ();
+               }
+       }
+
+       class AspNetHttpContextInfo : HttpContextInfo
+       {
+               public AspNetHttpContextInfo (HttpContext ctx)
+               {
+                       this.ctx = ctx;
+               }
+               
+               HttpContext ctx;
+
+               public HttpContext Source {
+                       get { return ctx; }
+               }
+
+               public override NameValueCollection QueryString {
+                       get { return ctx.Request.QueryString; }
+               }
+               public override Uri RequestUrl {
+                       get { return ctx.Request.Url; }
+               }
+               public override string HttpMethod {
+                       get { return ctx.Request.HttpMethod; }
+               }
+
+               public override void Abort ()
+               {
+                       ctx.Response.Close ();
+               }
+       }
+
+       internal class HttpSimpleListenerManager : HttpListenerManager
        {
                static Dictionary<Uri, HttpListener> opened_listeners;
-               static Dictionary<Uri, List<HttpSimpleChannelListener<TChannel>>> registered_channels;
-               HttpSimpleChannelListener<TChannel> channel_listener;
                HttpListener http_listener;
-               MetadataPublishingInfo mex_info;
-               HttpGetWsdl wsdl_instance;
-               AutoResetEvent wait_http_ctx = new AutoResetEvent (false);
-               List<HttpListenerContext> pending = new List<HttpListenerContext> ();
 
-               static HttpListenerManager ()
+               static HttpSimpleListenerManager ()
                {
                        opened_listeners = new Dictionary<Uri, HttpListener> ();
-                       registered_channels = new Dictionary<Uri, List<HttpSimpleChannelListener<TChannel>>> ();
                }
 
-               public HttpListenerManager (HttpSimpleChannelListener<TChannel> channelListener)
+               public HttpSimpleListenerManager (IChannelListener channelListener)
+                       : base (channelListener)
                {
-                       this.channel_listener = channelListener;
-                       // FIXME: this cast should not be required, but current JIT somehow causes an internal error.
-                       mex_info = ((IChannelListener) channelListener).GetProperty<MetadataPublishingInfo> ();
-                       wsdl_instance = mex_info != null ? mex_info.Instance : null;
                }
 
-               public void Open (TimeSpan timeout)
+               protected override void OnRegister (IChannelListener channelListener, TimeSpan timeout)
                {
                        lock (opened_listeners) {
-                               if (!opened_listeners.ContainsKey (channel_listener.Uri)) {
+                               if (!opened_listeners.ContainsKey (channelListener.Uri)) {
                                        HttpListener listener = new HttpListener ();
 
-                                       string uriString = channel_listener.Uri.ToString ();
+                                       string uriString = channelListener.Uri.ToString ();
                                        if (!uriString.EndsWith ("/", StringComparison.Ordinal))
                                                uriString += "/";
                                        listener.Prefixes.Add (uriString);
                                        listener.Start ();
 
-                                       opened_listeners [channel_listener.Uri] = listener;
-                                       List<HttpSimpleChannelListener<TChannel>> registeredList = new List<HttpSimpleChannelListener<TChannel>> ();
-                                       registered_channels [channel_listener.Uri] = registeredList;
+                                       opened_listeners [channelListener.Uri] = listener;
                                }
 
-                               http_listener = opened_listeners [channel_listener.Uri];
-                               registered_channels [channel_listener.Uri].Add (channel_listener);
-
-                               // make sure to fill wsdl_instance among other 
-                               // listeners. It is somewhat hacky way, but 
-                               // otherwise there is no assured way to do it.
-                               if (wsdl_instance != null) {
-                                       foreach (var l in registered_channels [channel_listener.Uri])
-                                               l.ListenerManager.wsdl_instance = wsdl_instance;
-                               }
+                               http_listener = opened_listeners [channelListener.Uri];
                        }
                }
 
-               public void Stop (bool abort)
+               protected override void OnUnregister (IChannelListener listener, bool abort)
                {
                        lock (opened_listeners) {
                                if (http_listener == null)
                                        return;
-                               List<HttpSimpleChannelListener<TChannel>> channelsList = registered_channels [channel_listener.Uri];
-                               channelsList.Remove (channel_listener);
-                               if (channelsList.Count == 0) {
-                                       if (http_listener.IsListening) {
-                                               if (abort)
-                                                       http_listener.Abort ();
-                                               else
-                                                       http_listener.Close ();
-                                       }
-                                       ((IDisposable) http_listener).Dispose ();
-
-                                       opened_listeners.Remove (channel_listener.Uri);
-                                       try {
-                                               foreach (var ctx in pending)
-                                                       ctx.Response.Abort ();
-                                       } catch (Exception ex) {
-                                               // FIXME: log it
-                                               Console.WriteLine ("error during HTTP channel listener shutdown: " + ex);
-                                       }
-                                       http_listener = null;
+                               if (http_listener.IsListening) {
+                                       if (abort)
+                                               http_listener.Abort ();
+                                       else
+                                               http_listener.Close ();
                                }
+                               ((IDisposable) http_listener).Dispose ();
+
+                               opened_listeners.Remove (listener.Uri);
+                       }
+
+                       http_listener = null;
+               }
+
+               public override void KickContextReceiver (IChannelListener listener, Action<HttpContextInfo> contextReceivedCallback)
+               {
+                       http_listener.BeginGetContext (delegate (IAsyncResult result) {
+                               var hctx = http_listener.EndGetContext (result);
+                               contextReceivedCallback (new HttpListenerContextInfo (hctx));
+                       }, null);
+               }
+       }
+
+       internal class AspNetListenerManager : HttpListenerManager
+       {
+               SvcHttpHandler http_handler;
+
+               public AspNetListenerManager (IChannelListener channelListener)
+                       : base (channelListener)
+               {
+                       http_handler = SvcHttpHandlerFactory.GetHandlerForListener (channelListener);
+               }
+
+               public SvcHttpHandler Source {
+                       get { return http_handler; }
+               }
+
+               protected override void OnRegister (IChannelListener channelListener, TimeSpan timeout)
+               {
+                       http_handler.RegisterListener (channelListener);
+               }
+
+               protected override void OnUnregister (IChannelListener listener, bool abort)
+               {
+                       http_handler.UnregisterListener (listener);
+               }
+
+               Func<IChannelListener,HttpContext> wait_delegate;
+
+               public override void KickContextReceiver (IChannelListener listener, Action<HttpContextInfo> contextReceivedCallback)
+               {
+                       if (wait_delegate == null)
+                               wait_delegate = new Func<IChannelListener,HttpContext> (http_handler.WaitForRequest);
+                       wait_delegate.BeginInvoke (listener, delegate (IAsyncResult result) {
+                               var ctx = wait_delegate.EndInvoke (result);
+                               contextReceivedCallback (ctx != null ? new AspNetHttpContextInfo (ctx) : null);
+                               }, null);
+               }
+       }
+
+       internal abstract class HttpListenerManager
+       {
+               static Dictionary<Uri, List<IChannelListener>> registered_channels;
+               IChannelListener channel_listener;
+               MetadataPublishingInfo mex_info;
+               HttpGetWsdl wsdl_instance;
+               AutoResetEvent wait_http_ctx = new AutoResetEvent (false);
+               List<HttpContextInfo> pending = new List<HttpContextInfo> ();
+
+public MetadataPublishingInfo MexInfo { get { return mex_info; } }
+
+               static HttpListenerManager ()
+               {
+                       registered_channels = new Dictionary<Uri, List<IChannelListener>> ();
+               }
+
+               protected HttpListenerManager (IChannelListener channelListener)
+               {
+                       this.channel_listener = channelListener;
+                       // FIXME: this cast should not be required, but current JIT somehow causes an internal error.
+                       mex_info = ((IChannelListener) channelListener).GetProperty<MetadataPublishingInfo> ();
+                       wsdl_instance = mex_info != null ? mex_info.Instance : null;
+               }
+
+               public void Open (TimeSpan timeout)
+               {
+                       if (!registered_channels.ContainsKey (channel_listener.Uri))
+                               registered_channels [channel_listener.Uri] = new List<IChannelListener> ();
+                       OnRegister (channel_listener, timeout);
+                       registered_channels [channel_listener.Uri].Add (channel_listener);
+
+                       // make sure to fill wsdl_instance among other 
+                       // listeners. It is somewhat hacky way, but 
+                       // otherwise there is no assured way to do it.
+                       if (wsdl_instance != null) {
+                               foreach (var l in registered_channels [channel_listener.Uri])
+                                       l.GetProperty<HttpListenerManager> ().wsdl_instance = wsdl_instance;
                        }
                }
 
+               public void Stop (bool abort)
+               {
+                       List<IChannelListener> channelsList = registered_channels [channel_listener.Uri];
+                       channelsList.Remove (channel_listener);
+
+                       try {
+                               foreach (var ctx in pending)
+                                       ctx.Abort ();
+                       } catch (Exception ex) {
+                               // FIXME: log it
+                               Console.WriteLine ("error during HTTP channel listener shutdown: " + ex);
+                       }
+
+                       if (channelsList.Count == 0)
+                               OnUnregister (channel_listener, abort);
+               }
+
+               protected abstract void OnRegister (IChannelListener listener, TimeSpan timeout);
+               protected abstract void OnUnregister (IChannelListener listener, bool abort);
+
                // Do not directly handle retrieved HttpListenerContexts when
                // the listener received ones.
                // Instead, iterate every listeners to find the most-likely-
@@ -125,7 +267,7 @@ namespace System.ServiceModel.Channels
                // If the listener is not requesting a context right now, then
                // store it in *each* listener's queue.
 
-               public void GetHttpContextAsync (Action<HttpListenerContext> callback)
+               public void GetHttpContextAsync (TimeSpan timeout, Action<HttpContextInfo> callback)
                {
                        lock (pending) {
                                foreach (var pctx in pending) {
@@ -135,21 +277,19 @@ namespace System.ServiceModel.Channels
                                        }
                                }
                        }
-                       HttpListenerContext ctx;
-                       http_listener.BeginGetContext (delegate (IAsyncResult result) {
-                               ctx = http_listener.EndGetContext (result);
-                               DispatchHttpListenerContext (ctx);
-                       }, null);
-                       wait_http_ctx.WaitOne ();
+                       KickContextReceiver (channel_listener, DispatchHttpListenerContext);
+                       wait_http_ctx.WaitOne (timeout);
                        lock (pending) {
-                               ctx = pending.Count > 0 ? pending [0] : null;
+                               HttpContextInfo ctx = pending.Count > 0 ? pending [0] : null;
                                if (ctx != null)
                                        pending.Remove (ctx);
+                               callback (ctx);
                        }
-                       callback (ctx);
                }
 
-               void DispatchHttpListenerContext (HttpListenerContext ctx)
+               public abstract void KickContextReceiver (IChannelListener listener, Action<HttpContextInfo> contextReceiverCallback);
+
+               void DispatchHttpListenerContext (HttpContextInfo ctx)
                {
                        if (wsdl_instance == null) {
                                pending.Add (ctx);
@@ -157,7 +297,7 @@ namespace System.ServiceModel.Channels
                                return;
                        }
                        foreach (var l in registered_channels [channel_listener.Uri]) {
-                               var lm = l.ListenerManager;
+                               var lm = l.GetProperty<HttpListenerManager> ();
                                if (lm.FilterHttpContext (ctx)) {
                                        lm.pending.Add (ctx);
                                        lm.wait_http_ctx.Set ();
@@ -168,9 +308,9 @@ namespace System.ServiceModel.Channels
                        wait_http_ctx.Set ();
                }
 
-               bool FilterHttpContext (HttpListenerContext ctx)
+               internal bool FilterHttpContext (HttpContextInfo ctx)
                {
-                       if (ctx.Request.HttpMethod.ToUpper () != "GET")
+                       if (ctx.HttpMethod.ToUpper () != "GET")
                                return mex_info == null;
 
                        if (wsdl_instance == null)
@@ -181,15 +321,15 @@ namespace System.ServiceModel.Channels
                        var cmpflag = UriComponents.HttpRequestUrl ^ UriComponents.Query;
                        var fmtflag = UriFormat.SafeUnescaped;
 
-                       if (Uri.Compare (ctx.Request.Url, wsdl_instance.WsdlUrl, cmpflag, fmtflag, StringComparison.Ordinal) == 0) {
+                       if (wsdl_instance.WsdlUrl != null && Uri.Compare (ctx.RequestUrl, wsdl_instance.WsdlUrl, cmpflag, fmtflag, StringComparison.Ordinal) == 0) {
                                if (mex_info == null)
                                        return false; // Do not handle this at normal dispatcher.
-                               if (ctx.Request.QueryString [null] == "wsdl")
+                               if (ctx.QueryString [null] == "wsdl")
                                        return mex_info.IsMex; // wsdl dispatcher should handle this.
                                if (!wsdl_instance.HelpUrl.Equals (wsdl_instance.WsdlUrl))
                                        return true; // in case help URL is not equivalent to WSDL URL, it anyways returns WSDL regardless of ?wsdl existence.
                        }
-                       if (Uri.Compare (ctx.Request.Url, wsdl_instance.HelpUrl, cmpflag, fmtflag, StringComparison.Ordinal) == 0) {
+                       if (wsdl_instance.HelpUrl != null && Uri.Compare (ctx.RequestUrl, wsdl_instance.HelpUrl, cmpflag, fmtflag, StringComparison.Ordinal) == 0) {
                                // Do not handle this at normal dispatcher.
                                // Do return true otherwise, even if it is with "?wsdl".
                                // (It must be handled above if applicable.)
index 89a97c8411c2cb3387097621b7912adc6913fdc0..f35245736eeda91b0fc14f62bfcff0553e38791f 100644 (file)
@@ -146,7 +146,7 @@ w.Close ();
                                throw new InvalidOperationException ("Another wait operation is in progress");
                        try {
                                wait = new AutoResetEvent (false);
-                               source.ListenerManager.GetHttpContextAsync (HttpContextAcquired);
+                               source.ListenerManager.GetHttpContextAsync (timeout, HttpContextAcquired);
                                if (wait != null) // in case callback is done before WaitOne() here.
                                        return wait.WaitOne (timeout, false);
                                return waiting.Count > 0;
@@ -162,12 +162,13 @@ w.Close ();
                        }
                }
 
-               void HttpContextAcquired (HttpListenerContext ctx)
+               void HttpContextAcquired (HttpContextInfo ctx)
                {
                        if (wait == null)
                                throw new InvalidOperationException ("WaitForRequest operation has not started");
+                       var sctx = (HttpListenerContextInfo) ctx;
                        if (State == CommunicationState.Opened && ctx != null)
-                               waiting.Add (ctx);
+                               waiting.Add (sctx.Source);
                        var wait_ = wait;
                        wait = null;
                        wait_.Set ();
index 8d943d5b32ee68a6edb3e801fe732bf0a6f9071d..6b05e9e869b7bd81b997eac852aa252830549f7e 100644 (file)
@@ -86,17 +86,13 @@ namespace System.ServiceModel.Channels {
                        get { return host; }
                }
 
-               public HttpContext WaitForRequest (IChannelListener listener, TimeSpan timeout)
+               public HttpContext WaitForRequest (IChannelListener listener)
                {
                        if (close_state > 0)
                                return null;
-                       DateTime start = DateTime.Now;
 
                        if (listeners [listener].Pending.Count == 0)
-                               listeners [listener].ProcessRequestHandle.WaitOne (timeout, false);
-
-                       if (listeners [listener].Pending.Count == 0)
-                               return null;
+                               listeners [listener].ProcessRequestHandle.WaitOne ();
 
                        var ctx = listeners [listener].Pending [0];
                        listeners [listener].Pending.RemoveAt (0);
@@ -105,6 +101,7 @@ namespace System.ServiceModel.Channels {
 
                IChannelListener FindBestMatchListener (HttpContext ctx)
                {
+/*
                        // Select the best-match listener.
                        IChannelListener best = null;
                        string rel = null;
@@ -124,17 +121,27 @@ namespace System.ServiceModel.Channels {
                                        best = l;
                        }
                        return best;
+*/
+                       var actx = new AspNetHttpContextInfo (ctx);
+                       foreach (var i in listeners)
+                               if (i.Listener.GetProperty<HttpListenerManager> ().FilterHttpContext (actx))
+                                       return i.Listener;
+                       throw new InvalidOperationException ();
                }
 
                public void ProcessRequest (HttpContext context)
                {
                        EnsureServiceHost ();
 
-                       var l = FindBestMatchListener (context);
-                       listeners [l].Pending.Add (context);
-                       listeners [l].ProcessRequestHandle.Set ();
                        var wait = new AutoResetEvent (false);
-                       wcf_wait_handles [context] = wait;
+                       var l = FindBestMatchListener (context);
+                       var i = listeners [l];
+                       lock (i) {
+                               i.Pending.Add (context);
+                               wcf_wait_handles [context] = wait;
+                               i.ProcessRequestHandle.Set ();
+                       }
+
                        wait.WaitOne ();
                }
 
@@ -183,6 +190,9 @@ namespace System.ServiceModel.Channels {
                        host.Extensions.Add (new VirtualPathExtension (baseUri.AbsolutePath));
 
                        host.Open ();
+
+                       // Not precise, but it needs some wait time to have all channels start requesting. And it is somehow required.
+                       Thread.Sleep (500);
                }
        }
 }