Modify set-cookie header (add/change) in JavaScript

Not applicable

I am running into issues when trying to add and modify set-cookie headers in the response from the target server before returning to the client. I am ending up with a single set-cookie header with a comma separated list of set-cookie headers. How do I set the cookies? (part 2)

1. GET COOKIES: It took me a while to figure out how to read in and process multiple set-cookie headers using various community questions. Some worked, some did not for me.

if (context.getVariable('response.header.set-cookie.values.count')) {
    var numHeaders = response.headers['Set-Cookie'].length();
    var allCookies = [];
    for (var i=0; i<numHeaders; ++i) {
        var cookie = response.headers['Set-Cookie'][i];
        var cookie2 = !!cookie.match(/Expires=/i) ? response.headers['Set-Cookie'][++i] : null;
        var fullCookie = cookie + (cookie2 ? ', ' + cookie2 : '');
        // do stuff to the full cookie
        allCookies.push(fullCookie.replace(/\s+/, ' '));
    }
}
allCookies.push('<new cookie>');
allCookies.push('<new cookie>);

2. SET COOKIES: How do I set the cookies? I have added and modified to the response so they each end up as a separate header. Everything I have tried ends up with a single set-cookie header will them comma separated.

I have tried things like:

context.setVariable('response.header.set-cookie', allCookies.join(','));

context.setVariable('response.header.set-cookie', allCookies);

I have tried setting each one separately in a for loop, and again by adding .0, .1, ..., .index to response.header.set-cookie.

I have also tried modifying without setVariable too: response.headers['Set-Cookie'][i] = allCookies[i];

Any help would be appreciated. I am sure I could do this with normal AssignMessage policies that clear then add, but I am not familiar enough with those either to know how to deal with a list of items to set.

2 15 19.1K
15 REPLIES 15

Former Community Member
Not applicable

Hi @jasons check out this thread, should give you more insight into what you are trying to do.

Thank you. This thread was helpful, but it is missing the part I am stuck on (or so it seems to me). Once I have modified the headers how do I set them for the response? Including new headers that were not part of the original set.

Former Community Member
Not applicable

Hi @jasons can you upload your api proxy bundle?

Unfortunately, I will not be able to at least not at the moment. Perhaps this will help identify the problem.

Can you run this JavaScript on the response from a target server?

var allCookies = ['foo1=value1', 'foo2=value2'];

// code that adds these cookies to the response headers as set-cookie headers?

Expected results:

client: Chrome, developer console in network tab

request response headers should include TWO set-cookie headers.

Sorry, the follow up question that may be easily answered now?

Make a request to an API that returns 1 set-cookie header:

set-cookie: api-foo: api-value

Then execute the following JavaScript on the response from the target server:

var cookie = response.headers['Set-Cookie'][0];
cookie = cookie.replace(/api-value/, 'API-VALUE');
var allCookies = [cookie, 'foo1=value1', 'foo2=value2'];
// Set set-cookie headers for all three. ???

@jasons have you been able to figure this out? Any learnings worth sharing?

Unfortunately I did not figure it out.

Former Community Member
Not applicable

@arghya das any thoughts?

I've done some experiments.

I am able to set multiple cookies in JavaScript callouts,

example which works:

context.setVariable('response.header.set-cookie.1',
   'Oatmeal=delicious; path=/;');
context.setVariable('response.header.set-cookie.2',
   'Trefoil=donotwant; path=/;');

resulting outbound response headers:

Set-Cookie: Oatmeal=delicious; path=/;
Set-Cookie: Trefoil=donotwant; path=/;

I ran some further tests and found that if you try setting an "expires" value in the cookie, it won't work correctly:

// THIS WILL NOT WORK
context.setVariable('response.header.set-cookie.1',
   'Oatmeal=delicious; expires=Wed, 11-Jan-2017 00:00:00 GMT; path=/;');
context.setVariable('response.header.set-cookie.2',
   'Trefoil=donotwant; expires=Sat, 17-Sep-2016 00:00:00 GMT; path=/;');

resulting response header (there is only one):

Set-Cookie: Oatmeal=delicious; expires=Wed, Trefoil=donotwant; expires=Sat, 17-Sep-2016 00:00:00 GMT; path=/;

The "expires" header is a form originally proposed by netscape in the mid-90s. It was problematic and was replaced in 1997 with a "max-age" value. See RFC2109. Therefore, if you want to set multiple cookies, and you'd like to have an expiry on each one, use the max-age form.

context.setVariable('response.header.set-cookie.1',
   'Oatmeal=delicious;');
context.setVariable('response.header.set-cookie.2',
   'Trefoil=donotwant; max-age=864000; path=/;');
context.setVariable('response.header.set-cookie.3',
   'Thinmint=indifferent; domain=*.apigee.net;');

results in this:

set-cookie: Oatmeal=delicious;
set-cookie: Trefoil=donotwant; max-age=864000; path=/;
set-cookie: Thinmint=indifferent; domain=*.apigee.net;

Thanks @Dino. I tried it out before and I also think its a bug. I should have updated this thread with the findings, but thanks for doing it.

I will follow up with the team, for a possible fix.

Upon further review, I don't think it's a bug in Edge. RFC2109 says we should not use expires in Set-Cookie headers. That RFC recommends using max-age. So there is no need to modify Edge.

Internet Explorer does not implement the max-age properly: http://mrcoles.com/blog/cookies-max-age-vs-expires/

So, expiry _is_ still needed. Furthermore, why is Edge even parsing this header? It should be just a string of text to set in a header, shouldn't it?

yes, but the problem is, in every other HTTP Header, a comma is used to indicate multiple distinct values. Only in the Set-Cookie header is the comma intended to be part of a single value. This is the problem. Apigee Edge does not special case the comma in the Set-Cookie header.

@arghya das this is re: APIRT-2311 .

So yes, it is a bug in Apigee Edge. It wouldn't be a problem at all if not for IE, and its lack of support for max-age, and if it were not for servers that ignore RFC2109. Regrettably, yes, expires may still be needed.

btw, that page you cited, @Martijn Stellinga , refers to IE7 and IE8. I think we can safely ignore those browsers now, as MS no longer supports them. Even so, there is an updated testing page at http://inikulin.github.io/cookie-compat/#MOZILLA0001 showing that IE11 and IE12 (MS Edge) still do not support max-age.

I did a quick recap for this over on StackOverflow. The issue can be solved by using the date format of ANSI C's asctime. I added a quick JS port on the SO-link.

Thank you, helpful.