Skip to content

Commit

Permalink
fix: Use correct host and protocol for alternate links when running b…
Browse files Browse the repository at this point in the history
…ehind a proxy (`x-forwarded-host`, `x-forwarded-proto`) (#462 by @HHongSeungWoo)



---------

Co-authored-by: Jan Amann <jan@amann.me>
  • Loading branch information
HHongSeungWoo and amannn committed Aug 22, 2023
1 parent 68914a3 commit 747cf8e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import {NextRequest} from 'next/server';
import MiddlewareConfig, {
MiddlewareConfigWithDefaults
} from './NextIntlMiddlewareConfig';
import {isLocaleSupportedOnDomain} from './utils';
import {getHost, isLocaleSupportedOnDomain} from './utils';

function getUnprefixedUrl(config: MiddlewareConfig, request: NextRequest) {
const url = new URL(request.url);
url.host = getHost(request.headers) ?? url.host;
url.protocol = request.headers.get('x-forwarded-proto') ?? url.protocol;

if (!url.pathname.endsWith('/')) {
url.pathname += '/';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ import {it, expect} from 'vitest';
import {MiddlewareConfigWithDefaults} from '../../src/middleware/NextIntlMiddlewareConfig';
import getAlternateLinksHeaderValue from '../../src/middleware/getAlternateLinksHeaderValue';

function getRequest(url = 'https://example.com/') {
return {url} as NextRequest;
}

it('works for prefixed routing (as-needed)', () => {
const config: MiddlewareConfigWithDefaults = {
defaultLocale: 'en',
Expand All @@ -17,7 +13,10 @@ it('works for prefixed routing (as-needed)', () => {
};

expect(
getAlternateLinksHeaderValue(config, getRequest()).split(', ')
getAlternateLinksHeaderValue(
config,
new NextRequest('https://example.com/')
).split(', ')
).toEqual([
'<https://example.com/>; rel="alternate"; hreflang="en"',
'<https://example.com/es>; rel="alternate"; hreflang="es"',
Expand All @@ -27,7 +26,7 @@ it('works for prefixed routing (as-needed)', () => {
expect(
getAlternateLinksHeaderValue(
config,
getRequest('https://example.com/about')
new NextRequest('https://example.com/about')
).split(', ')
).toEqual([
'<https://example.com/about>; rel="alternate"; hreflang="en"',
Expand All @@ -46,7 +45,10 @@ it('works for prefixed routing (always)', () => {
};

expect(
getAlternateLinksHeaderValue(config, getRequest()).split(', ')
getAlternateLinksHeaderValue(
config,
new NextRequest('https://example.com/')
).split(', ')
).toEqual([
'<https://example.com/en>; rel="alternate"; hreflang="en"',
'<https://example.com/es>; rel="alternate"; hreflang="es"',
Expand All @@ -56,7 +58,7 @@ it('works for prefixed routing (always)', () => {
expect(
getAlternateLinksHeaderValue(
config,
getRequest('https://example.com/about')
new NextRequest('https://example.com/about')
).split(', ')
).toEqual([
'<https://example.com/en/about>; rel="alternate"; hreflang="en"',
Expand Down Expand Up @@ -92,10 +94,13 @@ it("works for type domain with `localePrefix: 'as-needed'`", () => {
};

[
getAlternateLinksHeaderValue(config, getRequest()).split(', '),
getAlternateLinksHeaderValue(
config,
getRequest('https://example.es/')
new NextRequest('https://example.com/')
).split(', '),
getAlternateLinksHeaderValue(
config,
new NextRequest('https://example.es/')
).split(', ')
].forEach((links) => {
expect(links).toEqual([
Expand All @@ -111,7 +116,7 @@ it("works for type domain with `localePrefix: 'as-needed'`", () => {
expect(
getAlternateLinksHeaderValue(
config,
getRequest('https://example.com/about')
new NextRequest('https://example.com/about')
).split(', ')
).toEqual([
'<https://example.com/about>; rel="alternate"; hreflang="en"',
Expand Down Expand Up @@ -150,10 +155,13 @@ it("works for type domain with `localePrefix: 'always'`", () => {
};

[
getAlternateLinksHeaderValue(config, getRequest()).split(', '),
getAlternateLinksHeaderValue(
config,
getRequest('https://example.es/')
new NextRequest('https://example.com/')
).split(', '),
getAlternateLinksHeaderValue(
config,
new NextRequest('https://example.es/')
).split(', ')
].forEach((links) => {
expect(links).toEqual([
Expand All @@ -169,7 +177,7 @@ it("works for type domain with `localePrefix: 'always'`", () => {
expect(
getAlternateLinksHeaderValue(
config,
getRequest('https://example.com/about')
new NextRequest('https://example.com/about')
).split(', ')
).toEqual([
'<https://example.com/en/about>; rel="alternate"; hreflang="en"',
Expand All @@ -180,3 +188,30 @@ it("works for type domain with `localePrefix: 'always'`", () => {
'<https://example.ca/fr/about>; rel="alternate"; hreflang="fr"'
]);
});

it('uses the external host name from headers instead of the url of the incoming request (relevant when running the app behind a proxy)', () => {
const config: MiddlewareConfigWithDefaults = {
defaultLocale: 'en',
locales: ['en', 'es'],
alternateLinks: true,
localePrefix: 'as-needed',
localeDetection: true
};

expect(
getAlternateLinksHeaderValue(
config,
new NextRequest('http://127.0.0.1/about', {
headers: {
host: 'example.com',
'x-forwarded-host': 'example.com',
'x-forwarded-proto': 'https'
}
})
).split(', ')
).toEqual([
'<https://example.com/about>; rel="alternate"; hreflang="en"',
'<https://example.com/es/about>; rel="alternate"; hreflang="es"',
'<https://example.com/about>; rel="alternate"; hreflang="x-default"'
]);
});

3 comments on commit 747cf8e

@vercel
Copy link

@vercel vercel bot commented on 747cf8e Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

example-next-13-next-auth – ./examples/example-next-13-next-auth

example-next-13-next-auth-next-intl.vercel.app
example-next-13-next-auth-git-main-next-intl.vercel.app
example-next-13-next-auth.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 747cf8e Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

next-intl-example-next-13 – ./examples/example-next-13

next-intl-example-next-13.vercel.app
next-intl-example-next-13-git-main-next-intl.vercel.app
next-intl-example-next-13-next-intl.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 747cf8e Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

next-intl-docs – ./docs

next-intl-docs-next-intl.vercel.app
next-intl-docs.vercel.app
next-intl-docs-git-main-next-intl.vercel.app

Please sign in to comment.