launchdarkly / js-client-sdk

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

Custom HTTP Transport #196

Closed vijaypemmaraju closed 2 years ago

vijaypemmaraju commented 4 years ago

I'd like to implement LaunchDarkly into a chrome extension. However, due to recent changes in chromium, cross-origin requests can no longer be made from the content scripts that are injected into pages. Instead, we have to make requests from the background page and relay them to the content scripts. I've built a whole mechanism for this already for our existing API calls.

My first thought was implementing LD in the background page and creating an analogous relaying system, but it would be nice if I could just implement it directly in the content scripts and simply configure how the underlying API call is made (i.e. a custom HTTP transport). I'm not interested in the streaming API, I just want access to the variations.

As far as I can tell, there's no functionality for this today. Would this be something that's viable to implement?

eli-darkly commented 4 years ago

I haven't developed any Chrome extensions, so I'm not sure I entirely understand the situation, but... if the extension is not allowed to make a CORS request, then how would your custom HTTP transport in the extension be implemented?

The HTTP code is already behind an abstraction in the SDK (since the core SDK code is shared by the browser SDK and the client-side Node and Electron SDKs, which use Node HTTP) so it's plausible that we could expose a property for plugging in a different function, but I'm unclear on how that function would work in this case.

vijaypemmaraju commented 4 years ago

In my case, the custom function would effectively forward the request to the background page. This is a snippet of what our implementation looks like for our existing codebase:

function sendHTTPRequestMessage(payload) {
  const deferred = $.Deferred();

  chrome.runtime.sendMessage({
    action: 'SEND_HTTP_REQUEST',
    payload,
  }, ([responseType, ...args]) => {
    if (responseType === 'done') {
      deferred.resolve(...args);
    } else {
      deferred.reject(...args);
    }
  });

  return deferred;
}

What happens in the background page itself is a bit of an implementation detail, but it basically just executes the request that it was given and sends back the response.

Let me know if that makes sense.

eli-darkly commented 4 years ago

Hmm, well... I hadn't read the Chromium docs link you provided, but now I have, and now I'm confused on a different point. At one point on that page, they say they're "removing the ability to make cross-origin requests in content scripts", period. But elsewhere it says the change "will limit content scripts to the same fetches that the page itself can perform". That would include a CORS request if the server is sending CORS headers to say that such requests are allowable— which we do. It sounds to me like they are only turning off the ability to enable CORS for certain domains that wouldn't otherwise be reachable, via the extension's permissions.

Have you verified experimentally that these requests from the SDK really do not work when it's invoked from your extension?

vijaypemmaraju commented 4 years ago

I haven't tested directly with the launchdarkly SDK yet (our trial expired, so waiting on billing to get unblocked), but I dug a little further and found this:

image

Our backend sets this header for all requests, which is likely why we had to implement this despite having the appropriate CORS headers. Do you know if LaunchDarkly sets this header? If not, perhaps we might not need this.

eli-darkly commented 4 years ago

No, the LaunchDarkly SDK endpoints do not set any X-Content-Type-Options header in their responses.

vijaypemmaraju commented 4 years ago

Cool, that sounds promising, I'll give it a try and report back.