Exemplo n.º 1
0
 private static object GetDocumentResponse(DreamContext context, DreamMessage request, Result<DreamMessage> response)
 {
     var docResponse = new Result<XDoc>();
     docResponse.WhenDone(
         r => response.Return(DreamMessage.Ok(r)),
         response.Throw);
     return docResponse;
 }
Exemplo n.º 2
0
        private Result Write(Action<string> activity, Stream stream, byte[] buffer, int offset, int count, Result result)
        {
            // asynchronously execute read operation
            Result<IAsyncResult> inner = new Result<IAsyncResult>(TimeSpan.MaxValue);
            inner.WhenDone(delegate(Result<IAsyncResult> _unused) {
                try {
                    activity(string.Format("pre {0}!EndWrite", stream.GetType().FullName));
                    stream.EndWrite(inner.Value);
                    activity("post EndWrite");
                    result.Return();
                } catch(Exception e) {
                    activity("throw Write 1");
                    result.Throw(e);
                }
            });
            try {
                activity(string.Format("pre {0}!BeginWrite", stream.GetType().FullName));
                stream.BeginWrite(buffer, offset, count, inner.Return, stream);
                activity("post BeginWrite");
            } catch(Exception e) {
                activity("throw Write 2");
                result.Throw(e);
            }

            // return yield handle
            return result;
        }
Exemplo n.º 3
0
 public void Result_with_current_state_should_get_original_state_on_whendone_with_return_before_whendone()
 {
     var state = new TaskLifeSpanState("baz");
     TaskEnv.Current.SetState(state);
     var allgood = false;
     var resetEvent = new ManualResetEvent(false);
     var r = new Result(TaskEnv.Current);
     r.Return();
     r.WhenDone(r2 => {
         allgood = !r2.HasException && state == TaskEnv.Current.GetState<TaskLifeSpanState>();
         resetEvent.Set();
     });
     resetEvent.WaitOne();
     Assert.IsTrue(allgood);
 }
Exemplo n.º 4
0
 public void WhenDone_triggers_state_disposal()
 {
     var state = new TaskLifeSpanState("baz");
     Assert.IsFalse(state.IsDisposed);
     TaskEnv.Current.SetState(state);
     var resetEvent = new ManualResetEvent(false);
     var result = new Result(TaskEnv.Current);
     _log.Debug("setting up whendone");
     result.WhenDone(r => {
         _log.Debug("whendone called");
         resetEvent.Set();
     });
     result.Return();
     resetEvent.WaitOne();
     Assert.IsTrue(Wait.For(() => state.IsDisposed, TimeSpan.FromSeconds(10)));
 }
