/// <summary> /// Create a cookie collection from a cookie header. /// </summary> /// <param name="header">Http cookie header.</param> /// <returns>Cookie collection.</returns> public static List <DreamCookie> ParseCookieHeader(string header) { List <DreamCookie> result = new List <DreamCookie>(); if (string.IsNullOrEmpty(header)) { return(result); } int index = 0; string name; string value; if (!ParseNameValue(out name, out value, header, ref index, false)) { return(result); } // check if we read the cookie version information if (string.Compare(name, "$Version", true) != 0) { // we read something else; let's forget that we read it index = 0; } while (index < header.Length - 1) { DreamCookie cookie = ParseCookie(header, ref index); if (cookie != null) { result.Add(cookie); } } return(result); }
/// <summary> /// Update the jar with a cookie. /// </summary> /// <param name="cookie">Cookie to store.</param> /// <param name="uri">Uri this cookie applies to.</param> public void Update(DreamCookie cookie, XUri uri) { List <DreamCookie> list = new List <DreamCookie>(); list.Add(cookie); Update(list, uri); }
private void Insert(DreamCookie updatedCookie, string[] segments, int depth) { // find leaf node if (depth < segments.Length) { if (_jars == null) { _jars = new Dictionary <string, DreamCookieJar>(StringComparer.OrdinalIgnoreCase); } DreamCookieJar subjar; if (!_jars.TryGetValue(segments[depth], out subjar)) { subjar = new DreamCookieJar(); _jars.Add(segments[depth], subjar); } subjar.Insert(updatedCookie, segments, depth + 1); } else { if (_cookies == null) { _cookies = new List <DreamCookie>(); } List <DreamCookie> expired = new List <DreamCookie>(); for (int i = 0; i < _cookies.Count; ++i) { DreamCookie cookie = _cookies[i]; // check if cookie is expired; if so, remove it if (cookie.Expired) { expired.Add(cookie); continue; } // TODO (steveb): we need to add support for '.' prefixes on the domain name // check if cookie matches the expired cookie if (StringUtil.EqualsInvariantIgnoreCase(cookie.Domain, updatedCookie.Domain) && StringUtil.EqualsInvariantIgnoreCase(cookie.Name, updatedCookie.Name) && (cookie.Secure == updatedCookie.Secure)) { _cookies[i] = updatedCookie; return; } } foreach (DreamCookie cookie in expired) { _cookies.Remove(cookie); } _cookies.Add(updatedCookie); } }
private void Delete(DreamCookie expiredCookie, string[] segments, int depth) { // find leaf node if (depth < segments.Length) { if (_jars != null) { DreamCookieJar subjar; if (_jars.TryGetValue(segments[depth], out subjar)) { subjar.Delete(expiredCookie, segments, depth + 1); if (subjar.IsEmpty) { _jars.Remove(segments[depth]); } } } } else if (_cookies != null) { List <DreamCookie> expired = new List <DreamCookie>(); foreach (DreamCookie cookie in _cookies) { // check if cookie is expired; if so, remove it if (cookie.Expired) { expired.Add(cookie); continue; } // TODO (steveb): we need to add support for '.' prefixes on the domain name // check if cookie matches the expired cookie if (StringUtil.EqualsInvariantIgnoreCase(cookie.Domain, expiredCookie.Domain) && StringUtil.EqualsInvariantIgnoreCase(cookie.Name, expiredCookie.Name) && (cookie.Secure == expiredCookie.Secure)) { expired.Add(cookie); continue; } } foreach (DreamCookie cookie in expired) { _cookies.Remove(cookie); } } }
//--- Class Methods --- /// <summary> /// Gets the matching cookie with the longest path from a collection of cookies. /// </summary> /// <param name="cookies">Collection of cookies.</param> /// <param name="name">Cookie name.</param> /// <returns>Matching cookie with longest path, or null if no cookies matched.</returns> public static DreamCookie GetCookie(List <DreamCookie> cookies, string name) { // TODO (steveb): consider making this an extension method // TODO (arnec): Should also match on domain/path as sanity check DreamCookie result = null; int maxPathLength = -1; foreach (DreamCookie cookie in cookies) { int length = cookie.Path == null ? 0 : cookie.Path.Length; if ((cookie.Name != name) || (length <= maxPathLength)) { continue; } maxPathLength = length; result = cookie; } return(result); }
//--- Methods --- /// <summary> /// Compare <see cref="DreamCookie"/> instances for identical content. /// </summary> /// <param name="cookie">Cookie to compare.</param> /// <returns><see langword="True"/> if the cookies are the same.</returns> public bool Equals(DreamCookie cookie) { return ToString().Equals(cookie.ToString()); }
public void With_and_without_cookiejar() { DreamCookie global = new DreamCookie("test", "global", new XUri("http://baz.com/foo")); List<DreamCookie> globalCollection = new List<DreamCookie>(); globalCollection.Add(global); Plug.GlobalCookies.Update(globalCollection, null); DreamCookie local = new DreamCookie("test", "local", new XUri("http://baz.com/foo")); List<DreamCookie> localCollection = new List<DreamCookie>(); localCollection.Add(local); DreamCookieJar localJar = new DreamCookieJar(); localJar.Update(localCollection, null); Plug globalPlug = Plug.New("http://baz.com/foo/bar"); Plug localPlug = globalPlug.WithCookieJar(localJar); Plug globalPlug2 = localPlug.WithoutCookieJar(); Assert.AreEqual("global", globalPlug.CookieJar.Fetch(globalPlug.Uri)[0].Value); Assert.AreEqual("local", localPlug.CookieJar.Fetch(localPlug.Uri)[0].Value); Assert.AreEqual("global", globalPlug2.CookieJar.Fetch(globalPlug2.Uri)[0].Value); }
public void TestCookie2() { Plug test = _host.At("test"); DreamMessage request = DreamMessage.Ok(); DreamCookie cookie = new DreamCookie("test-cookie", "test-value", null); request.Cookies.Add(cookie); DreamMessage response = test.Post(request); Assert.AreEqual(DreamStatus.Ok, response.Status); Assert.IsFalse(response.ToDocument()["body"].IsEmpty); Assert.AreEqual(cookie.ToString(), DreamCookie.ParseCookie(response.ToDocument()["headers/cookie"]).ToString()); }
//--- Constructors --- /// <summary> /// Create a new dispatcher. /// </summary> /// <param name="config">Configuration instance injected from pub sub service.</param> public Dispatcher(DispatcherConfig config) { _owner = config.ServiceUri.AsServerUri(); _serviceKeySetCookie = config.ServiceAccessCookie; _combinedSet = new PubSubSubscriptionSet(_owner, 0, _serviceKeySetCookie); _dispatchQueue = new ProcessingQueue<DispatcherEvent>(DispatchFromQueue, 10); }
//--- Methods --- /// <summary> /// Compare <see cref="DreamCookie"/> instances for identical content. /// </summary> /// <param name="cookie">Cookie to compare.</param> /// <returns><see langword="True"/> if the cookies are the same.</returns> public bool Equals(DreamCookie cookie) { return(ToString().Equals(cookie.ToString())); }
/// <summary> /// Update the jar with a collection cookies. /// </summary> /// <param name="collection">List of cookies to store.</param> /// <param name="uri">Uri cookies apply to.</param> public void Update(List <DreamCookie> collection, XUri uri) { if (collection == null) { throw new ArgumentNullException("collection"); } // process all cookies foreach (DreamCookie c in collection) { DreamCookie cookie = c; if (!string.IsNullOrEmpty(cookie.Name)) { string[] segments = null; if (uri != null) { // set default domain if needed if (string.IsNullOrEmpty(cookie.Domain)) { cookie = cookie.WithHostPort(uri.HostPort); } else if (!StringUtil.EqualsInvariantIgnoreCase(cookie.Domain, uri.HostPort)) { // domain doesn't match, ignore cookie continue; } // set default path if needed if (string.IsNullOrEmpty(cookie.Path)) { cookie = cookie.WithPath(uri.Path); segments = uri.Segments; } else { segments = cookie.Uri == null ? new string[0] : cookie.Uri.Segments; if (!uri.PathStartsWith(segments)) { // path doesn't match ignore cookie continue; } } } if (!string.IsNullOrEmpty(cookie.Path) && !string.IsNullOrEmpty(cookie.Domain)) { if (segments == null) { segments = cookie.Uri == null ? new string[0] : cookie.Uri.Segments; } if (cookie.Expired) { Delete(cookie, segments, 0); } else { Insert(cookie, segments, 0); } } } } }
//--- Constructors --- /// <summary> /// Create a new subscription set. /// </summary> /// <param name="owner">Owner uri.</param> /// <param name="version">Version serial number.</param> /// <param name="cookie">Pub sub location access cookie.</param> /// <param name="childSubscriptions">Subscriptions.</param> public PubSubSubscriptionSet(XUri owner, long version, DreamCookie cookie, params PubSubSubscription[] childSubscriptions) { Owner = owner; Version = version; Dictionary<string, PubSubSubscription> subs = new Dictionary<string, PubSubSubscription>(); foreach(var sub in childSubscriptions) { foreach(var channel in sub.Channels) { if(channel.Scheme == "pubsub") { // pubsub scheme is for PubSubService internal use only, so it should never be aggregated continue; } XUri[] resources = (sub.Resources == null || sub.Resources.Length == 0) ? new XUri[] { null } : sub.Resources; foreach(XUri resource in resources) { PubSubSubscription combo; string key = channel + ":" + resource; subs.TryGetValue(key, out combo); subs[key] = PubSubSubscription.MergeForChannelAndResource(channel, resource, this, cookie, sub, combo); } } } Subscriptions = new PubSubSubscription[subs.Count]; subs.Values.CopyTo(Subscriptions, 0); MaxFailures = MAX_FAILURES; }
/// <summary> /// Update the jar with a cookie. /// </summary> /// <param name="cookie">Cookie to store.</param> /// <param name="uri">Uri this cookie applies to.</param> public void Update(DreamCookie cookie, XUri uri) { List<DreamCookie> list = new List<DreamCookie>(); list.Add(cookie); Update(list, uri); }
private void Delete(DreamCookie expiredCookie, string[] segments, int depth) { // find leaf node if(depth < segments.Length) { if(_jars != null) { DreamCookieJar subjar; if(_jars.TryGetValue(segments[depth], out subjar)) { subjar.Delete(expiredCookie, segments, depth + 1); if(subjar.IsEmpty) { _jars.Remove(segments[depth]); } } } } else if(_cookies != null) { List<DreamCookie> expired = new List<DreamCookie>(); foreach(DreamCookie cookie in _cookies) { // check if cookie is expired; if so, remove it if(cookie.Expired) { expired.Add(cookie); continue; } // TODO (steveb): we need to add support for '.' prefixes on the domain name // check if cookie matches the expired cookie if(StringUtil.EqualsInvariantIgnoreCase(cookie.Domain, expiredCookie.Domain) && StringUtil.EqualsInvariantIgnoreCase(cookie.Name, expiredCookie.Name) && (cookie.Secure == expiredCookie.Secure)) { expired.Add(cookie); continue; } } foreach(DreamCookie cookie in expired) { _cookies.Remove(cookie); } } }
private void Insert(DreamCookie updatedCookie, string[] segments, int depth) { // find leaf node if(depth < segments.Length) { if(_jars == null) { _jars = new Dictionary<string, DreamCookieJar>(StringComparer.OrdinalIgnoreCase); } DreamCookieJar subjar; if(!_jars.TryGetValue(segments[depth], out subjar)) { subjar = new DreamCookieJar(); _jars.Add(segments[depth], subjar); } subjar.Insert(updatedCookie, segments, depth + 1); } else { if(_cookies == null) { _cookies = new List<DreamCookie>(); } List<DreamCookie> expired = new List<DreamCookie>(); for(int i = 0; i < _cookies.Count; ++i) { DreamCookie cookie = _cookies[i]; // check if cookie is expired; if so, remove it if(cookie.Expired) { expired.Add(cookie); continue; } // TODO (steveb): we need to add support for '.' prefixes on the domain name // check if cookie matches the expired cookie if(StringUtil.EqualsInvariantIgnoreCase(cookie.Domain, updatedCookie.Domain) && StringUtil.EqualsInvariantIgnoreCase(cookie.Name, updatedCookie.Name) && (cookie.Secure == updatedCookie.Secure)) { _cookies[i] = updatedCookie; return; } } foreach(DreamCookie cookie in expired) { _cookies.Remove(cookie); } _cookies.Add(updatedCookie); } }
/// <summary> /// Create a subscription from a subscription document. /// </summary> /// <param name="sub">Subscription document.</param> /// <param name="owner">Owning set.</param> public PubSubSubscription(XDoc sub, PubSubSubscriptionSet owner) { Owner = owner; // sanity check the input XDoc channels = sub["channel"]; if(channels.IsEmpty) { throw new ArgumentException("<subscription> must have at least one <channel>"); } XDoc filter = sub["filter"]; if(filter.ListLength > 1) { throw new ArgumentException("<subscription> must have zero or one <filter>"); } XDoc proxy = sub["uri.proxy"]; if(proxy.ListLength > 1) { throw new ArgumentException("<subscription> must have zero or one <uri.proxy>"); } XDoc recipients = sub["recipient"]; if(recipients.IsEmpty) { throw new ArgumentException("<subscription> must have at least one valid <recipient>"); } if(recipients.ListLength > 1 && proxy.ListLength == 0) { throw new ArgumentException("<subscription> must include <uri.proxy> if there is more than one <recipient>"); } // create our internal representation try { Id = sub["@id"].Contents; if(string.IsNullOrEmpty(Id)) { Id = Guid.NewGuid().ToString(); } XDoc cookie = sub["set-cookie"]; if(!cookie.IsEmpty) { Cookie = DreamCookie.ParseSetCookie(cookie); } List<XUri> channelList = new List<XUri>(); foreach(XDoc c in channels) { channelList.Add(c.AsUri); } Channels = channelList.ToArray(); List<XUri> resourceList = new List<XUri>(); foreach(XDoc r in sub["uri.resource"]) { resourceList.Add(r.AsUri); } Resources = resourceList.ToArray(); if(proxy.IsEmpty) { Destination = new DispatcherRecipient(recipients).Uri; } else { Destination = proxy.AsUri; _isProxy = true; } List<DispatcherRecipient> recipientList = new List<DispatcherRecipient>(); foreach(XDoc recipient in recipients) { recipientList.Add(new DispatcherRecipient(recipient)); } Recipients = recipientList.ToArray(); } catch(Exception e) { throw new ArgumentException("Unable to parse subscription: " + e.Message, e); } }
//--- Class Methods --- /// <summary> /// Merge two subscriptions on matchine channel and resource. /// </summary> /// <param name="channel">Common channel.</param> /// <param name="resource">Common resource.</param> /// <param name="owner">Common owner.</param> /// <param name="cookie">Subscription set cookie.</param> /// <param name="first">First subscription to merge.</param> /// <param name="second">Second subscription to merge.</param> /// <returns></returns> public static PubSubSubscription MergeForChannelAndResource(XUri channel, XUri resource, PubSubSubscriptionSet owner, DreamCookie cookie, PubSubSubscription first, PubSubSubscription second) { return new PubSubSubscription(channel, resource, owner, cookie, first, second); }
//--- Constructors --- private PubSubSubscription(XUri channel, XUri resource, PubSubSubscriptionSet owner, DreamCookie cookie, PubSubSubscription first, PubSubSubscription second) { if(channel == null) { throw new ArgumentNullException("channel"); } Channels = new[] { channel }; Resources = resource == null ? new XUri[0] : new[] { resource }; Id = Guid.NewGuid().ToString(); Owner = owner; Destination = Owner.Owner.At("publish"); Cookie = cookie; Recipients = ArrayUtil.Union(first.Recipients, (second == null) ? new DispatcherRecipient[0] : second.Recipients); _isProxy = true; }
public DreamMessage SyncDreamCookiesNoAttr( DreamCookie x ) { return Response(new XDoc("r").Elem("x", x.Value)); }
//--- Constructors --- /// <summary> /// Create a new dispatcher. /// </summary> /// <param name="config">Configuration instance injected from pub sub service.</param> /// <param name="queueRepository">Factory for dispatch queues used by persisted (i.e. expiring) subscriptions</param> public Dispatcher(DispatcherConfig config, IPubSubDispatchQueueRepository queueRepository) { _queueRepository = queueRepository; _owner = config.ServiceUri.AsServerUri(); _serviceKeySetCookie = config.ServiceAccessCookie; _combinedSet = new PubSubSubscriptionSet(_owner, 0, _serviceKeySetCookie); _dispatchQueue = new ProcessingQueue<DispatcherEvent>(DispatchFromQueue, 10); _defaultQueue = new ImmediatePubSubDispatchQueue(TryDispatchItem); var pubSubSubscriptionSets = queueRepository.GetUninitializedSets(); // Note (arnec): only invoking lock here, so that RegisterSet and Update don't do it over and over lock(_subscriptionsByOwner) { foreach(var set in pubSubSubscriptionSets) { RegisterSet(set, true); } Update(); } queueRepository.InitializeRepository(TryDispatchItem); }