Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

http2-proxy

Package Overview
Dependencies
Maintainers
1
Versions
193
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

http2-proxy

A simple http/2 & http/1.1 to http/1.1 spec compliant proxy helper for Node.

  • 5.0.35
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
26K
decreased by-6.64%
Maintainers
1
Weekly downloads
 
Created
Source

http2-proxy

A simple http/2 & http/1.1 to http/1.1 spec compliant proxy helper for Node.

Features

  • Proxies HTTP 2, HTTP 1 and WebSocket.
  • Simple and high performance.
  • Hop by hop header handling.
  • Connection header handling.
  • Via header handling.
  • Forward header handling.

Installation

$ npm install http2-proxy

Notes

http2-proxy requires at least node v10.0.0.

Fully async/await compatible and all callback based usage is optional and discouraged.

During 503 it is safe to assume that nothing was read or written. This makes it safe to retry request (including non idempotent methods).

Use a final and/or error handler since errored responses won't be cleaned up automatically. This makes it possible to perform retries.

const finalhandler = require('finalhandler')

const defaultWebHandler = (err, req, res) => {
  if (err) {
    console.error('proxy error', err)
    finalhandler(req, res)(err)
  }
}

const defaultWSHandler = (err, req, socket, head) => {
  if (err) {
    console.error('proxy error', err)
    socket.destroy()
  }
}

HTTP/1 API

You must pass allowHTTP1: true to the http2.createServer or http2.createSecureServer factory methods.

import http2 from 'http2'
import proxy from 'http2-proxy'

const server = http2.createServer({ allowHTTP1: true })
server.listen(8000)

You can also use http-proxy2 with the old http && https API's.

import http from 'http'

const server = http.createServer()
server.listen(8000)

API

Proxy HTTP/2, HTTP/1 and WebSocket

server.on('request', (req, res) => {
  proxy.web(req, res, {
    hostname: 'localhost'
    port: 9000
  }, defaultWebHandler)
})
server.on('upgrade', (req, socket, head) => {
  proxy.ws(req, socket, head, {
    hostname: 'localhost'
    port: 9000
  }, defaultWsHandler)
})

Use Connect & Helmet

const app = connect()
app.use(helmet())
app.use((req, res, next) => proxy
  .web(req, res, {
    hostname: 'localhost'
    port: 9000
  }, err => {
    if (err) {
      next(err)
    }
  })
)
server.on('request', app)

Add x-forwarded Headers

server.on('request', (req, res) => {
  proxy.web(req, res, {
    hostname: 'localhost'
    port: 9000,
    onReq: (req, { headers }) => {
      headers['x-forwarded-for'] = req.socket.remoteAddress
      headers['x-forwarded-proto'] = req.socket.encrypted ? 'https' : 'http'
      headers['x-forwarded-host'] = req.headers['host']
    }
  }, defaultWebHandler)
})

Follow Redirects

const http = require('follow-redirects').http

server.on('request', (req, res) => {
  proxy.web(req, res, {
    hostname: 'localhost'
    port: 9000,
    onReq: (req, options) => http.request(options)
  }, defaultWebHandler)
})

Add Response Header

server.on('request', (req, res) => {
  proxy.web(req, res, {
    hostname: 'localhost'
    port: 9000,
    onReq: (req, options) => http.request(options),
    onRes: (req, res, proxyRes) => {
      res.setHeader('x-powered-by', 'http2-proxy')
      res.writeHead(proxyRes.statusCode, proxyRes.headers)
      proxyRes.pipe(res)
    }
  }, defaultWebHandler)
})

Try Multiple Upstream Servers (Advanced)

const http = require('http')
const proxy = require('http2-proxy')
const createError = require('http-errors')

server.on('request', async (req, res) => {
  try {
    res.statusCode = null
    for await (const { port, timeout, hostname } of upstream) {
      if (req.aborted || finished) {
        return
      }

      let error = null
      let finished = false
      let bytesWritten = 0
      try {
        return await proxy.web(req, res, {
          port,
          timeout,
          hostname,
          onRes: async (req, res, proxyRes) => {
            if (proxyRes.statusCode >= 500) {
              throw createError(proxyRes.statusCode, proxyRes.message)
            }

            function setHeaders () {
              if (!bytesWritten) {
                res.statusCode = proxyRes.statusCode
                for (const [ key, value ] of Object.entries(headers)) {
                  res.setHeader(key, value)
                }
              }
            }

            // NOTE: At some point this will be possible
            // proxyRes.pipe(res)

            proxyRes
              .on('data', buf => {
                setHeaders()
                bytesWritten += buf.length
                if (!res.write(buf)) {
                  proxyRes.pause()
                }
              })
              .on('end', () => {
                // WORKAROUND: https://github.com/nodejs/node/pull/27984
                if (!proxyRes.aborted) {
                  setHeaders()
                  res.addTrailers(proxyRes.trailers)
                  res.end()
                  // WORKAROUND: https://github.com/nodejs/node/pull/24347
                  finished = true
                }
              })
              .on('close', () => {
                res.off('drain', onDrain)
              }))

            res.on('drain', onDrain)

            function onDrain () {
              proxyRes.resume()
            }
          }
        })
      } catch (err) {
        if (!err.statusCode) {
          throw err
        }

        error = err

        if (err.statusCode === 503) {
          continue
        }

        if (req.method === 'HEAD' || req.method === 'GET') {
          if (!bytesWritten) {
            continue
          }

          // TODO: Retry range request
        }

        throw err
      }
    }

    throw error || new createError.ServiceUnavailable()
  } catch (err) {
    defaultWebHandler(err)
  }
}

[async] web (req, res, options[, callback])

See request

[async] ws (req, socket, head, options[, callback])

See upgrade

options

Node

These are some existing issues in NodeJS to keep in mind when writing proxy code.

And some pending PR's:

Some of these are further referenced in the examples.

License

MIT

Keywords

FAQs

Package last updated on 30 Aug 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc