Socket
Socket
Sign inDemoInstall

toxy

Package Overview
Dependencies
30
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.3 to 0.2.0

examples/admin.js

1

index.js

@@ -19,2 +19,3 @@ const Toxy = require('./lib/toxy')

toxy.admin = require('./lib/admin')
toxy.Rule = require('./lib/rule')

@@ -21,0 +22,0 @@ toxy.Base = require('./lib/base')

@@ -35,1 +35,9 @@ exports.isRegExp = function isRegExp(o) {

}
exports.randomId = function (head, tail) {
var id = 0
var seed = head + '|' + tail
var len = seed.length
while (len--) { id += seed.charCodeAt(len) }
return id.toString(16).slice(0, 10)
}

3

lib/directive.js

@@ -9,2 +9,3 @@ const Rule = require('./rule')

this.directive = directive
this.name = directive.$name || directive.name
}

@@ -51,5 +52,5 @@

handler.$of = this
handler.$name = this.directive.$name || this.directive.name
handler.$name = this.name
return handler
}
module.exports = function inject(opts) {
var code = +opts.code || 500
return function inject(req, res, next) {
res.writeHead(+opts.code || 500, opts.headers)
res.writeHead(code, opts.headers)
res.end(opts.body, opts.encoding)
}
}

@@ -7,6 +7,7 @@ module.exports = function slowClose(opts) {

var ended = false
// Cache native methods
var _end = res.end
var resproto = Object.getPrototypeOf(res)
var _setHeader = resproto.setHeader
var _writeHead = resproto.writeHead
var _setHeader = res.setHeader
var _writeHead = res.writeHead

@@ -39,3 +40,3 @@ res.setHeader = function (header, value) {

// End response
// Ends the response
res.end.apply(res, args)

@@ -45,3 +46,3 @@

_res = _setHeader = null
_writeHead = args = resproto = null
_writeHead = args = null
}

@@ -48,0 +49,0 @@ }

@@ -7,3 +7,3 @@ const common = require('../common')

var threshold = +opts.threshold || 1000
var chunkSize = (+opts.chunk || +opts.bps) || 1024
var chunkSize = +opts.chunk || +opts.bps || 1024

