
Hackbarer HTTP-Proxy für Resilienztests und simulierte Netzwerkbedingungen
Hackbarer HTTP-Proxy zum Simulieren von Serverausfallszenarien, System-Resilienz-Tests und unerwarteten Netzwerkbedingungen, entwickelt für node.js.

Es wurde hauptsächlich für Ausfallresistenztests entwickelt, bei denen toxy besonders nützlich ist, um die Fehlertoleranz- und Resilienzfähigkeiten eines Systems abzudecken, insbesondere in störungstoleranten Netzwerken und serviceorientierten Architekturen, wo toxy als MitM-Proxy zwischen Diensten agieren kann, um Ausfälle zu injizieren.
toxy ermöglicht es Ihnen, Gifte einzustecken, optional gefiltert durch Regeln, die im Wesentlichen den HTTP-Fluss nach Bedarf abfangen und verändern können, indem sie mehrere böswillige Aktionen in der Mitte dieses Prozesses ausführen, wie z. B. die Bandbreite zu begrenzen, Netzwerkpakete zu verzögern, Netzwerk-Jitter-Latenz zu injizieren oder mit einem benutzerdefinierten Fehler- oder Statuscode zu antworten. Es operiert primär auf L7, obwohl es L3-Netzwerkbedingungen simulieren kann.
toxy kann fließend programmatisch oder über die HTTP-API genutzt werden. Es basiert auf rocky, einem voll funktionsfähigen middleware-orientierten HTTP-Proxy, und ist auch als Standard-Middleware in connect/express einsteckbar.
Erfordert node.js +4.
Es gibt einige andere ähnliche Lösungen wie toxy auf dem Markt, aber die meisten bieten keine angemessene programmatische Kontrolle und sind in der Regel nicht einfach zu hacken, zu konfigurieren oder direkt für Erweiterbarkeit geschlossen.
Darüber hinaus arbeiten die meisten dieser Lösungen nur auf der TCP-L3-Ebene, anstatt hochrangige Abstraktionen zu bieten, um allgemeine Anforderungen im spezifischen Bereich und der Natur des HTTP-L7-Protokolls abzudecken, wie toxy es versucht.
toxy bietet eine leistungsstarke hackbare und erweiterbare Lösung mit einer praktischen Abstraktion, ohne dabei die Fähigkeiten einer angemessenen Low-Level-Schnittstelle zur einfachen Handhabung von HTTP-Protokoll-Primitiven zu verlieren.
toxy wurde basierend auf den Prinzipien der Komposition, Einfachheit und Erweiterbarkeit entwickelt. Über seine integrierte hierarchische domänenspezifische Middleware-Schicht können Sie die Funktionen von toxy einfach an Ihre eigenen Bedürfnisse anpassen.
toxy führt zwei Direktiven ein: Gifte und Regeln.
Gifte sind die spezifische Logik, die eine eingehende oder ausgehende HTTP-Transaktion infiziert (z. B. eine Latenz injizieren, mit einem Fehler antworten). Eine HTTP-Transaktion kann von einem oder mehreren Giften vergiftet werden, und diese Gifte können auch so konfiguriert werden, dass sie sowohl den globalen als auch den Routenverkehr infizieren.
Regeln sind eine Art von Übereinstimmungsvalidierungsfiltern, die eine HTTP-Anfrage/Antwort inspizieren, um festzustellen, ob die HTTP-Transaktion vergiftet werden soll oder nicht (z. B. wenn Header übereinstimmen, Abfrageparameter, Methode, Body...). Regeln können wiederverwendet und sowohl auf eingehende als auch auf ausgehende Datenverkehrsflüsse angewendet werden, einschließlich verschiedener Bereiche: global, Route oder Vergiftungsebene.
↓ ( Incoming request ) ↓ ↓ ||| ↓ ↓ +-------------+ ↓ ↓ | Toxy Router | ↓ -> Match the incoming request ↓ +-------------+ ↓ ↓ ||| ↓ ↓ +--------------------+ ↓ ↓ | Incoming phase | ↓ -> The proxy receives the request from the client ↓ |~~~~~~~~~~~~~~~~~~~~| ↓ ↓ | ---------------- | ↓ ↓ | | Exec Rules | | ↓ -> Apply configured rules for the incoming request ↓ | ---------------- | ↓ ↓ | ||| | ↓ ↓ | ---------------- | ↓ ↓ | | Exec Poisons | | ↓ -> If all rules passed, then poison the HTTP flow ↓ | ---------------- | ↓ ↓ +~~~~~~~~~~~~~~~~~~~~+ ↓ ↓ / \ ↓ ↓ \ / ↓ ↓ +--------------------+ ↓ ↓ | HTTP dispatcher | ↓ -> Forward the HTTP traffic to the target server, either poisoned or not ↓ +--------------------+ ↓ ↓ / \ ↓ ↓ \ / ↓ ↓ +--------------------+ ↓ ↓ | Outgoing phase | ↓ -> Receives response from target server ↓ |~~~~~~~~~~~~~~~~~~~~| ↓ ↓ | ---------------- | ↓ ↓ | | Exec Rules | | ↓ -> Apply configured rules for the outgoing request ↓ | ---------------- | ↓ ↓ | ||| | ↓ ↓ | ---------------- | ↓ ↓ | | Exec Poisons | | ↓ -> If all rules passed, then poison the HTTP flow before send it to the client ↓ | ---------------- | ↓ ↓ +~~~~~~~~~~~~~~~~~~~~+ ↓ ↓ ||| ↓ ↓ ( Send to the client ) ↓ -> Finally, send the request to the client, either poisoned or not
## Verwendung
### Installation```
npm install toxy
Siehe examples-Verzeichnis für weitere Anwendungsfälle.```js var toxy = require('toxy') var poisons = toxy.poisons var rules = toxy.rules
// Create a new toxy proxy var proxy = toxy()
// Default server to forward incoming traffic proxy .forward('http://httpbin.org')
// Register global poisons and rules proxy .poison(poisons.latency({ jitter: 500 })) .rule(rules.probability(25))
// Register multiple routes proxy .get('/download/') .forward('http://files.myserver.net') .poison(poisons.bandwidth({ bps: 1024 })) .withRule(rules.headers({'Authorization': /^Bearer (.)$/i }))
// Infect outgoing traffic only (after the server replied properly) proxy .get('/image/*') .outgoingPoison(poisons.bandwidth({ bps: 512 })) .withRule(rules.method('GET')) .withRule(rules.timeThreshold({ duration: 1000, threshold: 1000 * 10 })) .withRule(rules.responseStatus({ range: [ 200, 400 ] }))
proxy .all('/api/*') .poison(poisons.rateLimit({ limit: 10, threshold: 1000 })) .withRule(rules.method(['POST', 'PUT', 'DELETE'])) // And use a different more permissive poison for GET requests .poison(poisons.rateLimit({ limit: 50, threshold: 1000 })) .withRule(rules.method('GET'))
// Handle the rest of the traffic proxy .all('/*') .poison(poisons.slowClose({ delay: 1000 })) .poison(poisons.slowRead({ bps: 128 })) .withRule(rules.probability(50))
proxy.listen(3000) console.log('Server listening on port:', 3000) console.log('Test it:', 'http://localhost:3000/image/jpeg')
## Benchmark
Siehe [toxy/benchmark](https://github.com/h2non/toxy/tree/master/benchmark) für Details.
## Poisons
Poisons hosten spezifische Logik, die eine HTTP-Transaktion im Proxy-Server abfängt, verändert, umschließt, modifiziert und/oder abbricht.
Poisons können auf eingehenden oder ausgehenden oder sogar auf beide Datenverkehrsflüsse angewendet werden (siehe [Poisoning Phasen](#poisoning-phases)).
Poisons können für verschiedene HTTP-Szenarien zusammengesetzt und wiederverwendet werden.
Sie werden asynchron in FIFO-Reihenfolge ausgeführt.
### Poisoning-Bereiche
`toxy` hat ein hierarchisches Design, das auf zwei verschiedenen Bereichen basiert: `global` und `route`.
Der **globale** Bereich bezieht sich auf den gesamten eingehenden HTTP-Datenverkehr, der vom Proxy-Server empfangen wird, unabhängig von HTTP-Methode oder Pfad.
Der **Route**-Bereich bezieht sich auf eingehenden Datenverkehr, der mit einem bestimmten HTTP-Verb und URI-Pfad übereinstimmt.
Poisons können an beide Bereiche angeschlossen werden, was bedeutet, dass Sie mit größerer Genauigkeit arbeiten und den Umfang der Vergiftung einschränken können,
zum Beispiel möchten Sie vielleicht eine Bandbreitenbegrenzungsvergiftung nur auf
bestimmte Routen anwenden, z. B. `/download` oder `/images`.
Siehe [routes.js](https://github.com/h2non/toxy/blob/master/examples/routes.js) für ein detailliertes Beispiel.
### Poisoning-Phasen
Poisons können an eingehende oder ausgehende Datenverkehrsflüsse oder sogar an beide angeschlossen werden.
**Eingehende** Vergiftung wird angewendet, wenn der Datenverkehr vom Proxy empfangen wurde,
aber noch nicht an den Zielserver weitergeleitet wurde.
**Ausgehende** Vergiftung bezieht sich auf den Datenverkehr, der an den Zielserver weitergeleitet wurde und
wenn der Proxy die Antwort von ihm empfängt, diese Antwort jedoch noch nicht an den Client gesendet wurde.
Das bedeutet im Wesentlichen, dass Sie Ihre Poisons einstecken können, um den HTTP-Datenverkehr zu infizieren,
bevor oder nachdem die Anfrage an den Ziel-HTTP-Server weitergeleitet oder an den Client gesendet wurde.
Dadurch können Sie eine bessere und genauere Vergiftung basierend auf der Anfrage oder Serverantwort anwenden.
Zum Beispiel möchten Sie aufgrund der Natur einiger Poisons, wie `inject error`,
diese möglicherweise basierend auf der Antwort des Zielservers aktivieren (z. B. ob ein bestimmter Header vorhanden ist oder nicht).
Siehe [poison-phases.js](https://github.com/h2non/toxy/blob/master/examples/poison-phases.js) für ein detailliertes Beispiel.
### Integrierte Poisons
#### Latenz
<table>
<tr>
<td><b>Name</b></td><td>latency</td>
</tr>
<tr>
<td><b>Poisoning Phase</b></td><td>incoming / outgoing</td>
</tr>
<tr>
<td><b>Erreicht den Server</b></td><td>true</td>
</tr>
</table>
Infiziert den HTTP-Fluss, indem ein Latenzjitter in die Antwort eingefügt wird
**Argumente**:
- **options** `object`
- **jitter** `number` - Jitter-Wert in Millisekunden
- **max** `number` - Maximaler Zufallsjitter
- **min** `number` - Minimaler Zufallsjitter```js
toxy.poison(toxy.poisons.latency({ jitter: 1000 }))
// Or alternatively using a random value
toxy.poison(toxy.poisons.latency({ max: 1000, min: 100 }))
| Name | inject |
| Vergiftungsphase | eingehend / ausgehend |
| Erreicht den Server | falsch (nur als eingehende Vergiftung) |
Fügt eine benutzerdefinierte Antwort ein, indem die Anfrage abgefangen wird, bevor sie an den Zielserver gesendet wird. Nützlich, um Fehler einzuschleusen, die vom Server stammen.
Argumente:
object
number - HTTP-Statuscode der Antwort. Standard 500object - Optionale zu sendende Headermixed - Optionale zu sendende Body-Daten. Es kann ein buffer oder string seinstring - Body-Kodierung. Standard `utf8````js
toxy.poison(toxy.poisons.inject({
code: 503,
body: '{"error": "toxy injected error"}',
headers: {'Content-Type': 'application/json'}
}))#### Bandwidth
<table>
<tr>
<td><b>Name</b></td><td>bandwidth</td>
</tr>
<tr>
<td><b>Poisoning Phase</b></td><td>incoming / outgoing</td>
</tr>
<tr>
<td><b>Reaches the server</b></td><td>true</td>
</tr>
</table>
Begrenzt die Anzahl der Bytes, die in einem bestimmten Zeitrahmen über das Netzwerk im ausgehenden HTTP-Verkehr gesendet werden.
Dieses Poison ist im Wesentlichen ein Alias für [throttle](#throttle).
**Argumente**:
- **options** `object`
- **bytes** `number` – Menge der zu sendenden Byte-Blöcke. Standard `1024`
- **threshold** `number` – Zeitrahmen für Pakete in Millisekunden. Standard `1000````js
toxy.poison(toxy.poisons.bandwidth({ bytes: 512 }))
| Name | rateLimit |
| Vergiftungsphase | eingehend / ausgehend |
| Erreicht den Server | true |
Begrenzt die Anzahl der Anfragen, die der Proxy in einem bestimmten Zeitrahmen erhält. Entwickelt, um API-Limits zu testen. Gibt typische X-RateLimit-*-Header aus.
Beachten Sie, dass dies eine sehr einfache Implementierung der Ratenbegrenzung ist; die Limits werden tatsächlich im Arbeitsspeicher gespeichert und sind daher vollständig flüchtig. Es gibt eine Reihe von funktionsreichen und konsistenten Ratenbegrenzungs-Implementierungen in npm, die Sie als Gift einbinden können. Möglicherweise interessiert Sie auch der Token-Bucket-Algorithmus.
Argumente:
object
number – Gesamtanzahl der Anfragen. Standardmäßig 10number – Zeitrahmen in Millisekunden. Standardmäßig 1000string – Optionale Fehlermeldung, wenn das Limit erreicht ist.number – HTTP-Statuscode, wenn das Limit erreicht ist. Standardmäßig 429.```js
toxy.poison(toxy.poisons.rateLimit({ limit: 5, threshold: 10 * 1000 }))#### Langsames Lesen
<table>
<tr>
<td><b>Name</b></td><td>slowRead</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>incoming</td>
</tr>
<tr>
<td><b>Erreicht den Server</b></td><td>true</td>
</tr>
</table>
Liest eingehende Payload-Datenpakete langsam. Nur gültig für Nicht-GET-Anfragen.
**Argumente**:
- **options** `object`
- **chunk** `number` - Paket-Chunk-Größe in Bytes. Standardmäßig `1024`
- **threshold** `number` - Grenzschwellenwert-Zeitrahmen in Millisekunden. Standardmäßig `1000````js
toxy.poison(toxy.poisons.slowRead({ chunk: 2048, threshold: 1000 }))
Name: slowOpen
| Name | slowOpen |
| Vergiftungsphase | eingehend |
| Erreicht den Server | wahr |
Verzögert den Bereitschaftszustand der HTTP-Verbindung.
Argumente:
object
number - Verzögerung der Verbindung in Millisekunden. Standardwert: `1000````js
toxy.poison(toxy.poisons.slowOpen({ delay: 2000 }))#### Slow close
<table>
<tr>
<td><b>Name</b></td><td>slowClose</td>
</tr>
<tr>
<td><b>Poisoning Phase</b></td><td>incoming / outgoing</td>
</tr>
<tr>
<td><b>Reaches the server</b></td><td>true</td>
</tr>
</table>
Verzögert das HTTP-Verbindungssignal zum Schließen (EOF).
**Argumente**:
- **options** `object`
- **delay** `number` - Verzögerungszeit in Millisekunden. Standardwert ist `1000````js
toxy.poison(toxy.poisons.slowClose({ delay: 2000 }))
| Name | throttle |
| Vergiftungsphase | eingehend / ausgehend |
| Erreicht den Server | true |
Beschränkt die Anzahl der über das Netzwerk gesendeten Pakete innerhalb eines bestimmten Zeitrahmens.
Argumente:
object
number - Größe des Paketblocks in Bytes. Standardmäßig 1024object - Verzögerungszeit für den Datenblock in Millisekunden. Standardmäßig `100````js
toxy.poison(toxy.poisons.throttle({ chunk: 2048, threshold: 1000 }))#### Verbindung abbrechen
<table>
<tr>
<td><b>Name</b></td><td>abort</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>eingehend / ausgehend</td>
</tr>
<tr>
<td><b>Erreicht den Server</b></td><td>false (nur als eingehendes Gift)</td>
</tr>
</table>
Bricht die TCP-Verbindung ab. Aus der Low-Level-Perspektive wird dies den Socket auf dem Server zerstören, indem es nur auf TCP-Ebene arbeitet, ohne spezifische HTTP-Anwendungsdaten zu senden.
**Argumente**:
- **options** `object`
- **delay** `number` - Bricht die TCP-Verbindung nach dem Warten der angegebenen Millisekunden ab. Standard: `0`
- **next** `boolean` - Wenn `true`, wird die Verbindung abgebrochen, wenn der Zielserver mehr Zeit als den `delay`-Parameter benötigt, um zu antworten. Standard: `false`
- **error** `Error` - Benutzerdefinierter interner node.js-Fehler, der beim Zerstören des Sockets verwendet wird. Standard: `null````js
// Basic connection abort
toxy.poison(toxy.poisons.abort())
// Abort after a delay
toxy.poison(toxy.poisons.abort(1000))
// In this case, the socket will be closed if
// the target server takes more than
// 2 seconds to respond
toxy.poison(toxy.poisons.abort({ delay: 2000, next: true }))
| Name | timeout |
| Poisoning Phase | incoming / outgoing |
| Reaches the server | true |
Definiert ein Antwort-Timeout. Nützlich bei Weiterleitung an potenziell langsame Server.
Argumente:
number - Timeout-Limit in Millisekunden```js
toxy.poison(toxy.poisons.timeout(5000))### Wie man Gifte schreibt
Gifte werden als standardmäßige Middleware-Funktionen mit der gleichen Schnittstelle wie connect/express-Middleware implementiert.
Einige Gifte sind nicht trivial zu implementieren, daher müssen Sie mit dem Node.js [http](https://nodejs.org/api/http.html)-Modul und seiner API vertraut sein.
Hier ist ein einfaches Beispiel für ein Server-Latenz-Gift:```js
var toxy = require('toxy')
function customLatencyPoison (delay) {
// We name the function since toxy uses it as identifier to get/disable/remove it in the future
return function customLatency (req, res, next) {
var timeout = setTimeout(process, delay)
req.once('close', onClose)
function onClose () {
clearTimeout(timeout)
next('client connection closed')
}
function process () {
req.removeListener('close', onClose)
next()
}
}
}
var proxy = toxy()
// Register and enable the poison
proxy
.get('/foo')
.poison(customLatencyPoison(2000))
Sie können optional die eingebauten Gifte mit Ihren eigenen Giften erweitern:```js toxy.addPoison(customLatency)
// Then you can use it as a built-in poison proxy .get('/foo') .poison(toxy.poisons.customLatency)
Ein praktisches Beispiel finden Sie in der Implementierung der [eingebauten Gifte](https://github.com/h2non/toxy/tree/master/lib/poisons).
## Regeln
Regeln sind einfache Validierungsfilter, die eingehenden oder ausgehenden HTTP-Verkehr überprüfen, um anhand bestimmter Regeln (z. B. Übereinstimmung mit Methode, Headern, Query-Parametern, Body...) zu bestimmen, ob die aktuelle HTTP-Transaktion vergiftet werden soll oder nicht, basierend auf dem Erfüllungswert der Regel.
Regeln sind nützlich, um Logik in verschiedenen Vergiftungsszenarien zu kombinieren, zu entkoppeln und wiederzuverwenden.
Regeln können auf globalen, Routen- oder sogar Vergiftungsbereich angewendet werden und gelten auch für beide [Vergiftungsphasen](#poisoning-phases).
Regeln werden in der FIFO-Reihenfolge ausgeführt. Ihre Auswertungslogik entspricht `Array#every()` in JavaScript: Alle Regeln müssen bestanden werden, um mit der Vergiftung fortzufahren.
### Eingebaute Regeln
#### Wahrscheinlichkeit
<table>
<tr>
<td><b>Name</b></td><td>Wahrscheinlichkeit</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>eingehend / ausgehend</td>
</tr>
</table>
Aktiviert die Regel mit einer zufälligen Wahrscheinlichkeit. Nützlich für zufällige Vergiftungen.
**Argumente**:
- **percentage** `number` - Prozentsatz der Filterung. Standard `50````js
var rule = toxy.rules.probability(85)
toxy.rule(rule)
| Name | timeThreshold |
| Vergiftungsphase | incoming / outgoing |
Einfache Regel, um Vergiftungen basierend auf einer bestimmten Zeitschwelle und Dauer zu aktivieren. Zum Beispiel können Sie eine bestimmte Vergiftung für eine bestimmte Zeitspanne (z. B. 1 Sekunde) innerhalb einer Zeitschwelle (z. B. 1 Minute) aktivieren.
Argumente:
object
number – Zeitintervall in Millisekunden aktivieren. Standardwert: 1000number – Zeitschwelle in Millisekunden, die gewartet werden muss, bevor die Vergiftung wieder aktiviert wird. Standardwert: `10000````js
// Enable the poisoning only 100 milliseconds per each 10 seconds
proxy.rule(toxy.rules.timeThreshold(100))
// Enable poisoning during 1 second every minute
proxy.rule(toxy.rules.timeThreshold({ duration: 1000, period: 1000 * 60 }))#### Methode
<table>
<tr>
<td><b>Name</b></td><td>method</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>eingehend / ausgehend</td>
</tr>
</table>
Filtert nach HTTP-Methode.
**Argumente**:
- **method** `string|array` - Methode oder Methoden zum Filtern.```js
var method = toxy.rules.method(['GET', 'POST'])
toxy.rule(method)
Filtert nach dem Content-Type-Header. Er sollte vorhanden sein.
Arguments:
string|regexp - Header-Wert zum Abgleich.```js
var rule = toxy.rules.contentType('application/json')
toxy.rule(rule)#### Headers
<table>
<tr>
<td><b>Name</b></td><td>headers</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>eingehend / ausgehend</td>
</tr>
</table>
Nach Anfrage-Headern filtern.
**Argumente**:
- **headers** `object` - Header, die nach Schlüssel-Wert-Paar abgeglichen werden. `value` kann ein string, regexp, `boolean` oder `function(headerValue, headerName) => boolean` sein.```js
var matchHeaders = {
'content-type': /^application/\json/i,
'server': true, // meaning it should be present,
'accept': function (value, key) {
return value.indexOf('text') !== -1
}
}
var rule = toxy.rules.headers(matchHeaders)
toxy.rule(rule)
| Name | responseHeaders |
| Vergiftungsphase | outgoing |
Filter nach Antwort-Headern vom Zielserver. Gleiche wie die headers-Regel, aber für die ausgehende Anfrage.
Argumente:
object - Header, die nach Schlüssel-Wert-Paar abgeglichen werden sollen. value kann ein string, regexp, boolean oder function(headerValue, headerName) => boolean sein.```js
var matchHeaders = {
'content-type': /^application/\json/i,
'server': true, // meaning it should be present,
'accept': function (value, key) {
return value.indexOf('text') !== -1
}
}var rule = toxy.rules.responseHeaders(matchHeaders) toxy.rule(rule)
#### Body
<table>
<tr>
<td><b>Name</b></td><td>Body</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>eingehend / ausgehend</td>
</tr>
</table>
Stimme die eingehende Body-Nutzlast mit einem angegebenen `string`, `regexp` oder benutzerdefinierten Filter `function` ab.
Diese Regel ist recht einfach, daher solltest du für komplexes Body-Matching (z.B. Validierung gegen ein JSON-Schema) wahrscheinlich deine eigene Regel schreiben.
**Argumente**:
- **match** `string|regexp|function` – Zu vergleichender Body-Inhalt
- **limit** `string` – Optional. Body-Limit in menschenlesbarer Größe. Z.B: `5mb`
- **encoding** `string` – Body-Kodierung. Standardmäßig `utf8`
- **length** `number` – Body-Länge. Standardmäßig aus dem `Content-Length`-Header entnommen```js
var rule = toxy.rules.body('"hello":"world"')
toxy.rule(rule)
// Or using a filter function returning a boolean
var rule = toxy.rules.body(function contains(body) {
return body.indexOf('hello') !== -1
})
toxy.rule(rule)
| Name | responseBody |
| Poison Phase | outgoing |
Übereinstimmung der ausgehenden Body-Nutzlast anhand eines gegebenen string, regexp oder einer benutzerdefinierten Filter-function.
Argumente:
string|regexp|function – Zu vergleichender Body-Inhaltstring – Body-Kodierung. Standard ist utf8number – Body-Länge. Standardwert wird aus dem Content-Length-Header übernommen.```js
var rule = toxy.rules.responseBody('"hello":"world"')
toxy.rule(rule)// Or using a filter function returning a boolean var rule = toxy.rules.responseBody(function contains(body) { return body.indexOf('hello') !== -1 }) toxy.rule(rule)
#### Antwortstatus
<table>
<tr>
<td><b>Name</b></td><td>responseStatus</td>
</tr>
<tr>
<td><b>Vergiftungsphase</b></td><td>ausgehend</td>
</tr>
</table>
Bewertet den Antwortstatus des Zielservers.
Nur anwendbar auf ausgehende Vergiftungen.
**Argumente**:
- **range** `array` - Paar von Statuscode-Bereichen zum Abgleichen. Standard `[200, 300]`.
- **lower** `number` - Vergleicht Status als `lower than`-Operation. Standardmäßig `null`.
- **higher** `number` - Vergleicht Status als `higher than`-Operation. Standardmäßig `null`.
- **value** `number` - Statuscode zum Abgleichen mittels striktem Gleichheitsvergleich. Standardmäßig `null`.
- **include** `array` - Unsortierte Liste von Statuscodes zum Abgleichen. Nützlich, um benutzerdefinierte Status anzugeben. Standardmäßig `null`.```js
// Strict evaluation of the status code
toxy.rule(toxy.rules.responseBody(200))
// Using a range of valid status
toxy.rule(toxy.rules.responseBody([200, 204]))
// Using relational comparison
toxy.rule(toxy.rules.responseBody({ higher: 199, lower: 400 }))
// Custom unordered status code to match
toxy.rule(toxy.rules.responseBody({ include: [200, 204, 400, 404] }))
Liste der von der Community bereitgestellten Drittanbieter-Regeln. PRs sind willkommen.
Regeln sind einfache Middleware-Funktionen, die asynchron mit einem boolean-Wert auflösen, um zu bestimmen, ob eine bestimmte HTTP-Transaktion beim Vergiften ignoriert werden soll.
Ihre Regel muss mit einem boolean-Parameter auflösen, indem sie die Funktion next(err, shouldIgnore) in der Middleware aufruft und einen true-Wert übergibt, wenn die Regel keine Übereinstimmungen hat und die Vergiftung nicht angewendet werden soll, und somit mit dem nächsten Middleware-Stack fortfährt.
Hier ist ein Beispiel einer einfachen Regel, die die HTTP-Methode abgleicht, um zu bestimmen, ob:```js var toxy = require('toxy')
function customMethodRule(matchMethod) { /**
var proxy = toxy()
// Register and enable the rule proxy .get('/foo') .rule(customMethodRule('GET')) .poison(/* ... */)
Sie können optional die eingebauten Regeln mit Ihren eigenen Regeln erweitern:```js
toxy.addRule(customMethodRule)
// Then you can use it as a built-in poison
proxy
.get('/foo')
.rules(toxy.rules.customMethodRule)
Schauen Sie sich für praktische Beispiele die integrierten Regeln Implementierung an.
Die toxy-API ist vollständig auf der rocky-API aufgebaut. Mit anderen Worten, Sie können alle Methoden, Funktionen und die Middleware-Schicht nutzen, die nativ von rocky bereitgestellt werden.
Erstellt einen neuen toxy-Proxy.
Unterstützte options finden Sie in der rocky Dokumentation.```js
var toxy = require('toxy')
toxy({ forward: 'http://server.net', timeout: 30000 })
toxy .get('/foo') .poison(toxy.poisons.latency(1000)) .withRule(toxy.rules.contentType('json')) .forward('http://foo.server')
toxy .post('/bar') .poison(toxy.poisons.bandwidth({ bps: 1024 })) .withRule(toxy.rules.probability(50)) .forward('http://bar.server')
toxy .post('/boo') .outgoingPoison(toxy.poisons.bandwidth({ bps: 1024 })) .withRule(toxy.rules.method('GET')) .forward('http://boo.server')
toxy.all('/*')
toxy.listen(3000)
#### toxy#get(path, [ middleware... ])
Rückgabe: `ToxyRoute`
Registriert eine neue Route für die `GET`-Methode.
#### toxy#post(path, [ middleware... ])
Rückgabe: `ToxyRoute`
Registriert eine neue Route für die `POST`-Methode.
#### toxy#put(path, [ middleware... ])
Rückgabe: `ToxyRoute`
Registriert eine neue Route für die `PUT`-Methode.
#### toxy#patch(path, [ middleware... ])
Rückgabe: `ToxyRoute`
#### toxy#delete(path, [ middleware... ])
Rückgabe: `ToxyRoute`
Registriert eine neue Route für die `DELETE`-Methode.
#### toxy#head(path, [ middleware... ])
Rückgabe: `ToxyRoute`
Registriert eine neue Route für die `HEAD`-Methode.
#### toxy#all(path, [ middleware... ])
Rückgabe: `ToxyRoute`
Registriert eine neue Route für jede Methode.
#### toxy#poisons `=>` Object
Stellt eine Map mit den integrierten Poisons bereit. Prototyp-Alias zu `toxy.poisons`
#### toxy#rules `=>` Object
Stellt eine Map mit den integrierten Regeln bereit. Prototyp-Alias zu `toxy.rules`
#### toxy#forward(url)
Definiert eine URL, an die der vom Proxy empfangene eingehende Datenverkehr weitergeleitet wird.
#### toxy#balance(urls)
Leitet an mehrere Server weiter und verteilt die Last auf diese.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#programmatic-api)
#### toxy#replay(url)
Definiert einen neuen Wiedergabeserver.
Sie können diese Methode mehrmals aufrufen, um mehrere Wiedergabeserver zu definieren.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#programmatic-api)
#### toxy#use(middleware)
Bindet eine benutzerdefinierte Middleware ein.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#middleware-layer).
#### toxy#useResponse(middleware)
Bindet eine Middleware für ausgehenden Antwortdatenverkehr ein.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#middleware-layer).
#### toxy#useReplay(middleware)
Bindet eine Middleware für Wiedergabedatenverkehr ein.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#middleware-layer)
#### toxy#requestBody(middleware)
Fängt den eingehenden Anforderungstext ab. Nützlich, um ihn spontan zu ändern.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#programmatic-api)
#### toxy#responseBody(middleware)
Fängt den ausgehenden Antworttext ab. Nützlich, um ihn spontan zu ändern.
Weitere Informationen finden Sie in der [rocky-Dokumentation](https://github.com/h2non/rocky#programmatic-api)
#### toxy#middleware()
Gibt eine Standard-Middleware zur Verwendung mit connect/express zurück.
#### toxy#host(host)
Überschreibt den `Host`-Header mit einem benutzerdefinierten Wert. Ähnlich der Option `forwardHost`.
#### toxy#redirect(url)
Leitet den Datenverkehr an die angegebene URL um.
#### toxy#findRoute(routeIdOrPath, [ method ])
Findet eine Route anhand von ID oder Pfad und Methode.
#### toxy#listen(port)
Startet den integrierten HTTP-Server und lauscht auf einem bestimmten TCP-Port.
#### toxy#close([ callback ])
Schließt den HTTP-Server.
#### toxy#poison(poison)
Alias: `usePoison`, `useIncomingPoison`
Registriert ein neues Poison, um [eingehenden](#poisoning-phases) Datenverkehr zu infizieren.
#### toxy#outgoingPoison(poison)
Alias: `useOutgoingPoison`, `responsePoison`
Registriert ein neues Poison, um [ausgehenden](#poisoning-phases) Datenverkehr zu infizieren.
#### toxy#rule(rule)
Alias: `useRule`
Registriert eine neue Regel.
#### toxy#withRule(rule)
Aliase: `ifRule`, `whenRule`, `poisonRule`, `poisonFilter`
Wendet eine neue Regel auf das zuletzt registrierte Poison an.
#### toxy#enable(poison)
Aktiviert ein Poison anhand des Namensidentifikators.
#### toxy#disable(poison)
Deaktiviert ein Poison anhand des Namensidentifikators.
#### toxy#remove(poison)
Rückgabe: `boolean`
Entfernt ein eingehendes Datenverkehr-Poison anhand des Namensidentifikators oder der Objektreferenz.
#### toxy#removeOutgoing(poison)
Rückgabe: `boolean`
Entfernt ein ausgehendes Datenverkehr-Poison anhand des Namensidentifikators oder der Objektreferenz.
#### toxy#isEnabled(poison)
Rückgabe: `boolean`
Prüft, ob ein Poison anhand des Namensidentifikators aktiviert ist.
#### toxy#disableAll()
Alias: `disablePoisons`
Deaktiviert alle registrierten Poisons.
#### toxy#getPoison(name)
Rückgabe: `Directive|null`
Sucht und ruft ein registriertes Poison aus dem Stapel anhand des Namensidentifikators ab.
#### toxy#getIncomingPoison(name)
Rückgabe: `Directive|null`
Sucht und ruft ein registriertes `incoming`-Poison aus dem Stapel anhand des Namensidentifikators ab.
#### toxy#getOutgoingPoison(name)
Rückgabe: `Directive|null`
Sucht und ruft ein registriertes `outgoing`-Poison aus dem Stapel anhand des Namensidentifikators ab.
#### toxy#getPoisons()
Rückgabe: `array<Directive>`
Gibt ein Array der registrierten Poisons zurück.
#### toxy#getIncomingPoisons()
Rückgabe: `array<Directive>`
Gibt ein Array der registrierten `incoming`-Poisons zurück.
#### toxy#getOutgoingPoisons()
Rückgabe: `array<Directive>`
Gibt ein Array der registrierten `outgoing`-Poisons zurück.
#### toxy#flush()
Alias: `flushPoisons`
Entfernt alle registrierten Poisons für sowohl eingehende als auch ausgehende Datenverkehrsflüsse.
#### toxy#enableRule(rule)
Aktiviert eine Regel anhand des Namensidentifikators.
#### toxy#disableRule(rule)
Deaktiviert eine Regel anhand des Namensidentifikators.
#### toxy#removeRule(rule)
Rückgabe: `boolean`
Entfernt eine Regel anhand des Namensidentifikators.
#### toxy#disableRules()
Deaktiviert alle registrierten Regeln.
#### toxy#isRuleEnabled(rule)
Rückgabe: `boolean`
Prüft, ob die angegebene Regel anhand des Namensidentifikators aktiviert ist.
#### toxy#getRule(rule)
Rückgabe: `Directive|null`
Sucht und ruft eine registrierte Regel aus dem Stapel anhand des Namensidentifikators ab.
#### toxy#getRules()
Rückgabe: `array<Directive>`
Gibt ein Array mit den registrierten Regeln zurück, die als `Directive` verpackt sind.
#### toxy#flushRules()
Entfernt alle Regeln.
### toxy.addPoison(name, fn)
Erweitert die integrierten Poisons.
### toxy.addRule(name, fn)
Erweitert die integrierten Regeln.
### toxy.poisons `=>` Object
Stellt eine Map mit den integrierten Poisons bereit.
### toxy.rules `=>` Object
Stellt eine Map mit den integrierten Regeln bereit.
### toxy.VERSION `=>` String
Aktuelle semantische Version von toxy.
### ToxyRoute
`ToxyRoute` stellt die gleiche Schnittstelle bereit wie das globale `Toxy`-Interface, fügt jedoch einige zusätzliche Methoden auf Routenebene hinzu (siehe [rocky-Dokumentation](https://github.com/h2non/rocky#routepath)).
Weitere Aktionen, die Sie über die `ToxyRoute`-API ausführen, gelten nur auf Routenebene (verschachtelt). Mit anderen Worten: Sie kennen die API bereits.
Dieses Beispiel wird mögliche Zweifel wahrscheinlich klären:```js
var toxy = require('toxy')
var proxy = toxy()
// Now using the global API
proxy
.forward('http://server.net')
.poison(toxy.poisons.bandwidth({ bps: 1024 }))
.rule(toxy.rules.method('GET'))
// Now create a route
var route = proxy
.get('/foo')
.toPath('/bar') // Route-level API method
.host('server.net') // Route-level API method
.forward('http://new.server.net')
// Now using the ToxyRoute interface
route
.poison(toxy.poisons.bandwidth({ bps: 512 }))
.rule(toxy.rules.contentType('json'))
Ein praktischer Wrapper, der intern für Gifte und Regeln verwendet wird.
Normalerweise müssen Sie diese Schnittstelle nicht kennen, aber für Hacking-Zwecke oder niedrigschwelligere Aktionen könnte sie nützlich sein.
Rückgabe: boolean
Rückgabe: boolean
Rückgabe: boolean
Alias: filter
Rückgabe: function(req, res, next)
Die toxy HTTP-API folgt den JSON API-Konventionen, einschließlich ressourcenbasierter Hypermedia-Verknüpfung.
Für einen exemplarischen Anwendungsfall siehe das Admin-Server-Beispiel.```js const toxy = require('toxy')
// Create the toxy admin server var admin = toxy.admin({ cors: true }) 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)
// Then configure the proxy proxy .forward('http://my.target.net')
proxy .get('/slow') .poison(toxy.poisons.bandwidth({ bps: 1024 }))
// Handle the rest of the traffic proxy .all('/*') .poison(toxy.poisons.bandwidth({ bps: 1024 * 5 }))
console.log('toxy proxy listening on port:', 3000) console.log('toxy admin server listening on port:', 9000)
Weitere Details zur programmatischen API des Admin finden Sie [unten](#programmatic-api-1).
### Autorisierung
Die HTTP-API kann vor nicht autorisierten Clients geschützt werden.
Autorisierte Clients müssen den API-Key-Token über die HTTP-Header `API-Key` oder `Authorization` definieren.
Um dies zu aktivieren, übergeben Sie einfach die folgenden Optionen an den `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)
Hierarchie:
toxy-Instanzen
Akzeptiert: application/json
Beispiel-Payload:```js { "name": "method", "options": "GET" }
#### DELETE /servers/:id/rules
#### GET /servers/:id/rules/:id
#### DELETE /servers/:id/rules/:id
### Vergiftungen
#### GET /servers/:id/poison
#### POST /servers/:id/poisons
Akzeptiert: `application/json`
Beispiel-Payload:```js
{
"name": "latency",
"phase": "outgoing",
"options": { "jitter": 1000 }
}
Akzeptiert: application/json
Beispiel-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
Akzeptiert: `application/json`
Beispiel-Payload:```js
{
"path": "/foo", // Required
"method": "GET", // use ALL for all the methods
"forward": "http://my.server", // Optional custom forward server URL
}
Akzeptiert: application/json
Beispiel-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
Akzeptiert: `application/json`
Beispiel-Nutzlast:```js
{
"name": "latency",
"phase": "outgoing",
"options": { "jitter": 1000 }
}
Akzeptiert: application/json
Beispiel-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
### Programmatische API
Der integrierte HTTP-Administrationsserver bietet zudem eine einfache Schnittstelle, die für Erweiterbarkeit und Hacking-Zwecke offen ist.
Beispielsweise können Sie zusätzliche Middleware in den Admin-Server einbinden oder neue Routen registrieren.
#### toxy.admin([ opts ])
Gibt zurück: `Admin`
**Unterstützte Optionen**:
- **apiKey** `string` - Optionaler API-Schlüssel zum Schutz des Servers
- **port** `number` - Optional. TCP-Port zum Abhören
- **cors** `boolean` - CORS für Webbrowser-Zugriff aktivieren
- **middleware** `array<function>` - Zusätzliche Middleware einbinden
- **ssl** `object` - Node.js HTTPS-Server [TLS-Optionen](https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener).
##### Admin#listen([ port, host ])
Startet das Lauschen im Netzwerk.
##### Admin#manage(toxy)
Verwaltet eine `toxy`-Serverinstanz.
##### Admin#find(toxy)
Findet eine toxy-Instanz. Akzeptiert eine toxy-Server-ID oder eine toxy-Instanz.
##### Admin#remove(toxy)
Beendet die Verwaltung einer toxy-Instanz.
##### Admin#use(...middleware)
Registriert eine Middleware.
##### Admin#param(...middleware)
Registriert eine Parameter-Middleware.
##### Admin#get(path, [ ...middleware ])
Registriert eine GET-Route.
##### Admin#post(path, [ ...middleware ])
Registriert eine POST-Route.
##### Admin#put(path, [ ...middleware ])
Registriert eine PUT-Route.
##### Admin#delete(path, [ ...middleware ])
Registriert eine DELETE-Route.
##### Admin#patch(path, [ ...middleware ])
Registriert eine PATCH-Route.
##### Admin#all(path, [ ...middleware ])
Registriert eine Route, die jede HTTP-Methode akzeptiert.
##### Admin#middleware(req, res, next)
Middleware zur Einbindung mit connect/express.
##### Admin#close(cb)
Stoppt den Server.
## Lizenz
MIT - Tomas Aparicio
[](https://sourcegraph.com/github.com/h2non/toxy)