Exemplo n.º 5
0
        private Yield HandleInvoke(Action<string> activity, Plug plug, string verb, XUri uri, DreamMessage request, Result<DreamMessage> response)
        {
            Result<IAsyncResult> async;

            // remove internal headers
            request.Headers.DreamTransport = null;

            // set request headers
            request.Headers.Host = uri.Host;
            if(request.Headers.UserAgent == null) {
                request.Headers.UserAgent = "Dream/" + DreamUtil.DreamVersion;
            }

            // add cookies to request
            if(request.HasCookies) {
                request.Headers[DreamHeaders.COOKIE] = DreamCookie.RenderCookieHeader(request.Cookies);
            }

            // check if we can pool the request with an existing one
            if((plug.Credentials == null) && StringUtil.ContainsInvariantIgnoreCase(verb, "GET")) {

                // create the request hashcode
                StringBuilder buffer = new StringBuilder();
                buffer.AppendLine(uri.ToString());
                foreach(KeyValuePair<string, string> header in request.Headers) {
                    buffer.Append(header.Key).Append(": ").Append(header.Value).AppendLine();
                }
                Guid hash = new Guid(StringUtil.ComputeHash(buffer.ToString()));

                // check if an active connection exists
                Result<DreamMessage> relay = null;
                lock(_requests) {
                    List<Result<DreamMessage>> pending;
                    if(_requests.TryGetValue(hash, out pending)) {
                        relay = new Result<DreamMessage>(response.Timeout);
                        pending.Add(relay);
                    } else {
                        pending = new List<Result<DreamMessage>>();
                        pending.Add(response);
                        _requests[hash] = pending;
                    }
                }

                // check if we're pooling a request
                if(relay != null) {

                    // wait for the relayed response
                    yield return relay;
                    response.Return(relay);
                    yield break;
                } else {

                    // NOTE (steveb): we use TaskEnv.Instantaneous so that we don't exit the current stack frame before we've executed the continuation;
                    //                otherwise, we'll trigger an exception because our result object may not be set.

                    // create new handler to multicast the response to the relays
                    response = new Result<DreamMessage>(response.Timeout, TaskEnv.Instantaneous);
                    response.WhenDone(_ => {
                        List<Result<DreamMessage>> pending;
                        lock(_requests) {
                            _requests.TryGetValue(hash, out pending);
                            _requests.Remove(hash);
                        }

                        // this check should never fail!
                        if(response.HasException) {

                            // send the exception to all relays
                            foreach(Result<DreamMessage> result in pending) {
                                result.Throw(response.Exception);
                            }
                        } else {
                            DreamMessage original = response.Value;

                            // only memorize the message if it needs to be cloned
                            if(pending.Count > 1) {

                                // clone the message to all relays
                                foreach(Result<DreamMessage> result in pending) {
                                    result.Return(original.Clone());
                                }
                            } else {

                                // relay the original message
                                pending[0].Return(original);
                            }
                        }
                    });
                }
            }

            // initialize request
            activity("pre WebRequest.Create");
            var httpRequest = (HttpWebRequest)WebRequest.Create(uri.ToUri());
            activity("post WebRequest.Create");
            httpRequest.Method = verb;
            httpRequest.Timeout = System.Threading.Timeout.Infinite;
            httpRequest.ReadWriteTimeout = System.Threading.Timeout.Infinite;

            // Note (arnec): httpRequest AutoRedirect is disabled because Plug is responsible for it (this allows redirects to follow
            // the appropriate handler instead staying stuck in http end point land
            httpRequest.AllowAutoRedirect = false;

            // Note from http://support.microsoft.com/kb/904262
            // The HTTP request is made up of the following parts:
            // 1.   Sending the request is covered by using the HttpWebRequest.Timeout method.
            // 2.   Getting the response header is covered by using the HttpWebRequest.Timeout method.
            // 3.   Reading the body of the response is not covered by using the HttpWebResponse.Timeout method. In ASP.NET 1.1 and in later versions, reading the body of the response
            //      is covered by using the HttpWebRequest.ReadWriteTimeout method. The HttpWebRequest.ReadWriteTimeout method is used to handle cases where the response headers are
            //      retrieved in a timely manner but where the reading of the response body times out.

            httpRequest.KeepAlive = false;
            httpRequest.ProtocolVersion = System.Net.HttpVersion.Version10;

            // TODO (steveb): set default proxy
            //httpRequest.Proxy = WebProxy.GetDefaultProxy();
            //httpRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;

            // set credentials
            if(plug.Credentials != null) {
                httpRequest.Credentials = plug.Credentials;
                httpRequest.PreAuthenticate = true;
            } else if(!string.IsNullOrEmpty(uri.User) || !string.IsNullOrEmpty(uri.Password)) {
                httpRequest.Credentials = new NetworkCredential(uri.User ?? string.Empty, uri.Password ?? string.Empty);
                httpRequest.PreAuthenticate = true;

                // Note (arnec): this manually adds the basic auth header, so it can authorize
                // in a single request without requiring challenge
                var authbytes = Encoding.ASCII.GetBytes(string.Concat(uri.User ?? string.Empty, ":", uri.Password ?? string.Empty));
                var base64 = Convert.ToBase64String(authbytes);
                httpRequest.Headers.Add(DreamHeaders.AUTHORIZATION, "Basic " + base64);
            }

            // add request headres
            foreach(KeyValuePair<string, string> header in request.Headers) {
                HttpUtil.AddHeader(httpRequest, header.Key, header.Value);
            }

            // send message stream
            if((request.ContentLength != 0) || (verb == Verb.POST)) {
                async = new Result<IAsyncResult>();
                try {
                    activity("pre BeginGetRequestStream");
                    httpRequest.BeginGetRequestStream(async.Return, null);
                    activity("post BeginGetRequestStream");
                } catch(Exception e) {
                    activity("pre HandleResponse 1");
                    if(!HandleResponse(activity, e, null, response)) {
                        _log.ErrorExceptionMethodCall(e, "HandleInvoke@BeginGetRequestStream", verb, uri);
                        try {
                            httpRequest.Abort();
                        } catch { }
                    }
                    yield break;
                }
                activity("pre yield BeginGetRequestStream");
                yield return async.Catch();
                activity("post yield BeginGetRequestStream");

                // send request
                Stream outStream;
                try {
                    activity("pre EndGetRequestStream");
                    outStream = httpRequest.EndGetRequestStream(async.Value);
                    activity("pre EndGetRequestStream");
                } catch(Exception e) {
                    activity("pre HandleResponse 2");
                    if(!HandleResponse(activity, e, null, response)) {
                        _log.ErrorExceptionMethodCall(e, "HandleInvoke@EndGetRequestStream", verb, uri);
                        try {
                            httpRequest.Abort();
                        } catch { }
                    }
                    yield break;
                }

                // copy data
                using(outStream) {
                    Result<long> res;
                    activity("pre yield CopyStream");
                    yield return res = request.ToStream().CopyTo(outStream, request.ContentLength, new Result<long>(TimeSpan.MaxValue)).Catch();
                    activity("post yield CopyStream");
                    if(res.HasException) {
                        activity("pre HandleResponse 3");
                        if(!HandleResponse(activity, res.Exception, null, response)) {
                            _log.ErrorExceptionMethodCall(res.Exception, "*****@*****.**", verb, uri);
                            try {
                                httpRequest.Abort();
                            } catch { }
                        }
                        yield break;
                    }
                }
            }
            request = null;

            // wait for response
            async = new Result<IAsyncResult>(response.Timeout);
            try {
                activity("pre BeginGetResponse");
                httpRequest.BeginGetResponse(async.Return, null);
                activity("post BeginGetResponse");
            } catch(Exception e) {
                activity("pre HandleResponse 4");
                if(!HandleResponse(activity, e, null, response)) {
                    _log.ErrorExceptionMethodCall(e, "HandleInvoke@BeginGetResponse", verb, uri);
                    try {
                        httpRequest.Abort();
                    } catch { }
                }
                yield break;
            }
            activity("pre yield BeginGetResponse");
            yield return async.Catch();
            activity("post yield BeginGetResponse");

            // check if an error occurred
            if(async.HasException) {
                activity("pre HandleResponse 5");
                if(!HandleResponse(activity, async.Exception, null, response)) {
                    _log.ErrorExceptionMethodCall(async.Exception, "HandleInvoke@BeginGetResponse", verb, uri);
                    try {
                        httpRequest.Abort();
                    } catch { }
                }
                yield break;
            } else {

                // handle response
                try {
                    HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(async.Value);
                    activity("pre HandleResponse 6");
                    if(!HandleResponse(activity, null, httpResponse, response)) {
                        try {
                            httpRequest.Abort();
                        } catch { }
                    }
                } catch(Exception e) {
                    activity("pre HandleResponse 7");
                    if(!HandleResponse(activity, e, null, response)) {
                        _log.ErrorExceptionMethodCall(e, "HandleInvoke@EndGetResponse", verb, uri);
                        try {
                            httpRequest.Abort();
                        } catch { }
                    }
                    yield break;
                }
            }
        }