Adding CORS headers

Meteor added a way to suppress CORS headers in 2.14 (DISABLE_SOCKJS_CORS), which is great. The default ones were problematic.

However, removing them altogether breaks Cordova applications.
Is there a way to slip in a “Access-Control-Allow-Origin” header in the response to that intial to “sockjs/info” call? It would be fantastic if I could manually add that header with the value I need.

Thanks!

2 Likes

If I know things right then you should always be able to manipulate all incoming requests using WebApp.rawConnectHandlers.use and then add a middleware that adds respective headers or call next to pass handling on to all other requests.

1 Like

Thanks for the response. Between the connect and rawConnect handlers, I can get some things, but the sockjs stuff seems to be completely inaccessible.

I have a feeling I will need to access internal ‘use-at-your-own-risk’ properties at this point, but I don’t know what those would be. Nothing I have tried has worked.

I no longer deal with this logic in the Meteor app, instead add this header on the edge using Cloudflare Workers. Far easier to deal with, modify, etc. without re-deploying the Meteor app each time.

@sparky have you managed to fix this? If yes could you share please. Have the same question.

This is looks a bit cludgy, but I found an answer looking at the Meteor source code. I am not sure why they implemented the listener replacement this way, but I figured they had a reason.

Here are the tricky parts from the class. Once in your custom ‘preprocess’ function, you can check the url (like for /sockjs/), and do what you want.


/**

  • This class is used to intercept all requests and modify the response headers.
  • This was created to add CORS headers to the responses.
  • The mechanism used here was taken from the meteor source code.
  • Meteor 2.15/meteor-devel/packages/ddp-server/stream_server.js
    */
	private initialize()
	{
		const EVENT = 'request';
		const httpServer = WebApp.httpServer;

		const oldHttpServerListeners: Function[] = httpServer.listeners(EVENT).slice(0);
		httpServer.removeAllListeners(EVENT);

		// In the meteor source code, this process is done to both upgrade and request.  I don't think we need to mess with the header
		// on an upgrade.  Note, in the meteor docs, it says that the "upgrade" event type has different arguments then request,
		// which is probably why they use the 'arguments' object in the closure below.

		const self = this;
		const newListener = function (request: IncomingMessage, response: ServerResponse) {
			// Store arguments for use within the closure below
			const args = arguments;

			self.preprocess(httpServer, request, response);

			oldHttpServerListeners.forEach(function (oldListener) {
				oldListener.apply(httpServer, args);
			});
			self.postprocess(httpServer, request, response);
		};
		httpServer.addListener(EVENT, newListener);
	}
1 Like