Repository: glennjones/hapi-swagger (js)

Issue:
Invalid request call when hapi host is set to 0.0.0.0
#### Context

* *hapi-swgger version*: 9.0.2
* *any other relevant information*: Hapi 17.2.0

#### What are you trying to achieve or the steps to reproduce ?

I want to run hapi server on all my network interfaces (NIC) so I'm using following host: ```0.0.0.0```. While Swagger UI is displayed correctly, request executed through it does not work because it is invoked against host taken from Hapi configuration - ```0.0.0.0```.

```js
const server = new Hapi.Server({
    host: '0.0.0.0',
    port: 8083
});
```

#### What result did you get?
When I execute swagger request when I'm connected from whatever domain eg.
```http://192.168.0.55:8083/api/docs``` (NIC 1) or
```http://internal.domain.com:8083/api/docs``` (the same NIC 1) or 
```http://my.public.domain.com:8083/api/docs``` (NIC 2) 
```http:/123.123.123.123:8083/api/docs``` (the same NIC 2) 

all requests are executed as ```http://0.0.0.0:8083/api/config``` 

#### What did you expect ?
host for building request url should be taken directly from the browser - not Hapi configuration

It worked properly in hapi-swagger v8 and now it is broken

Pull request description:
fix: Use the incoming request to determine the host and port
This fixes issues when the hapi server is running on a different host/port to the external interface, e.g. within Docker.

Fix #497 

Patch:
diff --git a/lib/builder.js b/lib/builder.js
index 7290cf7..e30a36d 100644
--- a/lib/builder.js
+++ b/lib/builder.js
@@ -147,26 +147,28 @@ builder.dereference = async (schema) => {
  * @return {String}
  */
 internals.getHost = function(request) {
-    let host = request.info.hostname;
-    const port = request.server.info.port;
+    const proxyHost = request.headers['x-forwarded-host'] || request.headers['disguised-host'] || '';
+    if (proxyHost) {
+        return proxyHost;
+    }
+
+    const reqHost = request.info.host.split(':');
+    const host = reqHost[0];
+    const port = parseInt(reqHost[1] || '', 10);
     const protocol = request.server.info.protocol;
 
     // do not set port if its protocol http/https with default post numbers
     // this cannot be tested on most desktops as ports below 1024 throw EACCES
     /* $lab:coverage:off$ */
-    if (
-        (port && (protocol === 'http' && port !== 80)) ||
-        (protocol === 'https' && port !== 443)
+    if (!isNaN(port) &&
+        ((protocol === 'http' && port !== 80) ||
+        (protocol === 'https' && port !== 443))
     ) {
-        host += ':' + port;
+        return host + ':' + port;
     }
     /* $lab:coverage:on$ */
 
-    return (
-        request.headers['x-forwarded-host'] ||
-        request.headers['disguised-host'] ||
-        host
-    );
+    return host;
 };
 
 /**


Test patch:
diff --git a/test/Integration/builder-test.js b/test/Integration/builder-test.js
index 07b4b2f..a78e398 100644
--- a/test/Integration/builder-test.js
+++ b/test/Integration/builder-test.js
@@ -250,6 +250,26 @@ lab.experiment('builder', () => {
         expect(isValid).to.be.true();
     });
 
+    lab.test('getSwaggerJSON determines host and port from request info', async () => {
+
+        const server = await Helper.createServer({});
+
+        const response = await server.inject({ method: 'GET', headers: { host: '194.418.15.24:7645' }, url: '/swagger.json' });
+
+        expect(response.statusCode).to.equal(200);
+        expect(response.result.host).to.equal('194.418.15.24:7645');
+    });
+
+    lab.test('getSwaggerJSON doesn\'t specify port from request info when port is default', async () => {
+
+        const server = await Helper.createServer({});
+
+        const response = await server.inject({ method: 'GET', headers: { host: '194.418.15.24:80' }, url: '/swagger.json' });
+
+        expect(response.statusCode).to.equal(200);
+        expect(response.result.host).to.equal('194.418.15.24');
+    });
+
 });