* 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
+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,
HttpSimpleChannelListener<IReplyChannel> source;
List<HttpListenerContext> waiting = new List<HttpListenerContext> ();
EndpointAddress local_address;
+ RequestContext reqctx;
public HttpSimpleReplyChannel (HttpSimpleChannelListener<IReplyChannel> listener)
: base (listener)
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;
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;
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);
}
{
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;
}
}
{
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;
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)
public override void Close (TimeSpan timeout)
{
- // FIXME: use timeout
ctx.Response.Close ();
}
}