2009-06-11 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Thu, 11 Jun 2009 09:33:54 +0000 (09:33 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Thu, 11 Jun 2009 09:33:54 +0000 (09:33 -0000)
* HttpReplyChannel.cs : reject multiple WaitForRequest calls.
  Temporarily disable HTTP Keep-Alive since it somehow results in
  wrong reuse of connection (shown as NRE in HttpConnection).
  Make sure to close RequestContext which was created from it.
* HttpRequestContext.cs : simplify.

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

mcs/class/System.ServiceModel/System.ServiceModel.Channels/ChangeLog
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpReplyChannel.cs
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestContext.cs

index 89981ed5e17af1f4b244833048049bb1ba6f8515..cde7d9f8df0dd695a9ee3a0a4a12444a6819320a 100755 (executable)
@@ -1,3 +1,11 @@
+2009-06-11  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * HttpReplyChannel.cs : reject multiple WaitForRequest calls.
+         Temporarily disable HTTP Keep-Alive since it somehow results in
+         wrong reuse of connection (shown as NRE in HttpConnection).
+         Make sure to close RequestContext which was created from it.
+       * HttpRequestContext.cs : simplify.
+
 2009-06-11  Atsushi Enomoto  <atsushi@ximian.com>
 
        * HttpChannelListener.cs, TcpChannelListener.cs,
index 6492f9ea16f9bd23ee602ec5bcbe073eb9294adf..21fff1fa755341ed29acc1c360573685061d43d0 100644 (file)
@@ -40,6 +40,7 @@ namespace System.ServiceModel.Channels
                HttpSimpleChannelListener<IReplyChannel> source;
                List<HttpListenerContext> waiting = new List<HttpListenerContext> ();
                EndpointAddress local_address;
+               RequestContext reqctx;
 
                public HttpSimpleReplyChannel (HttpSimpleChannelListener<IReplyChannel> listener)
                        : base (listener)
@@ -47,6 +48,12 @@ namespace System.ServiceModel.Channels
                        this.source = listener;
                }
 
+               protected override void OnClose (TimeSpan timeout)
+               {
+                       if (reqctx != null)
+                               reqctx.Close ();
+               }
+
                public override bool TryReceiveRequest (TimeSpan timeout, out RequestContext context)
                {
                        context = null;
@@ -68,6 +75,12 @@ namespace System.ServiceModel.Channels
                        int maxSizeOfHeaders = 0x10000;
 
                        Message msg = null;
+
+                       // FIXME: our HttpConnection (under HttpListener) 
+                       // somehow breaks when the underlying connection is
+                       // reused. Remove it when it gets fixed.
+                       ctx.Response.KeepAlive = false;
+
                        if (ctx.Request.HttpMethod == "POST") {
                                if (!Encoder.IsContentTypeSupported (ctx.Request.ContentType)) {
                                        ctx.Response.StatusCode = (int) HttpStatusCode.UnsupportedMediaType;
@@ -109,22 +122,24 @@ buf.CreateMessage ().WriteMessage (w);
 w.Close ();
 */
                        context = new HttpRequestContext (this, msg, ctx);
+                       reqctx = context;
                        return true;
                }
 
+               AutoResetEvent wait;
+
                public override bool WaitForRequest (TimeSpan timeout)
                {
-                       AutoResetEvent wait = new AutoResetEvent (false);
+                       if (wait != null)
+                               throw new InvalidOperationException ("Another wait operation is in progress");
                        try {
-                               source.Http.BeginGetContext (HttpContextReceived, wait);
+                               wait = new AutoResetEvent (false);
+                               source.Http.BeginGetContext (HttpContextReceived, null);
                        } catch (HttpListenerException e) {
                                if (e.ErrorCode == 0x80004005) // invalid handle. Happens during shutdown.
                                        while (true) Thread.Sleep (1000); // thread is about to be terminated.
                                throw;
                        } catch (ObjectDisposedException) { return false; }
-                       // FIXME: we might want to take other approaches.
-                       if (timeout.Ticks > int.MaxValue)
-                               timeout = TimeSpan.FromDays (20);
                        return wait.WaitOne (timeout, false);
                }
 
@@ -132,10 +147,11 @@ w.Close ();
                {
                        if (State == CommunicationState.Closing || State == CommunicationState.Closed)
                                return;
-
+                       if (wait == null)
+                               throw new InvalidOperationException ("WaitForRequest operation has not started");
                        waiting.Add (source.Http.EndGetContext (result));
-                       AutoResetEvent wait = (AutoResetEvent) result.AsyncState;
                        wait.Set ();
+                       wait = null;
                }
        }
 
index d56e31defd1c028d9092c8daf3a23b9f33469f6a..38a06493440706fe612ab50ac18659fc7580719e 100644 (file)
@@ -34,67 +34,6 @@ namespace System.ServiceModel.Channels
 {
        internal class HttpRequestContext : RequestContext
        {
-               class HttpRequestContextAsyncResult : IAsyncResult
-               {
-                       AutoResetEvent wait;
-                       AsyncCallback callback;
-                       object state;
-                       bool done, waiting;
-                       TimeSpan timeout;
-                       Exception error;
-
-                       public HttpRequestContextAsyncResult (
-                               HttpRequestContext context,
-                               Message msg,
-                               TimeSpan timeout,
-                               AsyncCallback callback,
-                               object state)
-                       {
-                               this.timeout = timeout;
-                               this.wait = new AutoResetEvent (false);
-                               ThreadStart ts = delegate () {
-                                       try {
-                                               context.ProcessReply (msg, timeout);
-                                               if (callback != null)
-                                                       callback (this);
-                                       } catch (Exception ex) {
-                                               error = ex;
-                                       } finally {
-                                               done = true;
-                                               wait.Set ();
-                                       }
-                               };
-                               Thread t = new Thread (ts);
-                               t.Start ();
-                       }
-
-                       public WaitHandle AsyncWaitHandle {
-                               get { return wait; }
-                       }
-
-                       public object AsyncState {
-                               get { return state; }
-                       }
-
-                       public bool CompletedSynchronously {
-                               get { return done && !waiting; }
-                       }
-
-                       public bool IsCompleted {
-                               get { return done; }
-                       }
-
-                       public void WaitEnd ()
-                       {
-                               if (!done) {
-                                       waiting = true;
-                                       wait.WaitOne (timeout, true);
-                               }
-                               if (error != null)
-                                       throw error;
-                       }
-               }
-
                Message msg;
                HttpListenerContext ctx;
                HttpReplyChannel channel;
@@ -135,21 +74,24 @@ namespace System.ServiceModel.Channels
                                callback, state);
                }
 
+               Action<Message,TimeSpan> reply_delegate;
+
                public override IAsyncResult BeginReply (
                        Message msg, TimeSpan timeout,
                        AsyncCallback callback, object state)
                {
-                       return new HttpRequestContextAsyncResult (this, msg, timeout, callback, state);
+                       if (reply_delegate == null)
+                               reply_delegate = new Action<Message,TimeSpan> (Reply);
+                       return reply_delegate.BeginInvoke (msg, timeout, callback, state);
                }
 
                public override void EndReply (IAsyncResult result)
                {
                        if (result == null)
                                throw new ArgumentNullException ("result");
-                       HttpRequestContextAsyncResult r = result as HttpRequestContextAsyncResult;
-                       if (r == null)
-                               throw new InvalidOperationException ("Wrong IAsyncResult");
-                       r.WaitEnd ();
+                       if (reply_delegate == null)
+                               throw new InvalidOperationException ("reply operation has not started");
+                       reply_delegate.EndInvoke (result);
                }
 
                public override void Reply (Message msg)
@@ -198,7 +140,6 @@ namespace System.ServiceModel.Channels
 
                public override void Close (TimeSpan timeout)
                {
-                       // FIXME: use timeout
                        ctx.Response.Close ();
                }
        }