Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reading duplicated cookies #60

Open
a-x- opened this issue Sep 5, 2016 · 11 comments · May be fixed by #108
Open

Reading duplicated cookies #60

a-x- opened this issue Sep 5, 2016 · 11 comments · May be fixed by #108

Comments

@a-x-
Copy link

a-x- commented Sep 5, 2016

my bro sends weird cookies (after deleting and installing cookies again):

user_id=; session_id=; session_id=XXXXXXX; user_id=6

cookie-parser parse e.g. user_id as a ''

but expected reading a latest value of each cookie

expressjs/cookie-parser#31

@dougwilson
Copy link
Contributor

Hi @a-x-, that is correct, since the interface of this module only provides one value per name, so the first occurrence is chosen. I guess we can either completely change the interface to allow you to get all the values for a given name or we can change which one we can get if you can provide a link to some specification that says which occurrence we should actually be reading (the first or the last in your example).

It is perfectly legal for a web browser to send a Cookie header with multiple occurrences of the same cookie name, because a browser can have multiple overlapping cookies for the same page with the same name, differing on some attribute like path, httpOnly, or similar, so it isn't clear if you have two over-lapping cookies which to use.

Having a cookie with an empty value is a perfectly value cookie, so simply skipping over those a preferring ones with values is not on option, unless you know of a specification that says servers should be doing this.

@a-x-
Copy link
Author

a-x- commented Sep 6, 2016

oh, thank you

it's a kind of shit:

Although cookies are serialized linearly in the Cookie header,
   servers SHOULD NOT rely upon the serialization order.  In particular,
   if the Cookie header contains two cookies with the same name (e.g.,
   that were set with different Path or Domain attributes), servers
   SHOULD NOT rely upon the order in which these cookies appear in the
   header.

servers SHOULD NOT rely upon the order in which these cookies appear in the header

https://tools.ietf.org/html/rfc6265#section-4.2.2


So, there I see the solution.

Can you add into your cookie parser conf something like «same keys order policy»?

e.g.: { sameKeysPolicy: 'first' || 'last' || 'collection' }

@a-x-
Copy link
Author

a-x- commented Sep 6, 2016

You can use the { sameKeysPolicy: 'first' } for compatibility reasons.
And, as I think, you should recommend using the { sameKeysPolicy: 'last' } for new users

@dougwilson
Copy link
Contributor

Cool, feel fee to make a PR. If you at foing to recommend "last" in the documentation, you'll probably need to explain why one should choose "last" over "first", especially since that spec says do not rely on order, so it says doing either is equally bad, neither is recommended.

Perhaps it would be better to rewrite the interface to allow retrieval of all the cookies?

@demurgos
Copy link

demurgos commented Nov 13, 2017

Hi,
Could I suggest an alternative solution?
Parsing the cookies could return an array of parsed cookies instead of a dictionary from names to sometimes cookies/sometimes collections of cookies.
This could even return an ES6 Set object. This is the model that is the closest to the RFC.

It could be a method with another name or an option.

@yvele
Copy link

yvele commented Feb 25, 2020

Any workaround or alternative package to read multiple cookies (having the same key)?

Edit:

@SachinShekhar
Copy link

@yvele

Any workaround or alternative package to read multiple cookies (having the same key)?

Have a look at my PR: #108

@eggers
Copy link

eggers commented Mar 21, 2022

As a warning, if you are specifying first/last, different browsers behave differently I was seeing different behavior for chrome & safari sending the same cookies in a different order.

@jbuhacoff
Copy link

I noticed the description of the new feature says "All values will be put into an array." but the implementation actually returns either a string if it's a single value or an array if it's multiple values.

When a multi-valued cookies setting is enabled, it might be more convenient to always return an array (even for one value) instead of either a string or an array, because the application is already expecting that there could be multiple values and be ready to handle them. Instead of having to check whether it got a string or an array, the application could just start processing the array.

For example, in the case of receiving some empty cookie values:

let session_id = null;
const cookies = cookie.parse(...);
if (typeof cookies.session_id === 'string') {
    if (cookies.session_id) { session_id = cookies.session_id }
} else if (Array.isArray(cookies.session_id)) {
    const nonempty = cookies.session_id.filter((item) => item.trim().length > 0);
    if (nonempty.length > 0) { session_id = nonempty[0]; } // arbitrary choice
}
if (!session_id) { /* no cookie */ }

But if the value is always an array (when multi-valued setting is enabled), there are less cases when checking the result:

let session_id = null;
const cookies = cookie.parse(...);
if (cookies.session_id) {
    const nonempty = cookies.session_id.filter((item) => item.trim().length > 0);
    if (nonempty.length > 0) { session_id = nonempty[0]; } // arbitrary choice
}
if (!session_id) { /* no cookie */ }

The difference becomes even greater if there are other things to check, like if the value is a valid cookie value. Because then you have to either 1) check it in the string section and in the array section, which results in a little duplication, or 2) to avoid the duplication you need to check if the value is string or array, convert string to [string], then process the array.

Even the PR shows this issue when preparing the output:

// only assign once unless multiValuedCookies is true
    if (undefined == obj[key]) {
      obj[key] = tryDecode(val, dec);
    } else if (opt.multiValuedCookies) {
      if (typeof obj[key] === 'string') {
        obj[key] = [obj[key], tryDecode(val, dec)];
      } else {
        obj[key].push(tryDecode(val, dec));
      }
    }

But if multi-valued cookies are always in an array, it could be like this instead:

// only assign once unless multiValuedCookies is true
    if (opt.multiValuedCookies) {
      if (undefined == obj[key]) {
         obj[key] = [];
      }
      obj[key].push(tryDecode(val, dec));
    } else if (undefined == obj[key]) {
      obj[key] = tryDecode(val, dec);
    }

It's one less level of nested if's, and if you write in modern javascript and transpile to backward-compatible javascript, it's even cleaner:

// only assign once unless multiValuedCookies is true
    if (opt.multiValuedCookies) {
      obj[key] ??= [];
      obj[key].push(tryDecode(val, dec));
    } else if (undefined == obj[key]) {
      obj[key] = tryDecode(val, dec);
    }

@hanvyj

This comment was marked as spam.

@MatthewPattell
Copy link

Ok, we fork and merge #108 PR and publish package on @lomray/cookie. We really need this feature and can't wait.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants