Bouncy - Open Source Code Exploration
Bouncy is a tool to "pipe raw http traffic from [an] incoming http request to a another remote end point."
It's an interesting tool and, for me, a useful find. Not to reveal too much but this site is running on Node among other technologies.
I think this tool has a lot of possible applications[1] but for me, it acts as a virtual host router. I don't want to go into too much detail here (you can see here for more info) but in my scenario, I wanted to setup my server so that I could host another site on the same server if needed or desired.
Bouncy allows me to do that; using bouncy I created a small custom program that listens on port 80 (the website port). When it accepts an incoming request it routes it to the correct site which is running on another port (on the same server) -- say 8000 for discussion.
It determines the site via the request host headers (req.headers.host
).
Summary of example configuration:
- Bouncy = Port 80
- The Open Source U = Port 8000
- Possible future sites = Port 8001, 8002, etc
It's a small library (it's available as a CLI tool as well) and I think it's an excellent candidate for a first article. I'm, frankly, curious how it works and it's small enough to sort out the structure of these posts.
For the purpose of this article, I've forked the git repository to https://github.com/TheOpenSourceU/bouncy
I'll use and reference this version in this article. Because the parent/source project could continue to be developed, I've created a branch called tOSU/explore. This will remain consistent with this article whereas master can deviate. I want to keep master consistent with the sources' master.
Technology Prerequisites
I'll do my best to link or explain related technologies and concepts. A principle goal of this site is to engage folks with a diverse backgrounds and experience levels.
That said, I do make some assumptions about a basic familiarity with some technology. At this time, I don't have public comments on this site but should you need to provide critical (respectful) feedback or ask questions, please feel use the GitHub issues located here.
Index of Dependencies
Knowing and understanding the high-level purpose of a package/programs dependencies is helpful in understanding the parent application.
Bouncy has two main dependencies (for those unfamiliar, this is in the package.json
file.
// ...
"dependencies" : {
"through": "~2.3.4",
"optimist": "~0.3.5"
},
// ...
- through: Creates a stream that is readable and writable.
- optimist: (deprecated) is a command line option parser written by the same author as Bouncy.
index.js
The entry point and frankly the main implementation. Bouncy is built on top of the bog standard NodeJS http/https library and in a way, simply wraps it. Given it's relationship to http
/https
, Bouncy is event driven.
The correct server type is created (secure or not); then three events are assigned handlers. The first is the connection
or secureConnection
event which is handled by an anonymous function which we'll call the "connection event handler". The other two events are upgrade
and request
which are both assigned onrequest
.
Connection Event Handler
This accepts the parameter stream
. This represents the network stream of data coming in for the request. The handler adds a property called _bouncyStream
which is the results of stealthBuffer().
The next snippet is the nuts and bolts of the handler.
var src = stream._bouncyStream = stealthBuffer();
// ... old version work around ...
else stream.pipe(src);
At this point, stream
is an instance of Socket and src
is an instance of Stream. (Notice that despite the name, stream is not Stream -- that capital "S" is important.)
The src
(Stream) is piped (sent) to the Socket. This completes the set up of the connection. Now, bouncy will wait for incoming requests and through onrequest
, route them.
onrequest
This is the main purpose of Bouncy. This ultimately bounces the request to another port via the cb
parameter as this is the user implemented code provided as a callback.
Here's the example given on the GitHub page.
var bouncy = require('bouncy');
var server = bouncy(function (req, res, bounce) {
if (req.headers.host === 'beep.example.com') {
bounce(8001);
}
else if (req.headers.host === 'boop.example.com') {
bounce(8002);
}
else {
res.statusCode = 404;
res.end('no such host');
}
});
server.listen(8000);
The anonymous function passed into the bouncy
and is called after some setup which is mainly creating the bounce
method. The end user then calls bounce
with the appropriate port and said method pipes
the connection to the new path.
This "bounces" the request to the new port.
stealthBuffer()
stealthBuffer()
returns an instance of the dependency through
; recall this provides the means to make a stream readable and writable.
This is ultimately used in the connection event handler. The bottom line is it augments the request for passing it through to the bounce
method in the onrequest
handler.
I'm wondering if Bouncy can be used to load balance the same site on two different instances of NodeJS. I strongly suspect it could and hope to test that soon... ↩︎