Skip to content

Commit dea8b62

Browse files
Merge pull request js-cookie#7 from js-cookie/raw-option-removal
Remove encoding operation and raw option
2 parents cd50945 + 4150b5e commit dea8b62

5 files changed

Lines changed: 267 additions & 160 deletions

File tree

.jshintrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"undef": true,
1010
"unused": true,
1111
"globals": {
12-
"Cookies": true,
13-
"require": true
12+
"Cookies": true
1413
}
1514
}

README.md

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ Cookies.set('name', 'value', { expires: 7, path: '/' });
4545
Read cookie:
4646

4747
```javascript
48-
Cookies.get('name'); // => "value"
48+
Cookies.get('name'); // => 'value'
4949
Cookies.get('nothing'); // => undefined
5050
```
5151

5252
Read all available cookies:
5353

5454
```javascript
55-
Cookies.get(); // => { "name": "value" }
55+
Cookies.get(); // => { name: 'value' }
5656
```
5757

5858
Delete cookie:
@@ -72,24 +72,35 @@ Cookies.remove('name', { path: '/' }); // => true
7272

7373
*Note: when deleting a cookie, you must pass the exact same path, domain and secure options that were used to set the cookie, unless you're relying on the default options that is.*
7474

75-
## Configuration
75+
## JSON
7676

77-
### raw
77+
js-cookie provides automatic JSON storage for cookies.
7878

79-
By default the cookie value is encoded/decoded when writing/reading, using `encodeURIComponent`/`decodeURIComponent`. Bypass this by setting raw to true:
79+
When creating a cookie you can pass an Array or Object Literal instead of a string in the value. If you do so, js-cookie store the string representation of the object according to the `JSON.stringify` api (if available):
8080

8181
```javascript
82-
Cookies.raw = true;
82+
Cookies.set('name', { foo: 'bar' });
8383
```
8484

85-
### json
85+
When reading a cookie with the default `Cookies.get()` api, you receive the stringified representation stored in the cookie:
8686

87-
Turn on automatic storage of JSON objects passed as the cookie value. Assumes `JSON.stringify` and `JSON.parse`:
87+
```javascript
88+
Cookies.get('name'); // => '{"foo":"bar"}'
89+
```
90+
91+
When reading a cookie with the `Cookies.getJSON()` api, you receive the parsed representation of the string stored in the cookie according to the `JSON.stringify` api (if available):
8892

8993
```javascript
90-
Cookies.json = true;
94+
Cookies.getJSON('name'); // => { foo: 'bar' }
9195
```
9296

