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

Can't read set-cookie headers from backend server properly #75

Closed
AfzalH opened this issue May 19, 2020 · 7 comments
Closed

Can't read set-cookie headers from backend server properly #75

AfzalH opened this issue May 19, 2020 · 7 comments

Comments

@AfzalH
Copy link

AfzalH commented May 19, 2020

I'm using apollo server as an orchestration layer which connects and gets data from other backend servers.
I need to forward the set-cookie headers from backend server. Works well if there's one set-cookie header but if there are multiple there's a problem.

const { RESTDataSource } = require("apollo-datasource-rest");

class MyDataSource extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'https://example.com';
  }

  didReceiveResponse(response, _request) {
    // here response.header is an Iterable and get method gives a string joining multiple header
    let cookies = response.headers.get("set-cookie");
    console.log(cookies);
    return super.didReceiveResponse(response, _request);
  }

  async resolverFunc(body) {
    // ...
  }
}

return type for response.headers.get is string | null but in this case it should be array.
if we console log response.headers we see that inside Symbol map the set-cookie header is actually an array but gets converted to string when trying to get the value using the get method.
Couldn't find a way to get the original array.

@maapteh
Copy link

maapteh commented Jan 27, 2021

Hi, this is more about servers in general right?

Im doing the following in our http middleware proxy in some totally other server code but i think it should help you looking how to proceed. And its simple :)

const SetCookies = response.headers.get("set-cookie")

if (SetCookies) {
    response.setHeader("set-cookie", Array.isArray(SetCookies) ? cookies : SetCookies.split(','));
}

@AfzalH
Copy link
Author

AfzalH commented Jan 27, 2021

this is unpredictable as cookie value may contain ,
edit: not cookie value, I mean the set-cookie header might contain ,

@maapteh
Copy link

maapteh commented Jan 27, 2021 via email

@AfzalH
Copy link
Author

AfzalH commented Jan 27, 2021

Read a little bit further and you'll see there's expires=DATE where date contains a comma... so couple cookies joined with a , having optional expire value will case a problem
NAME=VALUE
This string is a sequence of characters excluding semi-colon, comma and white space. If there is a need to place such data in the name or value, some encoding method such as URL style %XX encoding is recommended, though no encoding is defined or required.
This is the only required attribute on the Set-Cookie header.

expires=DATE
The expires attribute specifies a date string that defines the valid life time of that cookie. Once the expiration date has been reached, the cookie will no longer be stored or given out.
The date string is formatted as:

Wdy, DD-Mon-YYYY HH:MM:SS GMT

Of course it can be solved by some regex matching etc.

@maapteh
Copy link

maapteh commented Jan 28, 2021

Ah oke now you edit :) that makes my response weird indeed :)

Hi Afzal, i will debug for you, since i have the code in production :) Internally i have:

Fri%2C%2029%20Jan%202021%2020%3A15%3A48%20GMT

@cjonesdoordash
Copy link

Hey so I ran into this same issue. Conveniently enough the apollo-datasource-rest uses node-fetch under the hood, which actually has the ability to grab the all the headers of a specific key and return them as a string[].

Apollo doesn't have the method typed so you'll have to augment the types or cast it to any.

This worked for me:
response.headers.raw()['set-cookie']

@glasser glasser transferred this issue from apollographql/apollo-server Oct 21, 2022
@glasser
Copy link
Member

glasser commented Dec 9, 2022

This is unfortunately not particularly fixable in a compelling way: we've chosen to orient this package around the Fetch API but the Fetch API does not let you differentiate between "a header showed up twice" and "the same thing but joined with comma-space". (This API was designed for browsers where it explicitly cannot see Set-Cookie headers!) Making RESTDataSource work with multiple Fetch implementations is a pretty key part of the design so we can't really rely on response.headers.raw() in our general implementation.

If you're sure you're using node-fetch then you can do what @cjonesdoordash showed and use response.headers.raw(). However, if the operation ends up interacting with HTTPCache then the response will get cloned and that will fail. If it's not a GET (and you don't explicitly set ttl via cacheOptions or cacheOptionsFor) then that clone won't happen, so the @cjonesdoordash method will work fine. I suspect many Set-Cookie responses are to POSTs anyway so that should be OK?

What I'd like to do is add a test that if you send a POST (with the default node-fetch fetcher) that gets multiple set-cookie headers, you can use the raw() trick on the response. For various reasons we should finish #110 first.

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

No branches or pull requests

4 participants