public void Can_clone_xdoc_message() { var m = new DreamMessage(DreamStatus.Ok, new DreamHeaders().Add("foo", "bar"), new XDoc("doc")); m.Headers.Add("baz", "blah"); var m2 = m.Clone(); Assert.AreEqual(m.ToDocument().ToCompactString(), m2.ToDocument().ToCompactString()); Assert.AreEqual(m.Headers["foo"], m2.Headers["foo"]); Assert.AreEqual(m.Headers["baz"], m2.Headers["baz"]); }
public void Can_clone_no_content_message() { var m = new DreamMessage(DreamStatus.Ok, new DreamHeaders().Add("foo", "bar")); m.Headers.Add("baz", "blah"); var m2 = m.Clone(); Assert.AreEqual(m.ToText(), m2.ToText()); Assert.AreEqual(m.Headers["foo"], m2.Headers["foo"]); Assert.AreEqual(m.Headers["baz"], m2.Headers["baz"]); }
public void Can_clone_a_null_stream_message() { var m = new DreamMessage(DreamStatus.Ok, new DreamHeaders().Add("foo", "bar"), MimeType.TEXT, Stream.Null.Length, Stream.Null); m.Headers.Add("baz", "blah"); var m2 = m.Clone(); Assert.AreEqual(0, m2.ContentLength); Assert.AreEqual(m.ContentType.ToString(), m2.ContentType.ToString()); Assert.AreEqual(m.Headers["foo"], m2.Headers["foo"]); Assert.AreEqual(m.Headers["baz"], m2.Headers["baz"]); }
public void Can_clone_byte_message() { var m = new DreamMessage(DreamStatus.Ok, new DreamHeaders().Add("foo", "bar"), MimeType.TIFF, new byte[] { 1, 2, 3, 4 }); m.Headers.Add("baz", "blah"); var m2 = m.Clone(); Assert.AreEqual(m.ToBytes(), m2.ToBytes()); Assert.AreEqual(m.ContentType.ToString(), m2.ContentType.ToString()); Assert.AreEqual(m.Headers["foo"], m2.Headers["foo"]); Assert.AreEqual(m.Headers["baz"], m2.Headers["baz"]); }
//--- Constructors --- /// <summary> /// Create a new event from a dream message. /// </summary> /// <param name="message">Message to parse.</param> public DispatcherEvent(DreamMessage message) { // sanity check the input string[] origins = message.Headers.DreamEventOrigin; if (origins.Length == 0) { throw new DreamBadRequestException(string.Format("message must specify at least one DreamEventOrigin header")); } if (string.IsNullOrEmpty(message.Headers.DreamEventChannel)) { throw new DreamBadRequestException("message must have exactly one DreamEventChannel header"); } // parse message _message = message.Clone(); Channel = new XUri(_message.Headers.DreamEventChannel); if (!string.IsNullOrEmpty(_message.Headers.DreamEventResource)) { Resource = new XUri(_message.Headers.DreamEventResource); } List <XUri> originList = new List <XUri>(); foreach (string origin in origins) { originList.Add(new XUri(origin)); } Origins = originList.ToArray(); List <DispatcherRecipient> recipientList = new List <DispatcherRecipient>(); foreach (string recipient in _message.Headers.DreamEventRecipients) { recipientList.Add(new DispatcherRecipient(new XUri(recipient))); } Recipients = recipientList.ToArray(); List <XUri> viaList = new List <XUri>(); foreach (string via in _message.Headers.DreamEventVia) { viaList.Add(new XUri(via)); } Via = viaList.ToArray(); // attach an Id, if one does not exist Id = message.Headers.DreamEventId; if (string.IsNullOrEmpty(Id)) { Id = Guid.NewGuid().ToString(); } }
public void Can_clone_a_memory_stream_message() { var text = "blah"; var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(text); writer.Flush(); stream.Position = 0; var m = new DreamMessage(DreamStatus.Ok, new DreamHeaders().Add("foo", "bar"), MimeType.TEXT, stream.Length, stream); m.Headers.Add("baz", "blah"); _log.Debug("about to clone"); var m2 = m.Clone(); var reader = new StreamReader(m2.ToStream()); Assert.AreEqual(text, reader.ReadToEnd()); Assert.AreEqual(m.ContentType.ToString(), m2.ContentType.ToString()); Assert.AreEqual(m.Headers["foo"], m2.Headers["foo"]); Assert.AreEqual(m.Headers["baz"], m2.Headers["baz"]); }
public void Can_clone_a_memory_stream_message_that_has_been_read() { var text = "blah"; var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(text); writer.Flush(); var m = new DreamMessage(DreamStatus.Ok, new DreamHeaders().Add("foo", "bar"), MimeType.TEXT, stream.Length, stream); m.Headers.Add("baz", "blah"); var m2 = m.Clone(); var reader = new StreamReader(m2.ToStream()); Assert.AreEqual(text, reader.ReadToEnd()); Assert.AreEqual(m.ContentType.ToString(), m2.ContentType.ToString()); Assert.AreEqual(m.Headers["foo"], m2.Headers["foo"]); Assert.AreEqual(m.Headers["baz"], m2.Headers["baz"]); }
private DreamMessage MemorizeAndClone(DreamMessage request) { return request.IsCloneable ? request.Clone() : new DreamMessage(request.Status,request.Headers,request.ContentType,request.ToBytes()); }
private DreamMessage MemorizeAndClone(DreamMessage request) { return(request.IsCloneable ? request.Clone() : new DreamMessage(request.Status, request.Headers, request.ContentType, request.ToBytes())); }
//--- Constructors --- /// <summary> /// Create a new event from a dream message. /// </summary> /// <param name="message">Message to parse.</param> public DispatcherEvent(DreamMessage message) { // sanity check the input string[] origins = message.Headers.DreamEventOrigin; if(origins.Length == 0) { throw new DreamBadRequestException(string.Format("message must specify at least one DreamEventOrigin header")); } if(string.IsNullOrEmpty(message.Headers.DreamEventChannel)) { throw new DreamBadRequestException("message must have exactly one DreamEventChannel header"); } // parse message _message = message.Clone(); Channel = new XUri(_message.Headers.DreamEventChannel); if(!string.IsNullOrEmpty(_message.Headers.DreamEventResource)) { Resource = new XUri(_message.Headers.DreamEventResource); } List<XUri> originList = new List<XUri>(); foreach(string origin in origins) { originList.Add(new XUri(origin)); } Origins = originList.ToArray(); List<DispatcherRecipient> recipientList = new List<DispatcherRecipient>(); foreach(string recipient in _message.Headers.DreamEventRecipients) { recipientList.Add(new DispatcherRecipient(new XUri(recipient))); } Recipients = recipientList.ToArray(); List<XUri> viaList = new List<XUri>(); foreach(string via in _message.Headers.DreamEventVia) { viaList.Add(new XUri(via)); } Via = viaList.ToArray(); // attach an Id, if one does not exist Id = message.Headers.DreamEventId; if(string.IsNullOrEmpty(Id)) { Id = Guid.NewGuid().ToString(); } }
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 original.Memorize(new Result()).Wait(); foreach (var 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; } } }
public IEnumerator<IYield> Invoke(Plug plug, string verb, XUri uri, DreamMessage request, Result<DreamMessage> response) { MockPlug.MockInvokeDelegate callback; var match = GetBestMatch(uri); if(match.Item1 == null) { response.Return(DreamMessage.Ok(new XDoc("empty"))); yield break; } lock(_registry) { callback = _registry[match.Item1]; } yield return Async.Fork(() => callback(plug, verb, uri, request.Clone(), response), new Result(TimeSpan.MaxValue)); }