hapijs / hapi

The Simple, Secure Framework Developers Trust
https://hapi.dev
Other
14.63k stars 1.34k forks source link

Incorrect request.url.href in Hapi Server Requests #4506

Closed Dmitriyx closed 5 months ago

Dmitriyx commented 5 months ago

Runtime

node.js

Runtime version

v22

Module version

v21

Last module version without issue

No response

Used with

No response

Any other relevant information

Request.url is part of the URL constructor. https://github.com/hapijs/hapi/blob/master/lib/types/request.d.ts#L470 https://nodejs.org/api/url.html#class-url

What are you trying to achieve or the steps to reproduce?

I am trying to see what url was used to call my api endpoint, using request.url.href is what can be used, however it is incorrect.

Hapi says the http protocol was used instead of https.

Install ngrok, and run cli command ngrok http 3000

Run Example Server Code:

const Hapi = require('@hapi/hapi');

const init = async () => {

    const server = Hapi.server({
        port: 3000,
        host: 'localhost'
    });

    server.route({
        method: 'GET',
        path: '/',
        handler: (request, h) => {
            console.log('----------------------')
            console.log(`Requesting url is: ${request.url.href}`);
            console.log('----------------------')

            return 'Hello World!';
        }
    });

    await server.start();
    console.log('Server running on %s', server.info.uri);
};

process.on('unhandledRejection', (err) => {

    console.log(err);
    process.exit(1);
});

init();

then execute your cURL command curl --location '< https ngrok url >'

What was the result you got?

The actual log is: http://1f0b-47-20-124-200.ngrok-free.app I got the url with the http protocol instead of https.

What result did you expect?

What I expected to get: https://1f0b-47-20-124-200.ngrok-free.app

I also checked the URL class.

const test = new URL("https://1f0b-47-20-124-200.ngrok-free.app");
console.log(test.href)

this logs the correctly

an example using vanilla server to construct full url.

const http = require('node:http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  if (req.method === 'GET' && req.url === '/') {
    res.statusCode = 200;

    console.log('----------------------')
    console.log(`Requesting url is: ${req.headers['x-forwarded-proto']}://${req.headers.host}${req.url}`);
    console.log('----------------------')

    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello, World!\n');
  } else {
    res.statusCode = 404;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Not Found\n');
  }
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
kanongil commented 5 months ago

Thanks for the report. This is not a bug, and working as intended.

Hapi can only use the security of its listening endpoint to determine if it should be http: or https:. In this case the server has been started as a regular http server.

If you want to know the scheme the client used to connect to the proxy, the proxy will have to signal this to the server, and the server will have to use custom logic to use this signalling to override its understanding of the connecting url. One common way to do this is using the X-Forwarded-Proto header.