Setting and reading cookies
Picos can be used with a variety of event generators. When the event generator is a browser, it is useful for a pico to be able to set a cookie in the browser. Then, rules reacting to later events, and queries responding to requests from that same browser will have access to the value of the cookie.
This is one way that picos can pass information from one to another. For example, a pico which does subscriptions might set its wellKnown_Tx
channel id in a cookie. Then, events sent to other picos from the same browser would make that information be, well, well known. Such other picos would then be in a position to propose subscriptions to the first pico using that channel id.
experimental feature in version 1.0.11
This feature is recent, so you will need to do a git pull
after updating to version 1.0.10, or wait until the feature has been included in version 1.0.11 (or higher)
Setting a cookie
Here is a KRL rule which causes a cookie to be set in the browser which, as an event generator, sends a matching event:
rule set_cookie { select when cookie needed pre { eci = wrangler:channels(["wellKnown_Rx","Tx_Rx"]).head(){"id"} || meta:eci; } every { send_directive("_cookie",{"cookie": <<wellKnown_Rx=#{eci}; Path=/sky>>}); } }
Note that this assumes (line 4) that the set_cookie
rule is part of a ruleset which uses io.picolabs.wrangler
as a module (see below). Line 4 computes an ECI which is either the well known one for subscriptions (if that ruleset is installed in this pico), or the ECI used to send the cookie:needed
event (see meta, the library).
Line 7 sends a directive with a special name, _cookie
. At the conclusion of event processing, the pico engine interprets this directive, and will include the appropriate HTTP "Set-Cookie" header. Upon receipt of the response including this header, a browser will remember the cookie name and value, for future interaction with the same pico engine hostname.
The use of the wrangler module would be indicated in the meta
section of the ruleset by:
use module io.picolabs.wrangler alias wrangler
Conditional setting of a cookie
An alternative, which sets a cookie for wellKnown_Rx
only when the pico actually does subscriptions would be:
rule set_cookie { select when cookie needed pre { eci = wrangler:channels(["wellKnown_Rx","Tx_Rx"]).head(){"id"}; } if eci then every { send_directive("_cookie",{"cookie": <<wellKnown_Rx=#{eci}; Path=/sky>>}); } }
Reading a cookie
Every event includes an attribute, named _headers
, which is all of the HTTP headers (available only when the event generator is a browser or other user agent communicating over HTTP). Similarly, in such cases every query will include an argument named _headers
giving the function access to the HTTP headers.
Here is a KRL function which produces a map from cookie names to values:
cookies = function(_headers) { arg = event:attr("_headers") || _headers; arg{"cookie"}.isnull() => {} | arg{"cookie"} //.klog("cookie") .split("; ") //.klog("split") .map(function(v){v.split("=")}) //.klog("map1") .collect(function(v){v.head()}) //.klog("collect") .map(function(v){v.head()[1]}) //.klog("map2") }
Line 1 mentions the argument name _headers
for the case in which this function is called directly through a /sky/cloud
query.
Line 2 binds the name arg
to either the event attribute named _headers
or the argument named _headers
so that, whether it is called via a query or from a rule which is reacting to an event, it will be a map of the HTTP headers.
If the HTTP headers do not exist, or they do not contain an entry for cookie, then this function returns an empty map, meaning there are no cookies available (line 3).
Otherwise the function continues with a chain of operators (lines 4-8) computing the desired map from cookie names to values.
Sample output from the klog calls suggested in the comments, for a particular function invocation shown here:
cookie "wellKnown_Rx=4MVMwL7AsyqRfSRjGcuruQ; sessionid=38afes7a8" split ["wellKnown_Rx=4MVMwL7AsyqRfSRjGcuruQ","sessionid=38afes7a8"] map1 [["wellKnown_Rx","4MVMwL7AsyqRfSRjGcuruQ"],["sessionid","38afes7a8"]] collect {"wellKnown_Rx":[["wellKnown_Rx","4MVMwL7AsyqRfSRjGcuruQ"]],"sessionid":[["sessionid","38afes7a8"]]} map2 {"wellKnown_Rx":"4MVMwL7AsyqRfSRjGcuruQ","sessionid":"38afes7a8"}
This chain of operators is very similar to the one used to decode WWW form-encoded parameters except that cookies are separated by a semi-colon and space.
Reading a cookie using /sky/cloud
Copyright Picolabs | Licensed under Creative Commons.