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.
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.
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.
@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.
User | Count |
---|---|
1 | |
1 | |
1 | |
1 | |
1 |