0

I am programming a task manager for node.js apps. These apps are opened in an arbitrary port, so, in order to reach them I want to fake their root in a URL like this:

http://domain.com/proxy/yourApplication

So third parties could make HTTP requests to their app without knowing in which port it runs.

Then I chose http-proxy:

var express = require('express')
, router = express.Router()
, Helper = require('../helper')
, launcher = require('../launcher')
, httpProxy = require('http-proxy')
, proxy = httpProxy.createProxyServer({ws: true});

And the code that listens at that route...

// Proxy
router.use('/proxy/:name?', function(req, res) {

  var app, reqPath, referer, proxyUrl;

  // Capture the referer to proxy the request
  // in case the path is not clear enaugh
  if (req.get('referer') !== undefined) {
    var aux = req.get('referer').split('/');
    referer = aux[aux.indexOf('proxy') + 1]
  }

  // This block returns an app object
  // with the port where it is running
  app = launcher.getApp(req.params.name)
  || launcher.getApp(referer);

  if (app) {
    // Here app is running

    // In case the path is /proxy/:name
    // instead of /proxy/:name/ you need this block
    req.url = (req.url === '/') ? '' : req.url;
    reqPath = (referer !== undefined)
     ? '/' + req.params.name + req.url
     : req.url;
    req.url = reqPath.replace('/proxy/', '/');
    req.url = req.url.replace('/' + app.name, '');

    // This block of code actually pipes the request
    // to the running app and pass it to the client
    proxyUrl = req.protocol + '://localhost:' + app.port;
    proxy.web(req, res, { 
      target: proxyUrl
    });

    // Some logging
    console.log('req url: %s', req.url);
    console.log('proxy url: %s', proxyUrl);
    console.log('referer: %s', referer);

  } else {
    // Here app is not running
    res.status(404).json("App not running");
  }
});

It works just fine with most apps, but when opening an app with socket.io it prompts:

WebSocket connection to 'ws://localhost/proxy/xy-terminal/socket.io/1/websocket/gMqK_XRwZENuUibi4ekJ' failed: Connection closed before receiving a handshake response

In the server console...

Trace: { [Error: socket hang up] code: 'ECONNRESET' }
    at process.<anonymous> (/Users/jdario/Development/xy-dashboard/www:107:11)
    at process.emit (events.js:107:17)
    at process._fatalException (node.js:236:26)
    at ProxyServer.emit (/Users/jdario/Development/xy-dashboard/node_modules/http-proxy/node_modules/eventemitter3/index.js:75:35)
    at ClientRequest.proxyError (/Users/jdario/Development/xy-dashboard/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:140:16)
    at ClientRequest.emit (events.js:129:20)
    at Socket.socketCloseListener (_http_client.js:247:9)
    at Socket.emit (events.js:129:20)
    at TCP.close (net.js:485:12)

Since it is a "proxy" that fakes an app root I may not be available to modify their source code individually, they should just work as intended. When opening them in the right port (3000 in this case) they do not show any error.

Thank you in advance!

jsdario
  • 6,477
  • 7
  • 41
  • 75
  • Do you understand that a webSocket connection starts out as an http request which is then upgraded to the webSocket protocol? So, your proxy would need to handle that and would need a way to tell which app a webSocket connection was destined for. – jfriend00 Apr 13 '15 at 04:22
  • Yes! Actually I believed the error could be there but after inspected the source code of http-proxy I could not find out. Also I have to note that other connections trials after the first works perfectly. The first is 'pending' when hitting '/proxy/appName/' and 'finished' when reaching '/proxy/appName'. – jsdario Apr 13 '15 at 09:01

1 Answers1

0

Shortest answer was to indeed modify the proxied apps source code individually. So now they use

var io = require('socket.io')(http, { path: '/proxy/yourApplication'})

This post addressed the problem. https://stackoverflow.com/a/31658307/2633577

However this answer is not the best because it is not 100% transparent to hosted apps.

Community
  • 1
  • 1
jsdario
  • 6,477
  • 7
  • 41
  • 75