@@ -16,3 +16,5 @@ return function slowRead(req, res, next) {

if (isInvalidMethod(req)) return next()
if (isInvalidMethod(req)) {
return next()
}

@@ -42,7 +44,9 @@ // Handle client close connection properly

function pushDefer(chunk, next) {
setTimeout(function () {
setTimeout(push, threshold)
function push() {
if (closed) return next('closed')
_push.call(req, chunk.buffer, chunk.encoding)
next()
}, threshold)
}
}

@@ -49,0 +53,0 @@

@@ -6,3 +6,3 @@ const common = require('../common')

var threshold = +opts.threshold || 100
var chunkSize = (+opts.chunk || +opts.bps) || 1024
var chunkSize = +opts.bps || +opts.chunk || 1024

@@ -14,7 +14,6 @@ return function throttle(req, res, next) {

var resproto = Object.getPrototypeOf(res)
var _end = resproto.end
var _write = resproto.write
var _end = res.end
var _write = res.write
// Listen for client connection close
// Listen for connection close in both ends
req.on('close', cleanup)

@@ -34,3 +33,3 @@ res.on('close', cleanup)

// Party time: finally write each chunk with a delay in FIFO order
// Party time: write each chunk with a delay in FIFO order
common.eachSeries(buf, writeDefer, end)

@@ -45,6 +44,8 @@

function writeDefer(chunk, next) {
setTimeout(function () {
setTimeout(write, threshold)
function write() {
if (closed) return next('closed')
_write.call(res, chunk.buffer, chunk.encoding, next)
}, threshold)
}
}

@@ -56,8 +57,8 @@

// Restore and clean references
// Restore methods
res.end = _end
res.write = _write
_end = _write = resproto = buf = null
// Clean listeners to prevent leaks
// Clean references and listeners to prevent leaks
_end = _write = buf = null
req.removeListener('close', cleanup)

@@ -64,0 +65,0 @@ req.removeListener('close', cleanup)

const midware = require('midware')
const Proxy = require('./proxy')
const Admin = require('./admin')
const randomId = require('./common').randomId
const noop = function () {}
const defaultPort = +process.env.PORT || 3000
module.exports = Toxy

@@ -8,2 +13,4 @@

Proxy.call(this, opts)
this.routes = []
this._rules = midware()

@@ -18,12 +25,26 @@ this._poisons = midware()

Toxy.prototype.listen = function (port, host) {
this.host = host
this.port = +port || defaultPort
Proxy.prototype.listen.call(this, this.port, host)
return this
}
function wrapRouteConstructor(self) {
var _route = self.route
self.route = function () {
self.route = function (method, path) {
var route = _route.apply(self, arguments)
// Create toxy route-evel specific middleware
// Expose useful data in the route
route.id = randomId(method, path)
route.method = method.toUpperCase()
// Creates toxy route-level middleware stacks
route._rules = midware()
route._poisons = midware()
// Setup middleware and final route handler
// Register route in the toxy stack
self.routes.push(route)
// Setup route middleware and final handler
setupMiddleware(route)

@@ -39,3 +60,3 @@ reDispatchRoute(route)

route.use(function (req, res, next) {
route.dispatcher.doDispatch(req, res, function () {})
route.dispatcher.doDispatch(req, res, noop)
})

@@ -42,0 +63,0 @@ }

{
"name": "toxy",
"version": "0.1.3",
"description": "Hackable HTTP proxy to simulate server failure scenarios and unexpected conditions",
"version": "0.2.0",
"description": "Hackable HTTP proxy to simulate server failure scenarios and unexpected network conditions",
"repository": "h2non/toxy",

@@ -18,3 +18,3 @@ "author": "Tomas Aparicio",

"testing",
"resilency",
"resiliency",
"fuzz",

@@ -27,3 +27,6 @@ "evil",

"unexpected",
"backoff"
"backoff",
"network",
"latency",
"jitter"
],

@@ -38,6 +41,9 @@ "engines": {

"midware": "^0.1.3",
"object-assign": "^3.0.0",
"raw-body": "^2.1.2",
"rocky": "^0.3.3"
"rocky": "^0.3.3",
"router": "^1.1.3"
},
"devDependencies": {
"async": "^1.4.2",
"chai": "^3.0.0",

@@ -44,0 +50,0 @@ "clone": "^1.0.2",

@@ -1,12 +0,13 @@

# toxy [![Build Status](https://api.travis-ci.org/h2non/toxy.svg?branch=master&style=flat)](https://travis-ci.org/h2non/toxy) [![Code Climate](https://codeclimate.com/github/h2non/toxy/badges/gpa.svg)](https://codeclimate.com/github/h2non/toxy) [![NPM](https://img.shields.io/npm/v/toxy.svg)](https://www.npmjs.org/package/toxy) ![Stability](http://img.shields.io/badge/stability-beta-orange.svg?style=flat)
# toxy [![Build Status](https://api.travis-ci.org/h2non/toxy.svg?branch=master&style=flat)](https://travis-ci.org/h2non/toxy) [![Code Climate](https://codeclimate.com/github/h2non/toxy/badges/gpa.svg)](https://codeclimate.com/github/h2non/toxy) [![NPM](https://img.shields.io/npm/v/toxy.svg)](https://www.npmjs.org/package/toxy)
<img align="right" height="180" src="http://s8.postimg.org/ikc9jxllh/toxic.jpg" />
**toxy** is a **hackable HTTP proxy** to **simulate** server **failure scenarios** and **unexpected network conditions**, built for [node.js](http://nodejs.org)/[io.js](https://iojs.org).
**toxy** is a fully programmatic and **hackable HTTP proxy** to **simulate** server **failure scenarios** and **unexpected network conditions**, built for [node.js](http://nodejs.org)/[io.js](https://iojs.org).
It was mainly designed for fuzzing/evil testing purposes, becoming particulary useful to cover fault tolerance and resiliency capabilities of a system, especially in [service-oriented](http://microservices.io/) architectures, where toxy may act as intermediate proxy among services.
It was mainly designed for fuzzing/evil testing purposes, toxy becomes particulary useful to cover fault tolerance and resiliency capabilities of a system, especially in [service-oriented](http://microservices.io/) architectures, where toxy may act as intermediate proxy among services.
toxy allows you to plug in [poisons](#poisons), optionally filtered by [rules](#rules), which basically can intercept and alter the HTTP flow as you need, performing multiple evil actions in the middle of that process, such as limiting the bandwidth, delaying TCP packets, injecting network jitter latency or replying with a custom error or status code.
toxy allows you to plug in [poisons](#poisons), optionally filtered by [rules](#rules), which essentially can intercept and alter the HTTP flow as you need, performing multiple evil actions in the middle of that process, such as limiting the bandwidth, delaying TCP packets, injecting network jitter latency or replying with a custom error or status code.
toxy is compatible with [connect](https://github.com/senchalabs/connect)/[express](http://expressjs.com), and it was built on top of [rocky](https://github.com/h2non/rocky), a full-featured, middleware-oriented HTTP proxy.
toxy can be fluently used [programmatically](#programmatic-api) or via [HTTP API](#http-api).
It's compatible with [connect](https://github.com/senchalabs/connect)/[express](http://expressjs.com), and it was built on top of [rocky](https://github.com/h2non/rocky), a full-featured middleware-oriented HTTP proxy.

@@ -47,2 +48,7 @@ Requires node.js +0.12 or io.js +1.6

- [Programmatic API](#programmatic-api)
- [HTTP API](#http-api)
- [Usage](#usage)
- [Authorization](#authorization)
- [API](#api)
- [Programmatic API](#programmatic-api-1)
- [License](#license)

@@ -54,5 +60,6 @@

- Hackable and elegant programmatic API (inspired on connect/express)
- Admin HTTP API for external management and dynamic configuration
- Featured built-in router with nested configuration
- Hierarchical poisioning and rules based filtering
- Hierarchical middleware layer (global and route-specific)
- Hierarchical and composable poisioning with rule based filtering
- Hierarchical middleware layer (both global and route scopes)
- Easily augmentable via middleware (based on connect/express middleware)

@@ -65,3 +72,3 @@ - Built-in poisons (bandwidth, error, abort, latency, slow read...)

- Compatible with connect/express (and most of their middleware)
- Runs as standalone HTTP proxy
- Able to run as standalone HTTP proxy

@@ -72,5 +79,5 @@ ## Introduction

There're some other similar solutions to `toxy` in the market, but most of them don't provide a proper programmatic control and are not easy to hack, configure and/or extend. Additionally, most of the those solutions are based only on the TCP stack, instead of providing features to the specific domain of the HTTP protocol, like toxy does.
There're some other similar solutions like `toxy` in the market, but most of them do not provide a proper programmatic control and usually are not easy to hack, configure and/or extend. Additionally, most of the those solutions only operate at TCP level stack instead of providing high-level abstraction to cover common requirements of the specific domain and nature of the HTTP protocol, like toxy does.
`toxy` provides a powerful hackable and extensible solution with a convenient low-level interface and programmatic features based on simple, concise and fluent API, with the power, simplicity and fun of node.js.
toxy provides a powerful hackable and extensible solution with a convenient abstraction, but also a low-level interface and programmatic capabilities exposed as a simple, concise and fluent API, with the implicit power, simplicity and fun of node.js.

@@ -118,3 +125,3 @@ ### Concepts

See the [examples](https://github.com/h2non/toxy/tree/master/examples) directory for more use cases
See [examples](https://github.com/h2non/toxy/tree/master/examples) directory for more use cases.

@@ -126,4 +133,6 @@ ```js

// Create a new toxy proxy
var proxy = toxy()
// Default server to forward incoming traffic
proxy

@@ -140,2 +149,3 @@ .forward('http://httpbin.org')

.get('/download/*')
.forward('http://files.myserver.net')
.poison(poisons.bandwidth({ bps: 1024 }))

@@ -239,3 +249,4 @@ .withRule(rules.headers({'Authorization': /^Bearer (.*)$/i }))

Note that this is very simple rate limit implementation, indeed limits are stored in-memory, therefore are completely volalite. There're a bunch of more featured and consistent rate limiter implementations in [npm](https://www.npmjs.com/search?q=rate+limit) that you can plug in as poison.
Note that this is very simple rate limit implementation, indeed limits are stored in-memory, therefore are completely volalite.
There're a bunch of featured and consistent rate limiter implementations in [npm](https://www.npmjs.com/search?q=rate+limit) that you can plug in as poison. You might also interested in [token bucket algorithm](http://en.wikipedia.org/wiki/Token_bucket).

@@ -315,7 +326,8 @@ **Arguments**:

Aborts the TCP connection, optionally with a custom error. From the low-level perspective, this will destroy the socket on the server, operating only at TCP level without sending any specific HTTP application level data.
Aborts the TCP connection. From the low-level perspective, this will destroy the socket on the server, operating only at TCP level without sending any specific HTTP application level data.
**Arguments**:
- **miliseconds** `number` - Optional socket destroy delay in miliseconds
- **options** `object`
- **delay** `number` - Socket destroy delay in miliseconds. Default to `0`

@@ -524,14 +536,2 @@ ```js

### toxy.poisons `=>` Object
Exposes a map with the built-in poisons.
### toxy.rules `=>` Object
Exposes a map with the built-in rules.
### toxy.VERSION `=>` String
Current toxy semantic version.
#### toxy#get(path, [ middleware... ])

@@ -714,2 +714,14 @@ Return: `ToxyRoute`

### toxy.poisons `=>` Object
Exposes a map with the built-in poisons.
### toxy.rules `=>` Object
Exposes a map with the built-in rules.
### toxy.VERSION `=>` String
Current toxy semantic version.
### ToxyRoute

@@ -766,4 +778,283 @@

## HTTP API
The `toxy` HTTP API follows the [JSON API](http://jsonapi.org) conventions, including resouce based hypermedia linking.
### Usage
```js
const toxy = require('toxy')
// Create the toxy admin server
var admin = toxy.admin()
admin.listen(9000)
// Create the toxy proxy
var proxy = toxy()
proxy.listen(3000)
// Add the toxy instance to be managed by the admin server
admin.manage(proxy)
console.log('toxy proxy listening on port:', 3000)
console.log('toxy admin server listening on port:', 9000)
```
For more details about the admin programmatic API, see [below](#programmatic-api-1).
### Authorization
The HTTP API can be protected to unauthorized clients.
Authorized clients must define the API key token via `API-Key` or `Authorization` HTTP headers.
To enable it, you should simple pass the following options to `toxy` admin server:
```js
const toxy = require('toxy')
const opts = { apiKey: 's3cr3t' }
var admin = toxy.admin(opts)
admin.listen(9000)
console.log('protected toxy admin server listening on port:', 9000)
```
### API
**Hierarchy**:
- Servers - Managed `toxy` instances
- Rules - Globally applied rules
- Poisons - Globally applied poisons
- Rules - Poison-specific rules
- Routes - List of configured routes
- Route - Object for each specific route
- Rules - Route-level registered rules
- Poisons - Route-level registered poisons
- Rules - Route-level and poison-specific rules
#### GET /
### Servers
#### GET /servers
#### GET /servers/:id
### Rules
#### GET /servers/:id/rules
#### POST /servers/:id/rules
Accepts: `application/json`
Example payload:
```js
{
"name": "method",
"options": "GET"
}
```
#### DELETE /servers/:id/rules
#### GET /servers/:id/rules/:id
#### DELETE /servers/:id/rules/:id
### Poisons
#### GET /servers/:id/poison
#### POST /servers/:id/poisons
Accepts: `application/json`
Example payload:
```js
{
"name": "latency",
"options": { "jitter": 1000 }
}
```
#### DELETE /servers/:id/poisons
#### GET /servers/:id/poisons/:id
#### DELETE /servers/:id/poisons/:id
#### GET /servers/:id/poisons/:id/rules
#### POST /servers/:id/poisons/:id/rules
Accepts: `application/json`
Example payload:
```js
{
"name": "method",
"options": "GET"
}
```
#### DELETE /servers/:id/poisons/:id/rules
#### GET /servers/:id/poisons/:id/rules/:id
#### DELETE /servers/:id/poisons/:id/rules/:id
### Routes
#### GET /servers/:id/routes
#### POST /servers/:id/routes
Accepts: `application/json`
Example payload:
```js
{
"path": "/foo", // Required
"method": "GET", // use ALL for all the methods
"forward": "http://my.server", // Optional custom forward server URL
}
```
#### DELETE /servers/:id/routes
#### GET /servers/:id/routes/:id
#### DELETE /servers/:id/routes/:id
### Route rules
#### GET /servers/:id/routes/:id/rules
#### POST /servers/:id/routes/:id/rules
Accepts: `application/json`
Example payload:
```js
{
"name": "method",
"options": "GET"
}
```
#### DELETE /servers/:id/routes/:id/rules
#### GET /servers/:id/routes/:id/rules/:id
#### DELETE /servers/:id/routes/:id/rules/:id
### Route poisons
#### GET /servers/:id/routes/:id/poisons
#### POST /servers/:id/routes/:id/poisons
Accepts: `application/json`
Example payload:
```js
{
"name": "latency",
"options": { "jitter": 1000 }
}
```
#### DELETE /servers/:id/routes/:id/poisons
#### GET /servers/:id/routes/:id/poisons/:id
#### DELETE /servers/:id/routes/:id/poisons/:id
#### GET /servers/:id/routes/:id/poisons/:id/rules
#### POST /servers/:id/routes/:id/poisons/:id/rules
Accepts: `application/json`
Example payload:
```js
{
"name": "method",
"options": "GET"
}
```
#### DELETE /servers/:id/routes/:id/poisons/:id/rules
#### GET /servers/:id/routes/:id/poisons/:id/rules/:id
#### DELETE /servers/:id/routes/:id/poisons/:id/rules/:id
### Programmatic API
The built-in HTTP admin server also provides a simple interface open to extensibility and hacking purposes.
For instance, you can plug in additional middleware to the admin server, or register new routes.
#### toxy.admin([ opts ])
Returns: `Admin`
**Supported options**:
- **apiKey** - Optional API key to protect the server
- **port** - Optional. TCP port to listen
##### Admin#listen([ port, host ])
Start listening on the network.
##### Admin#manage(toxy)
Manage a `toxy` server instance.
##### Admin#find(toxy)
Find a toxy instance. Accepts toxy server ID or toxy instance.
##### Admin#remove(toxy)
Stop managing a toxy instance.
##### Admin#use(...middleware)
Register a middleware.
##### Admin#param(...middleware)
Register a param middleware.
##### Admin#get(path, [ ...middleware ])
Register a GET route.
##### Admin#post(path, [ ...middleware ])
Register a POST route.
##### Admin#put(path, [ ...middleware ])
Register a PUT route.
##### Admin#delete(path, [ ...middleware ])
Register a DELETE route.
##### Admin#patch(path, [ ...middleware ])
Register a PATCH route.
##### Admin#all(path, [ ...middleware ])
Register a route accepting any HTTP method.
##### Admin#middleware(req, res, next)
Middleware to plug in with connect/express.
##### Admin#close(cb)
Stop the server.
## License
MIT - Tomas Aparicio
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc