diff --git a/core/src/main/java/io/apigee/trireme/core/modules/HTTPWrap.java b/core/src/main/java/io/apigee/trireme/core/modules/HTTPWrap.java index 0459f269..f4e3ea2e 100644 --- a/core/src/main/java/io/apigee/trireme/core/modules/HTTPWrap.java +++ b/core/src/main/java/io/apigee/trireme/core/modules/HTTPWrap.java @@ -38,6 +38,9 @@ import io.apigee.trireme.net.spi.HttpServerStub; import io.apigee.trireme.net.spi.TLSParams; import io.apigee.trireme.net.spi.UpgradedSocket; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.util.Random; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.RhinoException; @@ -219,6 +222,31 @@ public void close() runner.unPin(); } + @JSFunction + @SuppressWarnings("unused") + public static Object localAddress(Context cx, Scriptable thisObj, Object[] args, Function func) + { + ServerContainer self = (ServerContainer)thisObj; + Scriptable addr = cx.newObject(thisObj); + if (self.adapter != null) { + InetSocketAddress sa = self.adapter.localAddress(); + if (sa == null) { + addr.put("address", addr, "localhost"); + addr.put("port", addr, -1); + addr.put("family", addr, "IPv4"); + } else { + addr.put("address", addr, sa.getHostString()); + addr.put("port", addr, sa.getPort()); + if (sa.getAddress() instanceof Inet6Address) { + addr.put("family", addr, "IPv6"); + } else { + addr.put("family", addr, "IPv4"); + } + } + } + return addr; + } + /** * This method is called when the whole server has failed or is shutting down prematurely. */ diff --git a/core/src/main/java/io/apigee/trireme/net/spi/HttpServerAdapter.java b/core/src/main/java/io/apigee/trireme/net/spi/HttpServerAdapter.java index 2d32256a..8e3805b1 100644 --- a/core/src/main/java/io/apigee/trireme/net/spi/HttpServerAdapter.java +++ b/core/src/main/java/io/apigee/trireme/net/spi/HttpServerAdapter.java @@ -21,6 +21,7 @@ */ package io.apigee.trireme.net.spi; +import java.net.InetSocketAddress; import javax.net.ssl.SSLContext; /** @@ -31,6 +32,16 @@ public interface HttpServerAdapter /** Start to listen on the specified host and port. */ void listen(String host, int port, int backlog, TLSParams tlsParams); + /** + * Get the address that we're listening on. This should be the real address where + * a client could send a request, not the initial parameters sent to "listen," + * in case port zero was used to create an anonymous port. + * If there is no meaningful way to return a real address, then return null -- the + * wrapper will use this to generate a random (and meaningless) port number so that clients will + * not break. + */ + InetSocketAddress localAddress(); + /** Don't close the socket, but stop accepting new connections */ void suspend(); diff --git a/net/src/main/java/io/apigee/trireme/container/netty/NettyHttpServer.java b/net/src/main/java/io/apigee/trireme/container/netty/NettyHttpServer.java index e1e91267..111ecb1c 100644 --- a/net/src/main/java/io/apigee/trireme/container/netty/NettyHttpServer.java +++ b/net/src/main/java/io/apigee/trireme/container/netty/NettyHttpServer.java @@ -46,6 +46,7 @@ import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslHandler; import io.netty.handler.timeout.IdleStateHandler; +import java.net.InetSocketAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -88,7 +89,7 @@ public void listen(String host, int port, int backlog, TLSParams tlsParams) } try { server = NettyFactory.get().createServer(port, host, backlog, makePipeline(tlsParams)); - log.debug("Listening on port {}", port); + log.debug("Listening on {}", server.getAddress()); } catch (ChannelException ce) { stub.onError(ce.getMessage()); stub.onClose(null, null); @@ -143,6 +144,11 @@ boolean isClosing() { return closing; } + @Override + public InetSocketAddress localAddress() { + return server.getAddress(); + } + @Override public void suspend() { diff --git a/net/src/main/java/io/apigee/trireme/container/netty/NettyServer.java b/net/src/main/java/io/apigee/trireme/container/netty/NettyServer.java index 319caecd..d3e2b1a9 100644 --- a/net/src/main/java/io/apigee/trireme/container/netty/NettyServer.java +++ b/net/src/main/java/io/apigee/trireme/container/netty/NettyServer.java @@ -71,6 +71,9 @@ public void close() } public InetSocketAddress getAddress() { + if (serverChannel != null) { + return (InetSocketAddress)(serverChannel.localAddress()); + } return address; } diff --git a/net/src/test/resources/tests/basichttpstest.js b/net/src/test/resources/tests/basichttpstest.js index f2fa649a..658fc1a2 100644 --- a/net/src/test/resources/tests/basichttpstest.js +++ b/net/src/test/resources/tests/basichttpstest.js @@ -22,9 +22,9 @@ var svr = https.createServer({ }); console.log('Server starting to listen'); -svr.listen(33333, function() { - console.log('Server listening'); - https.get({host: 'localhost', port: 33333, +svr.listen(0, function() { + console.log('Server listening on %j', svr.address()); + https.get({host: 'localhost', port: svr.address().port, path: '/', rejectUnauthorized: false}, function(resp) { var received = ''; console.log('Got a response with status code ' + resp.statusCode); diff --git a/net/src/test/resources/tests/basichttptest.js b/net/src/test/resources/tests/basichttptest.js index 7a12fc3f..6b6de130 100644 --- a/net/src/test/resources/tests/basichttptest.js +++ b/net/src/test/resources/tests/basichttptest.js @@ -1,5 +1,5 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); var util = require('util'); var socketsMatch = false; @@ -52,8 +52,10 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33333, function() { - http.get('http://localhost:33333/', function(resp) { +svr.listen(0, function() { + console.log('Server listening on %j', svr.address()); + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { var received = ''; resp.setEncoding('utf8'); if (resp.statusCode != 200) { @@ -75,9 +77,7 @@ svr.listen(33333, function() { var msg = JSON.parse(received); console.log('Received: %j', msg); - assert.equal(localAddress, msg.remoteAddress); assert.equal(localPort, msg.remotePort); - assert.equal(remoteAddress, msg.localAddress); assert.equal(remotePort, msg.localPort); socketsMatch = true; }); diff --git a/net/src/test/resources/tests/blackholeresponsetest.js b/net/src/test/resources/tests/blackholeresponsetest.js index 8cb14634..c3038b4c 100644 --- a/net/src/test/resources/tests/blackholeresponsetest.js +++ b/net/src/test/resources/tests/blackholeresponsetest.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var TIMEOUT = 1000; @@ -15,8 +16,9 @@ var svr = http.createServer(function(req, resp) { } }); -svr.listen(33342, function() { - http.get('http://localhost:33342', function(resp) { +svr.listen(0, function() { + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { var received = ''; resp.setEncoding('utf8'); assert.equal(resp.statusCode, 500); diff --git a/net/src/test/resources/tests/blackholeresponsetest2.js b/net/src/test/resources/tests/blackholeresponsetest2.js index a73bd005..fbe05ac1 100644 --- a/net/src/test/resources/tests/blackholeresponsetest2.js +++ b/net/src/test/resources/tests/blackholeresponsetest2.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var TIMEOUT = 1000; @@ -19,8 +20,9 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33341, function() { - http.get('http://localhost:33341', function(resp) { +svr.listen(0, function() { + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { var received = ''; resp.setEncoding('utf8'); assert.equal(resp.statusCode, 500); diff --git a/net/src/test/resources/tests/catchexception.js b/net/src/test/resources/tests/catchexception.js index 706e5406..901eeaa0 100644 --- a/net/src/test/resources/tests/catchexception.js +++ b/net/src/test/resources/tests/catchexception.js @@ -1,6 +1,7 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); var urlparse = require('url'); +var util = require('util'); var svr = http.createServer(function(req, resp) { console.log('Got %s', req.url); @@ -40,7 +41,10 @@ var svr = http.createServer(function(req, resp) { } }); -svr.listen(33333, function() { +var baseUrl; + +svr.listen(0, function() { + baseUrl = util.format('http://localhost:%d/', svr.address().port); doTest('GET', 'ok', false, 200, function() { doTest('GET', 'throw', false, 500, function() { doTest('POST', 'throwOnData', false, 500, function() { @@ -58,7 +62,7 @@ svr.listen(33333, function() { }); function doTest(verb, url, shouldClose, code, next) { - opts = urlparse.parse('http://localhost:33333/' + url); + opts = urlparse.parse(baseUrl + url); opts.method = verb; req = http.request(opts, function(resp) { var respData = ''; diff --git a/net/src/test/resources/tests/clientclose.js b/net/src/test/resources/tests/clientclose.js index 1162fe2f..83a272a6 100644 --- a/net/src/test/resources/tests/clientclose.js +++ b/net/src/test/resources/tests/clientclose.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var TIMEOUT = 100; var ITERATIONS = 10; @@ -63,8 +64,8 @@ function getClose(url, cb) { }); } -svr.listen(33344, function() { - var url = 'http://localhost:33344'; +svr.listen(0, function() { + var url = util.format('http://localhost:%d', svr.address().port); getGood(url, function() { getClose(url, function() { console.log('Done'); diff --git a/net/src/test/resources/tests/cpulooptest.js b/net/src/test/resources/tests/cpulooptest.js index fd148dda..ccce724d 100644 --- a/net/src/test/resources/tests/cpulooptest.js +++ b/net/src/test/resources/tests/cpulooptest.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var svr = http.createServer(function(req, resp) { console.log('Starting to loop the CPU'); @@ -12,8 +13,9 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33333, function() { - http.get('http://localhost:33333/', function(resp) { +svr.listen(0, function() { + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { svr.close(); assert.equal(500, resp.statusCode, 'Expected status code 500'); diff --git a/net/src/test/resources/tests/newhttptest.js b/net/src/test/resources/tests/newhttptest.js index 6a21fb08..4ed86768 100644 --- a/net/src/test/resources/tests/newhttptest.js +++ b/net/src/test/resources/tests/newhttptest.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var svr = http.createServer(function(req, resp) { console.log('Got an HTTP request'); @@ -14,9 +15,10 @@ var svr = http.createServer(function(req, resp) { }); console.log('Server starting to listen'); -svr.listen(33333, function() { +svr.listen(0, function() { console.log('Server listening'); - http.get('http://localhost:33333/', function(resp) { + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { var received = ''; console.log('Got a response with status code ' + resp.statusCode); resp.setEncoding('utf8'); diff --git a/net/src/test/resources/tests/postmanychunks.js b/net/src/test/resources/tests/postmanychunks.js index 4e30e049..ecf93d77 100644 --- a/net/src/test/resources/tests/postmanychunks.js +++ b/net/src/test/resources/tests/postmanychunks.js @@ -32,8 +32,8 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33333, function() { - var req = http.request({host: 'localhost', port: 33333, +svr.listen(0, function() { + var req = http.request({host: 'localhost', port: svr.address().port, path: '/', method: 'POST', headers: { 'Content-Type': 'text/plain' }}, function(resp) { diff --git a/net/src/test/resources/tests/postmanychunkshttps.js b/net/src/test/resources/tests/postmanychunkshttps.js index 2c3ac6ae..829a97b8 100644 --- a/net/src/test/resources/tests/postmanychunkshttps.js +++ b/net/src/test/resources/tests/postmanychunkshttps.js @@ -35,8 +35,8 @@ var svr = https.createServer({ }); }); -svr.listen(33333, function() { - var req = https.request({host: 'localhost', port: 33333, +svr.listen(0, function() { + var req = https.request({host: 'localhost', port: svr.address().port, path: '/', method: 'POST', headers: { 'Content-Type': 'text/plain' }, rejectUnauthorized: false}, diff --git a/net/src/test/resources/tests/postonechunk.js b/net/src/test/resources/tests/postonechunk.js index 130be37f..5597abf6 100644 --- a/net/src/test/resources/tests/postonechunk.js +++ b/net/src/test/resources/tests/postonechunk.js @@ -20,8 +20,8 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33333, function() { - var req = http.request({host: 'localhost', port: 33333, +svr.listen(0, function() { + var req = http.request({host: 'localhost', port: svr.address().port, path: '/', method: 'POST', headers: { 'Content-Type': 'text/plain' }}, function(resp) { diff --git a/net/src/test/resources/tests/postonechunkhttps.js b/net/src/test/resources/tests/postonechunkhttps.js index 6520344e..0565fbfa 100644 --- a/net/src/test/resources/tests/postonechunkhttps.js +++ b/net/src/test/resources/tests/postonechunkhttps.js @@ -22,8 +22,8 @@ var svr = https.createServer({ keystore: keystore, passphrase: 'secure' }, }); }); -svr.listen(33333, function() { - var req = https.request({host: 'localhost', port: 33333, +svr.listen(0, function() { + var req = https.request({host: 'localhost', port: svr.address().port, path: '/', method: 'POST', headers: { 'Content-Type': 'text/plain' }, rejectUnauthorized: false}, diff --git a/net/src/test/resources/tests/responsecodetest.js b/net/src/test/resources/tests/responsecodetest.js index 0b869259..0d1a0a52 100644 --- a/net/src/test/resources/tests/responsecodetest.js +++ b/net/src/test/resources/tests/responsecodetest.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var svr = http.createServer(function(req, resp) { console.log('Server: got request'); @@ -8,8 +9,9 @@ var svr = http.createServer(function(req, resp) { resp.end(); }); -svr.listen(33333, function() { - http.get('http://localhost:33333/', function(resp) { +svr.listen(0, function() { + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { resp.on('readable', function() { resp.read(); }); diff --git a/net/src/test/resources/tests/slowrequest.js b/net/src/test/resources/tests/slowrequest.js index 07c667c7..76a5bd52 100644 --- a/net/src/test/resources/tests/slowrequest.js +++ b/net/src/test/resources/tests/slowrequest.js @@ -23,10 +23,10 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33342, function() { +svr.listen(0, function() { var req = http.request({ hostname: 'localhost', - port: 33342, + port: svr.address().port, path: '/', method: 'POST' }, function(resp) { diff --git a/net/src/test/resources/tests/slowresponse.js b/net/src/test/resources/tests/slowresponse.js index ad92bfb3..acf90cb1 100644 --- a/net/src/test/resources/tests/slowresponse.js +++ b/net/src/test/resources/tests/slowresponse.js @@ -1,5 +1,6 @@ -var http = require('http'); var assert = require('assert'); +var http = require('http'); +var util = require('util'); var TIMEOUT = 1000; @@ -27,8 +28,9 @@ var svr = http.createServer(function(req, resp) { }); }); -svr.listen(33343, function() { - http.get('http://localhost:33343', function(resp) { +svr.listen(0, function() { + var url = util.format('http://localhost:%d', svr.address().port); + http.get(url, function(resp) { var received = ''; resp.setEncoding('utf8'); assert.equal(resp.statusCode, 200); diff --git a/net/src/test/resources/tests/upgradetest.js b/net/src/test/resources/tests/upgradetest.js index 82140aef..5e8d0d0d 100644 --- a/net/src/test/resources/tests/upgradetest.js +++ b/net/src/test/resources/tests/upgradetest.js @@ -38,11 +38,11 @@ srv.on('upgrade', function(req, socket, head) { }); // now that server is running -srv.listen(33334, function() { +srv.listen(0, function() { // make a request var options = { - port: 33334, + port: srv.address().port, hostname: 'localhost', headers: { 'Connection': 'Upgrade', diff --git a/node10/node10src/src/main/javascript/io/apigee/trireme/node10/trireme/adaptorhttp.js b/node10/node10src/src/main/javascript/io/apigee/trireme/node10/trireme/adaptorhttp.js index f404ec97..c933943a 100644 --- a/node10/node10src/src/main/javascript/io/apigee/trireme/node10/trireme/adaptorhttp.js +++ b/node10/node10src/src/main/javascript/io/apigee/trireme/node10/trireme/adaptorhttp.js @@ -614,12 +614,6 @@ if (HttpWrap.hasServerAdapter()) { fam = 'IPv4'; } - self.address = { - port: port, - address: address, - family: fam - }; - self._adapter = HttpWrap.createServerAdapter(); if (self.sslContext) { self._adapter.setSslContext(self.sslContext, self.rejectUnauthorized, self.requestCert); @@ -661,7 +655,7 @@ if (HttpWrap.hasServerAdapter()) { } Server.prototype.address = function() { - return this.address; + return this._adapter.localAddress(); }; Server.prototype.listen = function() { diff --git a/servlet/src/main/java/io/apigee/trireme/servlet/internal/ServletAdapter.java b/servlet/src/main/java/io/apigee/trireme/servlet/internal/ServletAdapter.java index 7bb4b41a..a6b9fd7f 100644 --- a/servlet/src/main/java/io/apigee/trireme/servlet/internal/ServletAdapter.java +++ b/servlet/src/main/java/io/apigee/trireme/servlet/internal/ServletAdapter.java @@ -25,6 +25,7 @@ import io.apigee.trireme.net.spi.HttpServerAdapter; import io.apigee.trireme.net.spi.HttpServerStub; import io.apigee.trireme.net.spi.TLSParams; +import java.net.InetSocketAddress; public class ServletAdapter implements HttpServerAdapter @@ -57,4 +58,11 @@ public void close() { // TODO } + + @Override + public InetSocketAddress localAddress() + { + // By returning null we are telling the adapter that we can't create a meaningful address. + return null; + } }