title: Proxy HTTPS with HTTP in Node.js express
body: <p>I wrote an express app as an HTTP proxy, to intercept and analyse some of the network traffic. The parts of traffic my app is interested in are all HTTP, however I still want my app to proxy HTTPS so users can use it without extra setting.</p>
  
  <p>My express app is created with a HTTP server. When testing, I changed the proxy setting in Chrome with SwitchyOmega, to proxy HTTPS connections with HTTP. HTTP works well, But my express app couldn't get these proxy requests for HTTPS.</p>
  
  <p>So I wrote a simple TCP proxy to check on them, and find that they're like this:</p>
  
  <pre><code>CONNECT HOSTNAME:443 HTTP/1.1
  Host: HOSTNAME
  Proxy-Connection: keep-alive
  User-Agent: MY_AGENT
  
  ENCRYPTED HTTPS
  </code></pre>
  
  <p>I believe these requests are HTTP, but why express isn't receiving them?</p>
  
  <p>For sure if I change the browser proxy setting to ignore HTTPS, the app works well. But I do want to know if there is any workaround that I can use to proxy all protocols with HTTP and only one port.</p>
  
  <p>THX.</p>
  
  <p><strong>UPDATE- code from my express app</strong></p>
  
  <pre><code>app.use('*', function (req, res, next) {
      // print all the request the app receive
      console.log('received:', req.url)
  })
  
  app.use(bodyParser.text({type: '*/*'}))
  app.use(cookieParser())
  app.use(logger('dev'))
  app.use(express.static(path.join(__dirname, 'public')))
  
  // serve web pages for my app, only the request targeting my server
  // is handled here(right IP and port), proxy request gets handled after this.
  app.use('/', internalRoute)
  
  // analyse the part I want
  app.use('/END_POINT_I_WANT', myRoute)
  
  // handle proxy requests
  app.use('*', function (req, res, next) {
    // proxy the request here
  })
  </code></pre>
  
  <p>The problem is, my first middleware, which is used to display all the requests the app receive, can't catch the HTTPS proxy requests wrapped in HTTP described above. And of course the middleware I used as proxy can't catch them either.</p>
  
  <p><strong>UPDATE-tried <a href="https://github.com/nodejitsu/node-http-proxy" rel="nofollow">node-http-prxoy</a>, no luck</strong></p>
  
  <pre><code>var httpProxy = require('http-proxy')
    , http = require('http')
    , fs = require('fs')
  
  var options = {target: 'http://127.0.0.1:8099'}
    , proxy = httpProxy.createServer(options)
  
  http.createServer(function (req, res) {
    console.log(req.url)
    proxy.web(req, res)
  }).listen(5050)
  </code></pre>
  
  <p>With the above code, and browser setting to proxy all protocols with HTTP, it works the same as my express app. HTTPS proxy requests gets <code>ERR_EMPTY_RESPONSE</code>, and nothing on the console.</p>
  
  <p>With the below options, it seems that I have to change the proxy protocol to HTTPS, which I'd rather not use, at least for now. And I get <code>ERR_PROXY_CERTIFICATE_INVALID</code> for my self-signed certs...</p>
  
  <pre><code>var options  = { secure: true
                 , target: 'http://127.0.0.1:8099'
                 , ssl: { key: fs.readFileSync('cert/key.pem', 'utf8')
                        , cert: fs.readFileSync('cert/server.crt', 'utf8')
                        }
                 }
  </code></pre>
  
  <p><strong>UPDATE- pin point the problem to the 'connect' event listener</strong></p>
  
  <p>Through some searching, I found <a href="https://newspaint.wordpress.com/2012/11/05/node-js-http-and-https-proxy/" rel="nofollow">this post</a> helpful.</p>
  
  <p>It pointed out that the http server doesn't have a listener for the <code>connect</code> event. I tried the code in the post, works. But as the last comment of that post mentioned, my app serves as a proxy in order to get the data, it then proxy the request to another proxy in order to go over the GreatFireWall.</p>
  
  <p>The process is like : <code>BROWSER -&gt; MY_APP -&gt; ANOTHER_PROXY -&gt; TARGET</code>.</p>
  
  <p>Without the <code>ANOTHER_PROXY</code>, which is an HTTP proxy, it works well for both HTTP and HTTPS. However I failed to chain them all up. The <code>ANOTHER_PROXY</code> I use supports HTTPS over HTTP.</p>