launchdarkly / js-client-sdk

LaunchDarkly Client-side SDK for Browser JavaScript
Other
113 stars 66 forks source link

Expected application/json content type but got "application/json, application/json; charset=utf-8"_ #205

Closed bradwoods closed 2 years ago

bradwoods commented 4 years ago

Describe the bug I'm getting the following error when using ldclient allFlags method: LaunchDarklyFlagFetchError in Expected application/json content type but got "application/json, application/json; charset=utf-8"

SDK version 2.15.2

eli-darkly commented 4 years ago

Please provide a little more information:

  1. What browser are you testing in?
  2. Are you using any kind of proxy or gateway in between the browser and the LaunchDarkly service?
  3. When you say "when using ldclient allFlags method", do you mean that you do not see the error if you do not use that method? It seems unlikely that that method is relevant, since it does not cause the client to make any network requests (it does that automatically, allFlags only returns the previously retrieved values).
  4. Was it working correctly at some point earlier, or is this the first time you've tried using the SDK?
eli-darkly commented 4 years ago

2a. Are you using any browser plugins that could modify HTTP responses? I ask because I just did some test requests to the same LaunchDarkly service endpoint that the browser SDK uses, and they returned a single content type of "application/json", not "application/json, application/json; charset=utf-8".

bradwoods commented 4 years ago

These errors are coming from users and not from our tests.

  1. Chrome, 80.0.3987
  2. Undetermined as this information isn't provided.
  3. I see what you're saying. Tracing back it would be the ldclient.on("ready") would this is originating from.
  4. This error has only occurred for some users.

Is it possible that a proxy is or firewall is altering the response from the LaunchDarkly request?

bradwoods commented 4 years ago

2a. This would be difficult to determine but I would say this might be the cause considering it's not happening to the majority of users. You can close this issue off.

eli-darkly commented 4 years ago

Is it possible that a proxy is or firewall is altering the response from the LaunchDarkly request?

It's theoretically possible for them to alter the response in any way they see fit, although I don't know why they would do it in this particular way.

Currently the LD service does not specify a charset for these responses, but in order to remain flexible in case we add that, the SDK was written to not require an exact match of "application/json" but just a content-type that starts with that string. Unfortunately, the actual test it's using is result.header('content-type').lastIndexOf(json) === 0, and since it used lastIndexOf rather than indexOf, the composite header value that it's seeing (application/json, application/json; charset=utf-8, which might mean that the header actually has two values, something that our service definitely should not be doing and is not doing in my tests) has two occurrences of that substring and does not pass the test.

So, since whatever is happening here might not be under our control but is clearly something that can happen somewhere, it might be a good idea for us to make the SDK code more resilient so that it will accept this unexpected header value.

eli-darkly commented 4 years ago

[tracked internally as 69815]

eli-darkly commented 4 years ago

A workaround for this is in the 2.17.2 release.

andrew-yangy commented 4 years ago

Thank @eli-darkly that works, however it's causing a new issue: EventSource's response has a MIME type ("application/json") that is not "text/event-stream". Aborting the connection. I'm using a CORS extension who is being the bad guy here, but I would really appreciate if you can make a fix for that as well, thanks.

eli-darkly commented 4 years ago

Unfortunately, unless you are using a polyfill for EventSource, I don't think there's anything that can be done about that. The browser's built-in EventSource will reject any response that has the wrong content type.

An extension that blindly adds a JSON content type header to every Ajax response no matter what would be a pretty badly broken extension. What is it?

eli-darkly commented 4 years ago

The reason we thought it was reasonable to do the patch we just released was that we wrongly assumed whatever was interfering with the response was using a rule like "if the content type is application/json without a charset, then add a charset" but was just forgetting to replace the header instead of adding an extra one. And the code that was being confused by the extra header was our code, so it was easy to fix.

We were not anticipating a situation where the content type would be entirely wrong, and even if this could be addressed by using a polyfill I'm not sure it would be appropriate for the streaming implementation to just ignore a completely wrong content type.

I think it's also safe to say that if you continue using that extension, LaunchDarkly is not the only software that could be broken by it. Arbitrarily changing the content type is very bad behavior.

andrew-yangy commented 4 years ago

@eli-darkly thanks for the explanation, that makes sense and I totally agree with you. BTW, the chrome extension I use is called https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc

eli-darkly commented 4 years ago

@ddvkid Thanks. We may want to report this issue to the extension developer but I'll see if I can reproduce it first. Is this with the latest version of the extension?

andrew-yangy commented 4 years ago

@eli-darkly yes I'm using the latest version, the mismatch of event source content-type will cause infinite reconnecting, maybe we can do something about it at least?

eli-darkly commented 4 years ago

Again, if you're not using a polyfill then there is very little we can do to influence the EventSource behavior. I'm not even sure it notifies us when it gets an error like that. We'd have to look into it further.

eli-darkly commented 4 years ago

@ddvkid Is the extension configured in any non-default way? So far I haven't been able to reproduce this behavior.

I do see in the source code that it can add a Content-Type: application/json; charset=utf-8 response header under some circumstances, but the code is minified (if the original code is in GitHub somewhere, I don't now where) so I'm finding it hard to see exactly what the behavior is. I can't think why they would ever do this at all, since the content type of the response is completely irrelevant to CORS rules as far as I know, but clearly it is happening for you and I'd like to have a reproducible test case here.

eli-darkly commented 4 years ago

@bradwoods @ddvkid - Any further updates, or shall I close this issue?

andrew-yangy commented 4 years ago

@eli-darkly thanks for your support, still not working but I agree it's the problem of that extension, so all good from me.

eli-darkly commented 4 years ago

Well, I would be curious to see if I can reproduce it, at least. I wasn't having any luck with that, which is why I had asked "Is the extension configured in any non-default way?" The default settings did not do anything like this for me.