useid / handlersjs

MIT License
3 stars 3 forks source link

Correct protocol on context.request.url when behind reverse proxy #246

Open elf-pavlik opened 2 months ago

elf-pavlik commented 2 months ago

I started running the SAI service behind a reverse proxy, which terminates HTTPS. I'm not sure how to get the correct context.request.url. I get http instead of https.

In CSS they use the 'X-Forwarded-Proto' header on the request. As shown in this snippet:

https://github.com/solid/solidproject.org/wiki/Using-NGINX-as-a-reverse-proxy#configuration

Also seen in code: https://github.com/CommunitySolidServer/CommunitySolidServer/blob/4599bf413e0ca08725d22b5e01fe43e97ef7d714/src/http/input/identifier/OriginalUrlExtractor.ts#L46-L53

I wasn't able to find how the same can be achieved in handlersjs.

After a quick look at the code, I found one place where http seems to be hardcoded https://github.com/useid/handlersjs/blob/876bbfe138b6c17f716bb1f7d72b144625f25677/packages/handlersjs-http/lib/servers/node/node-http-request-response.handler.ts#L207

elf-pavlik commented 2 months ago

For now, I just added another layer to the :onion:

import type { Observable } from 'rxjs';
import { getLogger } from '@useid/handlersjs-logging';
import type {
  HttpHandlerResponse,
  HttpHandler ,
  HttpHandlerContext
} from '@useid/handlersjs-http';

export class XForwardedProtoHandler implements HttpHandler {

  public logger = getLogger();

  /**
   * Checks HTTP X-Forwarded-Proto header, if needed updates protocol of context.request.url
   */
  constructor(
    private nestedHandler: HttpHandler
  ) {

    if (!nestedHandler) {

      throw new Error('A HttpHandler must be provided');

    }

  }

  handle(context: HttpHandlerContext): Observable<HttpHandlerResponse> {

    const headerValue = context.request.headers[`x-forwarded-proto`]
    const proto = headerValue.trim().replace(/\s*,.*/u, '')

    this.logger.debug('X-Forwarded-Proto: ', proto);

    if (proto === 'https') {
      context.request.url.protocol = 'https:'
    }

    return this.nestedHandler.handle(context)
  }

}