port

Re-assembling the Requested URL

It is simple to know the request URL path, it’s one (this.url in Koa) used by routing, but if you are looking to get the complete URL, it’s a little bit complicated. Luckily, there is a quick way to re-assemble the requested URL in Koa, if proxy is not a concern:

1
var url = this.request.protocol + '://' + this.request.host + this.request.originalUrl;

Or a shorter version:

1
var url = this.protocol + '://' + this.host + this.originalUrl;

The port number is included in this.host, for example: localhost:3000.

Putting into a complete script:

1
2
3
4
require('koa')().use(function *() {
// Echo back the request URL.
this.body = this.protocol + '://' + this.host + this.originalUrl;
}).listen(3000);

Assume that you have a server running on the host www.example.com with SSL enabled. If you make a request to the server with the URL: https://www.example.com/path, this URL will be echoed back in the response by the above script.

SuperTest: Listen at Random Port

In the example section of SuperTest (v0.15.0), it mentions something about ephemeral port:

You may pass an http.Server, or a Function to request() - if the server is not already listening for connections then it is bound to an ephemeral port for you so there is no need to keep track of ports. - https://github.com/visionmedia/supertest#example

Let’s dissect this sentence. There are a few key concepts to grasp:

  1. The request function will accept either a function or an http.Server object.
  2. When does the server not listening for connections?
  3. What is an ephemeral port?

Taking a peek at the index.js file in SuperTest source code, it is easy to see that it accepts both function and http.Server object, but prefer latter:

1
2
3
4
5
6
7
8
9
10
11
// See `index.js` in [SuperTest] source code.
if ('function' == typeof app) app = http.createServer(app);
// See `lib/test.js` in [SuperTest] source code.
Test.prototype.serverAddress = function (app, path) {
var addr = app.address();
if (!addr) this._server = app.listen(0);
var port = app.address().port;
var protocol = app instanceof htts.Server ? 'https' : 'http';
return protocol + '://1270.0.0.1:' + port + path;
});

Why it does this? This has to do with Express:

1
2
3
4
5
6
7
8
> typeof require('http').createServer()
'object'
> typeof require('express')()
'function'
> typeof require('koa')()
'object'
> require('http').createServer(require('express')()).address()
null

Only when initiating an Express app, it returns a function, not an object. And follows up on lib/test.js, when SuperTest detects the created server is yet to bind to any port number, it will invoke app.listen(0), so called ephemeral port. In fact, it is just a random port.

When something is ephemeral, it last for a very short time. When allowing a server to accept connections, we usually do is setting the server to listen on a specific port:

1
app.listen(3001);

What if setting this to 0 like above or omit this port number?

Locate HTTP Port Number from http.Server Instance

This is a bare minimal HTTP server:

1
require('http').createServer().listen(port);

If the port number is evaluated to be falsy, such as 0, null, undefined or an empty string, a random port will be assigned.

Begin accepting connections on the specified port and hostname. If the hostname is omitted, the server will accept connections on any IPv6 address (::) when IPv6 is available, or any IPv4 address (0.0.0.0) otherwise. A port value of zero will assign a random port. - https://iojs.org/api/http.html#http_server_listen_port_hostname_backlog_callback

We can use command line tool such as netstat to find out the port number:

1
2
$ netstat -ltpn | grep node
tcp6 0 0 :::44055 :::* LISTEN 5624/node

However, it will be very convenient without relying on external tools.

Luckily, we can find out the port number by using the address method:

1
require('http').createServer().listen().address()

The result will be similar to:

1
{ address: '::', family: 'IPv6', port: 44055 }

Furthermore, it works with all popular libraries that create an http.Server instance: