Skip to content

Reading duplicated cookies #60

Description

@a-x-

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

Activity

  1. dougwilson commented on Sep 6, 2016

    @dougwilson
    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.

  2. a-x- commented on Sep 6, 2016

    @a-x-
    Author

    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' }

  3. a-x- commented on Sep 6, 2016

    @a-x-
    Author

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

  4. dougwilson commented on Sep 6, 2016

    @dougwilson
    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?

  5. demurgos commented on Nov 13, 2017

    @demurgos

    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.

  6. yvele commented on Feb 25, 2020

    @yvele

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

    Edit:

  7. SachinShekhar commented on Jun 4, 2020

    @SachinShekhar

    @yvele

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

    Have a look at my PR: #108

  8. eggers commented on Mar 21, 2022

    @eggers

    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.

  9. jbuhacoff commented on Apr 24, 2022

    @jbuhacoff

    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);
        }
  10. hanvyj commented on Aug 8, 2022

    @hanvyj
  11. MatthewPattell commented on Jan 30, 2023

    @MatthewPattell

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions