UNPKG

9.19 kBMarkdownView Raw
1Mitm.js
2=======
3[![NPM version][npm-badge]](http://badge.fury.io/js/mitm)
4[![Build status][travis-badge]](https://travis-ci.org/moll/node-mitm)
5[npm-badge]: https://badge.fury.io/js/mitm.png
6[travis-badge]: https://travis-ci.org/moll/node-mitm.png?branch=master
7
8Mitm.js is a library for Node.js to **intercept and mock** outgoing network
9**TCP** and **HTTP** connections. Mitm.js intercepts and gives you
10a `Net.Socket` to communicate as if you were the remote server. For **HTTP
11requests** it even gives you `Http.IncomingMessage` and `Http.ServerResponse`
12— just like you're used to when writing Node.js servers. Except there's no
13actual server running, it's all just _In-Process Interception™_.
14
15Intercepting connections and requests is **extremely useful to test and ensure
16your code does what you expect**. Assert on request parameters and send back
17various responses to your code without ever having to hit the real network.
18**Fast as hell** and **a lot easier to develop with than external test
19servers**.
20
21Mitm.js should work both on the stable Node **v0.10.24** and up and **v0.11.11**
22and up and has **automated tests** to ensure it will stay that way.
23
24**Note**: This is a fairly early release of Mitm.js, so it might not cover all
25use cases you may come across. I've developed this on a need-to basis for
26testing [Monday Calendar][monday]'s syncing, so if you find a use-case I haven't
27come across, please fling me an [email][email], a [tweet][twitter] or [create an
28issue][issues] on GitHub.
29
30### Tour
31- Intercept both **TCP socket connections** (`Net.connect`) and **HTTP
32 requests** (`Http.request` and `Https.request`).
33
34- Hooks to Node.js's network functions at a **very low level** with the goal of
35 not having to patch existing classes and have everything behave as if bytes
36 were arriving from the network.
37
38- Does *not* have any kitchen sink features or yet another API to assert on
39 intercepted connections.
40 That's a different responsibility handled better by assertion libraries
41 (you'll do no better than to pick [Must.js][must] for that ;-).
42
43- Use an **API you already to know** to assert or respond to requests — Mitm.js
44 gives you access to a vanilla `Net.Socket` to respond with:
45
46 ```javascript
47 mitm.on("connection", function(socket) { socket.write("Hello back!") })
48
49 var socket = Net.connect(22, "example.org")
50 socket.write("Hello!")
51 socket.setEncoding("utf8")
52 socket.read() // => "Hello back!"
53 ```
54
55- When you do **HTTP or HTTPS** requests, Mitm.js gives you both
56 a `Http.IncomingMessage` and `Http.ServerResponse` to play the server with.
57 That means you'll be using an **API you're already familiar with**
58 rather than yet another idiosyncratic domain specific language.
59
60 Mitm.js comes very handy to ensure your code makes requests with the
61 appropriate parameters:
62 ```javascript
63 mitm.on("request", function(req, res) {
64 req.headers.authorization.must.equal("OAuth DEADBEEF")
65 })
66
67 Http.get("http://example.org")
68 ```
69
70 It's also useful to see if your code behaves as you'd expect if everything is
71 not `200 OK`:
72 ```javascript
73 mitm.on("request", function(req, res) {
74 res.statusCode = 402
75 res.end("Pay up, sugar!")
76 })
77
78 Http.get("http://example.org", function(res) {
79 res.setEncoding("utf8")
80 res.statusCode // => 402
81 res.on("data", console.log) // => "Pay up, sugar!"
82 })
83 ```
84
85 `Http.IncomingMessage` and `Http.ServerResponse` are the same objects
86 you get when you write Node.js HTTP servers with `Net.Server` or use a library
87 like [Express.js][express].
88
89- **Bypass** interception selectively for some connections (such as your SQL
90 server) and let them connect as usual.
91 ```javascript
92 mitm.on("connect", function(socket, opts) {
93 if (opts.host == "sql.example.org" && opts.port = 5432) socket.bypass()
94 })
95 ```
96
97- **Developed with automated tests**. Yeah, I know, why should one list this
98 a feature when writing tests is just a sign of professionalism and respect
99 towards other developers? But in a world where so many libraries and
100 "production" software are released without *any* tests, I like to point out
101 that I even write tests for testing libraries. ;-)
102
103[must]: https://github.com/moll/js-must
104[express]: http://expressjs.com
105
106
107Installing
108----------
109```
110npm install mitm
111```
112
113From v1.0.0 Mitm.js will follow [semantic versioning][semver], but until then,
114breaking changes may appear between minor versions (the middle number).
115
116[semver]: http://semver.org/
117
118
119Using
120-----
121Require Mitm.js and invoke it as a function to both create an instance of `Mitm`
122and enable intercepting:
123```javascript
124var Mitm = require("mitm")
125var mitm = Mitm()
126```
127
128Mitm.js will then intercept all requests until you disable it:
129```javascript
130mitm.disable()
131```
132
133### Intercepting in tests
134In tests, it's best to use the _before_ and _after_ hooks to enable and disable
135intercepting for each test case:
136```javascript
137beforeEach(function() { this.mitm = Mitm() })
138afterEach(function() { this.mitm.disable() })
139```
140
141### Intercepting TCP connections
142After you've called `Mitm()`, Mitm.js will intercept and emit `connection` on
143itself for each new connection.
144The `connection` event will be given a server side `Net.Socket` for you to reply
145with:
146
147```javascript
148mitm.on("connection", function(socket) { socket.write("Hello back!") })
149
150var socket = Net.connect(22, "example.org")
151socket.write("Hello!")
152socket.setEncoding("utf8")
153socket.read() // => "Hello back!"
154```
155
156### Intercepting HTTP/HTTPS requests
157After you've called `Mitm()`, Mitm.js will intercept and emit `request` on itself for each new HTTP or HTTPS request.
158The `request` event will be given a server side `Http.IncomingMessage` and
159`Http.ServerResponse`.
160
161For example, asserting on HTTP requests would look something like this:
162```javascript
163mitm.on("request", function(req, res) {
164 req.headers.authorization.must.equal("OAuth DEADBEEF")
165})
166
167Http.get("http://example.org")
168```
169
170Responding to requests is just as easy and exactly like you're used to from
171using Node.js HTTP servers (or from libraries like [Express.js][express]):
172```javascript
173mitm.on("request", function(req, res) {
174 res.statusCode = 402
175 res.end("Pay up, sugar!")
176})
177
178Http.get("http://example.org", function(res) {
179 res.statusCode // => 402
180 res.setEncoding("utf8")
181 res.on("data", console.log) // => "Pay up, sugar!"
182})
183```
184
185Please note that HTTPS requests are currently "morphed" into HTTP requests.
186That's to save us from having to set up certificates and disable their
187verification. But if you do need to test this, please ping me and we'll see if
188we can get Mitm.js to support that.
189
190### Bypassing interception
191You can bypass connections listening to the `connect` event on the Mitm instance
192and then calling `bypass` on the given socket. To help you do
193so selectively, `connect` is given the `options` object that was given to
194`Net.connect`:
195
196```javascript
197mitm.on("connect", function(socket, opts) {
198 if (opts.host == "sql.example.org" && opts.port = 5432) socket.bypass()
199})
200```
201
202Bypassed connections do **not** emit `connection` or `request` events. They're
203ignored by Mitm.js.
204
205In most cases you don't need to bypass because by the time you call `Mitm` in
206your tests to start intercepting, all of the long-running connections, such as
207database or cache connections, are already made.
208
209You might need to bypass connections you make to *localhost* when you're running
210integration tests against the HTTP server you started in the test process, but
211still want to intercept some other connections that this request might invoke.
212The following should suffice:
213
214```javascript
215mitm.on("connect", function(socket, opts) {
216 if (opts.host == "localhost") socket.bypass()
217})
218```
219
220
221Events
222------
223All events that Mitm will emit on an instance of itself (see [Using
224Mitm.js](#using) for examples):
225
226Event | Description
227-----------|------------
228connect | Emitted when a TCP connection is made.<br> Given the client side `Net.Socket` and `options` from `Net.connect`.
229connection | Emitted when a TCP connection is made.<br> Given the server side `Net.Socket` and `options` from `Net.connect`.
230request | Emitted when a HTTP/HTTPS request is made.<br> Given the server side `Http.IncomingMessage` and `Http.ServerResponse`.
231
232
233License
234-------
235Mitm.js is released under a *Lesser GNU Affero General Public License*, which
236in summary means:
237
238- You **can** use this program for **no cost**.
239- You **can** use this program for **both personal and commercial reasons**.
240- You **do not have to share your own program's code** which uses this program.
241- You **have to share modifications** (e.g. bug-fixes) you've made to this
242 program.
243
244For more convoluted language, see the `LICENSE` file.
245
246
247About
248-----
249**[Andri Möll][moll]** typed this and the code.
250[Monday Calendar][monday] supported the engineering work.
251
252If you find Mitm.js needs improving, please don't hesitate to type to me now
253at [andri@dot.ee][email] or [create an issue online][issues].
254
255[email]: mailto:andri@dot.ee
256[issues]: https://github.com/moll/node-mitm/issues
257[moll]: http://themoll.com
258[monday]: https://mondayapp.com
259[twitter]: https://twitter.com/theml