97+
## RFC 6265
98+
99+
This project assumes [RFC 6265](http://tools.ietf.org/html/rfc6265#section-4.1.1) as a reference for everything. That said, some custom rules are applied in order to provide robustness and cross-browser compatibility.
100+
101+
### Encoding
102+
All special characters that are not allowed in the cookie-value or cookie-name in at least one supported browser are encoded/decoded with each UTF-8 Hex equivalent. Special characters that consistently work among all supported browsers are not encoded/decoded this way.
103+
93104
## Cookie Options
94105

95106
Cookie attributes can be set globally by setting properties of the `Cookies.defaults` object or individually for each call to `Cookies.set()` by passing a plain object to the options argument. Per-call options override the default options.
@@ -131,22 +142,21 @@ If true, the cookie transmission requires a secure protocol (https). Default: `f
131142
Provide a conversion function as optional last argument for reading, in order to change the cookie's value
132143
to a different representation on the fly.
133144

134-
Example for parsing a value into a number:
145+
Example for parsing the value from a cookie generated with PHP's `setcookie()` method:
135146

136147
```javascript
137-
Cookies.set('foo', '42');
138-
Cookies.get('foo', Number); // => 42
148+
// 'cookie+with+space' => 'cookie with space'
149+
Cookies.get('foo', function (value) {
150+
return value.replace(/\+/g, ' ');
151+
});
139152
```
140153

141154
Dealing with cookies that have been encoded using `escape` (3rd party cookies):
142155

143156
```javascript
144-
Cookies.raw = true;
145157
Cookies.get('foo', unescape);
146158
```
147159

148-
You can pass an arbitrary conversion function.
149-
150160
## Contributing
151161

152162
Check out the [Contributing Guidelines](CONTRIBUTING.md)

src/js.cookie.js

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,64 @@
1717
window.Cookies = factory();
1818
}
1919
}(function () {
20-
21-
var pluses = /\+/g;
22-
23-
function encode(s) {
24-
return api.raw ? s : encodeURIComponent(s);
20+
var unallowedChars = {
21+
';': '%3B',
22+
',': '%2C',
23+
'"': '%22'
24+
};
25+
var unallowedCharsInName = extend(unallowedChars, {
26+
'=': '%3D',
27+
'\t': '%09'
28+
});
29+
var unallowedCharsInValue = extend(unallowedChars, {
30+
' ': '%20'
31+
});
32+
33+
function encode (value, charmap) {
34+
for (var character in charmap) {
35+
value = value
36+
.replace(new RegExp(character, 'g'), charmap[character]);
37+
}
38+
return value;
2539
}
2640

27-
function decode(s) {
28-
return api.raw ? s : decodeURIComponent(s);
41+
function decode (value, charmap) {
42+
for (var character in charmap) {
43+
value = value
44+
.replace(new RegExp(charmap[character], 'g'), character);
45+
}
46+
return value;
2947
}
3048

31-
function stringifyCookieValue(value) {
32-
return encode(api.json ? JSON.stringify(value) : String(value));
49+
function processWrite (value) {
50+
var stringified;
51+
try {
52+
stringified = JSON.stringify(value);
53+
if (/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/.test(stringified)) {
54+
value = stringified;
55+
}
56+
} catch(e) {}
57+
return encode(String(value), unallowedCharsInValue);
3358
}
3459

35-
function parseCookieValue(s) {
36-
if (s.indexOf('"') === 0) {
60+
function processRead (value, converter, json) {
61+
if (value.indexOf('"') === 0) {
3762
// This is a quoted cookie as according to RFC2068, unescape...
38-
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
63+
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
3964
}
4065

41-
try {
42-
// Replace server-side written pluses with spaces.
43-
// If we can't decode the cookie, ignore it, it's unusable.
44-
// If we can't parse the cookie, ignore it, it's unusable.
45-
s = decodeURIComponent(s.replace(pluses, ' '));
46-
return api.json ? JSON.parse(s) : s;
47-
} catch(e) {}
48-
}
66+
value = decode(value, unallowedCharsInValue);
67+
68+
if (json) {
69+
try {
70+
value = JSON.parse(value);
71+
} catch(e) {}
72+
}
4973

50-
function read(s, converter) {
51-
var value = api.raw ? s : parseCookieValue(s);
5274
return isFunction(converter) ? converter(value) : value;
5375
}
5476

55-
function extend() {
77+
function extend () {
5678
var key, options;
5779
var i = 0;
5880
var result = {};
@@ -65,15 +87,21 @@
6587
return result;
6688
}
6789

68-
function isFunction(obj) {
90+
function isFunction (obj) {
6991
return Object.prototype.toString.call(obj) === '[object Function]';
7092
}
7193

7294
var api = function (key, value, options) {
95+
var converter;
96+
97+
if (isFunction(value)) {
98+
converter = value;
99+
value = undefined;
100+
}
73101

74102
// Write
75103

76-
if (arguments.length > 1 && !isFunction(value)) {
104+
if (arguments.length > 1 && !converter) {
77105
options = extend(api.defaults, options);
78106

79107
if (typeof options.expires === 'number') {
@@ -82,7 +110,7 @@
82110
}
83111

84112
return (document.cookie = [
85-
encode(key), '=', stringifyCookieValue(value),
113+
encode(key, unallowedCharsInName), '=', processWrite(value),
86114
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
87115
options.path ? '; path=' + options.path : '',
88116
options.domain ? '; domain=' + options.domain : '',
@@ -102,25 +130,28 @@
102130

103131
for (; i < l; i++) {
104132
var parts = cookies[i].split('='),
105-
name = decode(parts.shift()),
133+
name = decode(parts.shift(), unallowedCharsInName),
106134
cookie = parts.join('=');
107135

108136
if (key === name) {
109-
// If second argument (value) is a function it's a converter...
110-
result = read(cookie, value);
137+
result = processRead(cookie, converter, this.json);
111138
break;
112139
}
113140

114-
// Prevent storing a cookie that we couldn't decode.
115-
if (!key && (cookie = read(cookie)) !== undefined) {
116-
result[name] = cookie;
141+
if (!key) {
142+
result[name] = processRead(cookie, converter, this.json);
117143
}
118144
}
119145

120146
return result;
121147
};
122148

123149
api.get = api.set = api;
150+
api.getJSON = function() {
151+
return api.get.apply({
152+
json: true
153+
}, [].slice.call(arguments));
154+
};
124155
api.defaults = {};
125156

126157
api.remove = function (key, options) {

test/.jshintrc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@
44

55
"-W053": true,
66

7-
"extends": "../.jshintrc"
7+
"extends": "../.jshintrc",
8+
"globals": {
9+
"require": true,
10+
"unescape": true
11+
}
812
}

0 commit comments

Comments
 (0)