1

During development I use grunt-connect-proxy to make some remote APIs locally available. This works just fine, except that the rewrite rules that I use are not applied to cookies:

proxies: [{
  context: '/publicPath',
  host: 'localhost',
  port: 8080,
  rewrite: {
    '^/publicPath': '/privatePath'
  }
}]

If the remote API sets a cookie with path /privatePath it must be rewritten to /publicPath.

E.g. When using Apache httpd I'd use the ProxyPassReverseCookiePath-Directive. How do I do it with grunt-connect-proxy?

yankee
  • 38,872
  • 15
  • 103
  • 162

1 Answers1

4

Thanks to this answer in "Rewrite response headers with node-http-proxy" I managed to figure it out. I created the following middleware:

function rewriteSetCookie(req, res, next) {
    var isProxyRequest = req.url.lastIndexOf('/publicPath', 0) === 0;
    if (isProxyRequest) {
        // we intercept the writeHead function, so that we can exchange headers just before they are written
        var oldWriteHead = res.writeHead;
        res.writeHead = function () {
            var cookie = res.getHeader('Set-Cookie');
            if (cookie) {
                res.setHeader('Set-Cookie', cookie.map(function(item) {
                    // Replace paths in all cookies. The simple string/replace approach might be too naive in some cases, so check before you copy&paste before thinking
                    return item.replace(/\/privatePath/, '/publicPath');
                }));
            }
            oldWriteHead.apply(res, arguments);
        };
    }
    next();
}

Just for reference here is the full configuration so that you can see how to use the middleware:

connect: {
    server: {
        options: {
            hostname: 'localhost',
            base: 'myBaseDir',
            open: true,
            middleware: function (connect, options) {
                if (!Array.isArray(options.base)) {
                    options.base = [options.base];
                }

                // Setup the proxy
                var middlewares = [rewriteSetCookie, proxySnippet];
                //                 ^^^^^^^^^^^^^^^^- Here is is used!

                // Serve static files.
                options.base.forEach(function(base) {
                    middlewares.push(connect.static(base));
                });

                // Make directory browse-able.
                var directory = options.directory || options.base[options.base.length - 1];
                middlewares.push(connect.directory(directory));

                return middlewares;
            }
        },
        proxies: [{
            context: '/publicPath',
            host: 'localhost',
            port: 8080,
            rewrite: {
                '^/publicPath': '/privatePath'
            }
        }]
    }
}
Community
  • 1
  • 1
yankee
  • 38,872
  • 15
  • 103
  • 162
  • I never get a cookie. I can't understand why. I'm proxying to a jboss server holding my rest-api. But set-cookie is never set. My connection-header is always = "close" between the proxy and jboss, is this why the cookie is never set ? – Viktor Eriksson Feb 08 '16 at 09:13
  • @ViktorEriksson: The connection header has absolutely nothing to do with cookies. It is hard to say what your problem is from this little information. Create a new question with some in depth analysis on what you are trying to do, what is actually happening and what you attempted so far to fix it. – yankee Feb 19 '16 at 14:53