1 | var _ = require("underscore")
|
2 | var Net = require("net")
|
3 | var Tls = require("tls")
|
4 | var Http = require("http")
|
5 | var Https = require("https")
|
6 | var ClientRequest = Http.ClientRequest
|
7 | var ServerResponse = Http.ServerResponse
|
8 | var Socket = Net.Socket
|
9 | var EventEmitter = require("events").EventEmitter
|
10 | var InternalSocket = require("./lib/internal_socket")
|
11 | var Stubs = require("./lib/stubs")
|
12 | var normalizeConnectArgs = Net._normalizeConnectArgs
|
13 | var createRequestAndResponse = Http._connectionListener
|
14 | module.exports = Mitm
|
15 |
|
16 | function Mitm() {
|
17 | if (!(this instanceof Mitm))
|
18 | return Mitm.apply(Object.create(Mitm.prototype), arguments).enable()
|
19 |
|
20 | this.stubs = new Stubs
|
21 | this.on("request", addResponse)
|
22 |
|
23 | return this
|
24 | }
|
25 |
|
26 | Mitm.prototype.on = EventEmitter.prototype.on
|
27 | Mitm.prototype.once = EventEmitter.prototype.once
|
28 | Mitm.prototype.off = EventEmitter.prototype.off
|
29 | Mitm.prototype.removeListener = EventEmitter.prototype.removeListener
|
30 | Mitm.prototype.emit = EventEmitter.prototype.emit
|
31 |
|
32 | var NODE_0_10 = !!process.version.match(/^v0\.10\./)
|
33 |
|
34 | Mitm.prototype.enable = function() {
|
35 |
|
36 | var netConnect = connect.bind(this)
|
37 | this.stubs.stub(Net, "connect", netConnect)
|
38 | this.stubs.stub(Net, "createConnection", netConnect)
|
39 | this.stubs.stub(Http.Agent.prototype, "createConnection", netConnect)
|
40 |
|
41 | if (NODE_0_10) {
|
42 |
|
43 | this.stubs.stub(Http.globalAgent, "createConnection", netConnect)
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | this.stubs.stub(Http.globalAgent, "maxSockets", Infinity)
|
49 | this.stubs.stub(Https.globalAgent, "maxSockets", Infinity)
|
50 | }
|
51 |
|
52 |
|
53 | this.stubs.stub(Tls, "connect", _.compose(authorize, netConnect))
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | var onSocket = _.compose(ClientRequest.prototype.onSocket, request.bind(this))
|
59 | this.stubs.stub(ClientRequest.prototype, "onSocket", onSocket)
|
60 |
|
61 | return this
|
62 | }
|
63 |
|
64 | Mitm.prototype.disable = function() {
|
65 | return this.stubs.restore(), this
|
66 | }
|
67 |
|
68 | function connect(opts, done) {
|
69 | var args = normalizeConnectArgs(arguments), opts = args[0], done = args[1]
|
70 | var sockets = InternalSocket.pair()
|
71 | var client = new Socket(_.defaults({handle: sockets[0]}, opts))
|
72 | var server = client.server = new Socket({handle: sockets[1]})
|
73 |
|
74 |
|
75 |
|
76 | if (done) client.once("connect", done)
|
77 |
|
78 |
|
79 |
|
80 | process.nextTick(client.emit.bind(client, "connect"))
|
81 | process.nextTick(server.emit.bind(server, "connect"))
|
82 |
|
83 | this.emit("connect", client)
|
84 | this.emit("connection", server)
|
85 |
|
86 | return client
|
87 | }
|
88 |
|
89 | function authorize(socket) {
|
90 | return socket.authorized = true, socket
|
91 | }
|
92 |
|
93 | function request(socket) {
|
94 | var self = this
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | if (NODE_0_10) {
|
101 | self = Object.create(this)
|
102 | self.emit = _.compose(process.nextTick, Function.bind.bind(this.emit, this))
|
103 | }
|
104 |
|
105 | return createRequestAndResponse.call(self, socket.server), socket
|
106 | }
|
107 |
|
108 | function addResponse(req, res) { req.res = res; res.req = req }
|