Reputation: 10124
I'm setting a cookie in Flask like follows :
response.set_cookie('notice', value = json.dumps(someObject), max_age=None)
If i print json.dumps(someObject) on the server I get :
{"message": "hello", "type": "success"}
On the client side it becomes :
"{\"message\": \"hello\"\054 \"type\": \"success\"}"
I want to decode it on a javascript client what format is it exactly ?
I'd like to decode it and pass it to angular.fromJson(), it looks like there is at least unescaping (of the the \") to do, but I'm surprize to see \054 (the octal ASCII code for the comma)
Upvotes: 4
Views: 4818
Reputation: 31166
Python - need to decode on reading using urllib
if "sensorcookie" in request.cookies:
ck = json.loads(urllib.parse.unquote(request.cookies.get("sensorcookie")))
else:
ck = {}
tz = "undefined" if os.environ.get("TZ") is None else os.environ.get("TZ")
ck = {"HOST_ENV":os.environ["HOST_ENV"], "TZ": tz, **ck}
resp.set_cookie("sensorcookie", json.dumps(ck))
Javascript - using js-cookies. Have to replace escaped commas and triple backslashes before JSON parse. I've constructed a wrapper "module" to do this
// https://yuiblog.com/blog/2007/06/12/module-pattern/
var sensorcookies = function () {
const defaultopts = {righttoleft:true, graphtype:"line", freq:"", pointsslider:100, pointstoplot:20, tickinterval:1, TZ:""};
const name = "sensorcookie";
function convertraw() {
var t = Cookies.get(name);
return (!t) ? defaultopts : { ...defaultopts, ...JSON.parse(t.replace(/\\054/g, ",").replace(/\\/g, ""))};
}
function privateget(attr) {
var opts = convertraw();
return opts[attr];
}
function privateset(attr, value) {
var opts = convertraw();
opts[attr] = value;
Cookies.set(name, JSON.stringify(opts));
}
// waitforcookies();
return {
version: "1.0",
get: (attr) => { return privateget(attr);},
set: (attr, value) => { privateset(attr, value);},
log: () => { Cookies.set(name, convertraw()); console.log(JSON.stringify(convertraw()));},
val: () => { return convertraw(); }
};
}(); // NB parens so makes it feel like a "module"
Upvotes: 0
Reputation: 1537
Dealing with the same issue today, but it seems the facts on the ground have changed.
First of all, sending the cookie back is as simple as:
cookie_str = json.dumps(mydictionary, separators=(',', ':'))
resp.set_cookie('cookiename', cookie_str, None, None, '/')
On the Javascript side, in browser, I read the cookie as follows using the js-cookies project:
var cookie2 = Cookies.noConflict();
var cookiejs = cookie2.getJSON('cookiename');
var one = ca.field1;
var two = ca.field2;
It does appear that the curly's are not getting escaped properly in my case. As a result, I have to find and replace the curley's with escaped versions \{
and \}
. However, after that, instead of using getJSON, I had to resort to jquery's $.parseJSON() function, which returns a usable json object.
Still haven't figured out how to get the cookie json string to behave correctly without re-escaping the curley's on the javascript side. The escaping and jquery method is a little hacky... but it works.
Also I'm using Zappa-Flask in AWS Lambda, not sure if that is messing up my cookie.
Upvotes: 0
Reputation: 1121864
The cookie value is quoted by the Werkzeug library to be safe for use in Cookie
headers; this includes quoting any commas, semicolons, double quotes and backslashes:
cookie_quoting_map = {
b',' : b'\\054',
b';' : b'\\073',
b'"' : b'\\"',
b'\\' : b'\\\\',
}
Anything else outside of letters, digits and the characters !#%&'~_`><@,:/$*+-.^|)(?}{=
is encoded to an octal codepoint as well. If there are any escaped values in the cookie, the whole cookie is also surrounded by double quotes.
If you need access to the cookie value in JavaScript, you'll have to decode this again. Values that start with a slash and 3 digits are octal values; a String.replace()
call should do:
function decode_flask_cookie(val) {
if (val.indexOf('\\') === -1) {
return val; // not encoded
}
val = val.slice(1, -1).replace(/\\"/g, '"');
val = val.replace(/\\(\d{3})/g, function(match, octal) {
return String.fromCharCode(parseInt(octal, 8));
});
return val.replace(/\\\\/g, '\\');
}
Demo:
> // recreate properly escaped value
> var cookie = "\"{\\\"message\\\": \\\"hello\\\"\\054 \\\"type\\\": \\\"success\\\"}\""
> cookie
""{\"message\": \"hello\"\054 \"type\": \"success\"}""
> decode_flask_cookie(cookie)
"{"message": "hello", "type": "success"}"
> JSON.parse(decode_flask_cookie(cookie))
Object {message: "hello", type: "success"}
Upvotes: 6