Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: hardcoded protocol in request url #37925

Merged
merged 7 commits into from
Jun 25, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/next/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { ParsedUrlQuery } from 'querystring'
import type { RenderOpts, RenderOptsPartial } from './render'
import type { ResponseCacheEntry, ResponseCacheValue } from './response-cache'
import type { UrlWithParsedQuery } from 'url'
import type { TLSSocket } from 'tls'
import {
CacheFs,
NormalizeError,
Expand All @@ -21,6 +22,7 @@ import {
import type { PreviewData } from 'next/types'
import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
import type { BaseNextRequest, BaseNextResponse } from './base-http'
import type { NodeNextRequest } from './base-http/node'
import type { PayloadOptions } from './send-payload'

import { join, resolve } from '../shared/lib/isomorphic/path'
Expand Down Expand Up @@ -407,14 +409,21 @@ export default abstract class Server<ServerOptions extends Options = Options> {
parsedUrl.query = parseQs(parsedUrl.query)
}

const protocol = (
(req as NodeNextRequest).originalRequest?.socket as TLSSocket
)?.encrypted
Copy link
Member

Choose a reason for hiding this comment

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

We potentially might want to support x-forwarded-proto in a follow-up but this will probably require config to verify the upstream proxy.

? 'https'
: 'http'

// When there are hostname and port we build an absolute URL
const initUrl =
this.hostname && this.port
? `http://${this.hostname}:${this.port}${req.url}`
? `${protocol}://${this.hostname}:${this.port}${req.url}`
: req.url

addRequestMeta(req, '__NEXT_INIT_URL', initUrl)
addRequestMeta(req, '__NEXT_INIT_QUERY', { ...parsedUrl.query })
addRequestMeta(req, '_protocol', protocol)

const domainLocale = detectDomainLocale(
this.nextConfig.i18n?.domains,
Expand Down
10 changes: 7 additions & 3 deletions packages/next/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1176,9 +1176,12 @@ export default class NextNodeServer extends BaseServer {
// For middleware to "fetch" we must always provide an absolute URL
const query = urlQueryToSearchParams(params.parsed.query).toString()
const locale = params.parsed.query.__nextLocale
const url = `http://${this.hostname}:${this.port}${
locale ? `/${locale}` : ''
}${params.parsed.pathname}${query ? `?${query}` : ''}`

const url = `${getRequestMeta(params.request, '_protocol')}://${
this.hostname
}:${this.port}${locale ? `/${locale}` : ''}${params.parsed.pathname}${
query ? `?${query}` : ''
}`
feugy marked this conversation as resolved.
Show resolved Hide resolved

if (!url.startsWith('http')) {
throw new Error(
Expand Down Expand Up @@ -1546,6 +1549,7 @@ export default class NextNodeServer extends BaseServer {
}

const nodeReq = params.req as NodeNextRequest

const result = await run({
name: middlewareInfo.name,
paths: middlewareInfo.paths,
Expand Down
1 change: 1 addition & 0 deletions packages/next/server/request-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface RequestMeta {
_nextDidRewrite?: boolean
_nextHadBasePath?: boolean
_nextRewroteUrl?: string
_protocol?: string
}

export function getRequestMeta(
Expand Down
11 changes: 11 additions & 0 deletions test/integration/custom-server/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { NextResponse } from 'next/server'

export default function middleware(request) {
const response = NextResponse.next()
response.headers.append('x-original-url', request.url)
return response
}

export const config = {
matcher: '/middleware-augmented',
}
3 changes: 3 additions & 0 deletions test/integration/custom-server/pages/middleware-augmented.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Index() {
return <h1>You passed the middleware!</h1>
}
15 changes: 12 additions & 3 deletions test/integration/custom-server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@ if (process.env.POLYFILL_FETCH) {
global.fetch = require('node-fetch').default
}

const http = require('http')
const { readFileSync } = require('fs')
const next = require('next')
const { join } = require('path')

const dev = process.env.NODE_ENV !== 'production'
const dir = __dirname
const port = process.env.PORT || 3000
const { createServer } = require(process.env.USE_HTTPS === 'true'
? 'https'
: 'http')

const app = next({ dev, dir })
const app = next({ dev, hostname: 'localhost', port, dir })
const handleNextRequests = app.getRequestHandler()

const httpOptions = {
key: readFileSync(join(__dirname, 'ssh/privkey.pem')),
cert: readFileSync(join(__dirname, 'ssh/cert.pem')),
}

app.prepare().then(() => {
const server = new http.Server(async (req, res) => {
const server = createServer(httpOptions, async (req, res) => {
if (req.url === '/no-query') {
return app.render(req, res, '/no-query')
}
Expand Down
20 changes: 20 additions & 0 deletions test/integration/custom-server/ssh/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDOzCCAiMCCQDZakQbo5eJ3TANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJV
UzENMAsGA1UECAwEVXRhaDEOMAwGA1UEBwwFUHJvdm8xIzAhBgNVBAoMGkFDTUUg
U2lnbmluZyBBdXRob3JpdHkgSW5jMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0y
MjA2MjMwODEyMTRaFw0zNjAzMDEwODEyMTRaMFgxCzAJBgNVBAYTAlVTMQ0wCwYD
VQQIDARVdGFoMQ4wDAYDVQQHDAVQcm92bzEWMBQGA1UECgwNQUNNRSBUZWNoIElu
YzESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA2jd+jc+UTEBT6xa/+uykqsGnhktcflG4Wf09iKx7Apyy6d5JWaJKo3Kd
nQ2QzaFTooPlZO7MfUSYfVjiOWG8CjHwjQpyVYWokE/VVwKB/fahK+07AhpdrR4G
QPL6+xpeJrEHkObV6FY+rLXEwPaklW/NTueNGVgMebC5YfMIM6Gbdt1c1TxOod7u
aWST2R/hhd4IxOBWLgAK4TZ2EFfJBmquGqPYDiDJFdcALTWSvLHZkdctQ9xHaAKj
rexGDTOKEQpx7Wgq1+FB8TRbPFU69zuv8RFReISuO1oNImMcj0QvR3dHWgWkgqZL
del/yKSG+NohWq/SJiSRKGDMROUz7QIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBc
c/Fcm4PFbLgimQmwsCN9MZPHGJUsnpWuAZMNCL5MhzCh3eCF/IrJpVpZyNQ6x4OB
bxnSwheV6Cs5KP4hQkBc1zUXA/ANEMj4yRqUIeQL3m/NndKHix1MmnILKtVfo9Hv
LN+coBvCYM7/fIqTz4Uj5v+cpLx/UHipVatCs6V3EtvjLPB/TWgUlraL1rLjnRtf
M9V/ym3n6e0k2UI4YZPRhsZrO7N7f1KDuxYiw8e3VfAxVggPy8bzSH7rvUWOChfM
iHbBH4ppusUpiy/C7ZqRYMMwVzbdRfiZCvkRnxBQAt0BX6elof9WhNdYiGxLr2L6
Uuh0eSNjFNh73cxfujU6
-----END CERTIFICATE-----
17 changes: 17 additions & 0 deletions test/integration/custom-server/ssh/csr.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICnTCCAYUCAQAwWDELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDjAMBgNV
BAcMBVByb3ZvMRYwFAYDVQQKDA1BQ01FIFRlY2ggSW5jMRIwEAYDVQQDDAlsb2Nh
bGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaN36Nz5RMQFPr
Fr/67KSqwaeGS1x+UbhZ/T2IrHsCnLLp3klZokqjcp2dDZDNoVOig+Vk7sx9RJh9
WOI5YbwKMfCNCnJVhaiQT9VXAoH99qEr7TsCGl2tHgZA8vr7Gl4msQeQ5tXoVj6s
tcTA9qSVb81O540ZWAx5sLlh8wgzoZt23VzVPE6h3u5pZJPZH+GF3gjE4FYuAArh
NnYQV8kGaq4ao9gOIMkV1wAtNZK8sdmR1y1D3EdoAqOt7EYNM4oRCnHtaCrX4UHx
NFs8VTr3O6/xEVF4hK47Wg0iYxyPRC9Hd0daBaSCpkt16X/IpIb42iFar9ImJJEo
YMxE5TPtAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAaUFYrLTcYKqDrckGCP5I
v6FrOFMbI5OphFB+TpwSMT1ODUHd/YyCGGyzJWtTH6reLIKUfgCoLDHKbw8adUVi
AyunlILjf7fFXImYeBGPtaUmnvCU2JDD6ljxH6ng1uVLZ8ELyHiloedi4nYup0Bd
P9HLK97wcMJbXEMpr0zWBrVsh9/hCaXDa5tWXsl4mm4kJKxmLvmdvQvYft/Tbjtr
HaxotgZOKEd/9uW67nNASbGwMa/9pK4VVv3/Yf4CtvJEIM5rPpWEPwaqFcqEnQ1Q
WWO6a4K+4dCOuBc3C4i+ldruhO8acz17TvI9KlzUfRhUD5MkCDE+JI8/FapdOg65
cQ==
-----END CERTIFICATE REQUEST-----
20 changes: 20 additions & 0 deletions test/integration/custom-server/ssh/private-root-ca.cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDSjCCAjICCQCL3fBbRQKFGTANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJV
UzENMAsGA1UECAwEVXRhaDEOMAwGA1UEBwwFUHJvdm8xIzAhBgNVBAoMGkFDTUUg
U2lnbmluZyBBdXRob3JpdHkgSW5jMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0y
MjA2MjMwODA4MzRaFw0zNjAzMDEwODA4MzRaMGcxCzAJBgNVBAYTAlVTMQ0wCwYD
VQQIDARVdGFoMQ4wDAYDVQQHDAVQcm92bzEjMCEGA1UECgwaQUNNRSBTaWduaW5n
IEF1dGhvcml0eSBJbmMxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvjX0w6vUBI5HPTzX2JO2alMufe4OlxZc7mO3
Eq5B36qqYo9jjkux8izM5x9VCCxgrVWO10R0Ah03JgyNgN8XfZlBSS1Fs7AdRdzV
pGJsA5e+GZyIIoxxFQfdjeWqSudp63aqRjnfRheqLKeOYNZ9JvbkyW2bR5+csbOa
Aql3xYBM3CtlUwMtP33YVWsIGo19WkSni2JjJvaoXxTve2nvc/aeEEpn54BDnnO0
tX8Fz/k5W3gWeaZI1Kw2fqZTL9yVtsCimbLtmqlXyhV7Qz7jOPvCEBbYgvaENGg/
mRLcaQ5wHAXBVsn8xM5g98S2nSDzt62wQb21uJFCotb3aY+TKwIDAQABMA0GCSqG
SIb3DQEBCwUAA4IBAQB7/ETcGZetgCBmXeY0xD6XYkR1SJKWI4H/2FHha+Ddpwz8
QrupN1lYzj3IRugGPPojDDjXvZseUUQ0TFwQ71ldJGIIXw4KF5FzGW0lcLbQc6Sr
WKhMPAHIm17oZIS3KaGoq3aZty1ryPzVfbNfk7QsOrg+GMPMyVD7smYjbtrSxXha
RhlUJM4EQRIFpBon3scea8f+nOUcXdplRqn33FmYp7NcpSKhBXx51zAFXsmIh2On
UU/eyWzH6s/pl76h9D4ll5P6l/k8FyPAntxm/RRTy8H73DUTX5XSQJaNfhwp6afx
W6/hMTsrcn4TbElL3NDJYz94dxVfsQPa0Sgrx5tw
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions test/integration/custom-server/ssh/private-root-ca.privkey.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvjX0w6vUBI5HPTzX2JO2alMufe4OlxZc7mO3Eq5B36qqYo9j
jkux8izM5x9VCCxgrVWO10R0Ah03JgyNgN8XfZlBSS1Fs7AdRdzVpGJsA5e+GZyI
IoxxFQfdjeWqSudp63aqRjnfRheqLKeOYNZ9JvbkyW2bR5+csbOaAql3xYBM3Ctl
UwMtP33YVWsIGo19WkSni2JjJvaoXxTve2nvc/aeEEpn54BDnnO0tX8Fz/k5W3gW
eaZI1Kw2fqZTL9yVtsCimbLtmqlXyhV7Qz7jOPvCEBbYgvaENGg/mRLcaQ5wHAXB
Vsn8xM5g98S2nSDzt62wQb21uJFCotb3aY+TKwIDAQABAoIBAHqK7Gv7kZZ1y3Oq
dSz0zTrm6Db9Xaz9HVYAK/v/BDWDEE57LpqILdZmAoSMbQ3c+VPyoRoS4eJSzCrZ
P3jdQZcLW0I3xoYjWlieE43aUthltHVvoU0QyfHQpW47nmCvgk/OnZisxCm2KU6n
jFTbGro1qeQTl0ynih36Jai9YYp9J7Ivt4UgYGeVpaJIa+mRMHz5GvTARQr31lg3
zJD9ZMIC2Nq6ryE9/ZQAjc/oIzW6L/uMmNwHNjTmtKexP9nt+A/jG8utl7fF2il4
DFUIVb20kM0+kN7JXjYBGQ91X/4QyRMulTYPp/snr843/qH2whNmHAfECl4ySuBJ
KUFcfeECgYEA3PJiacFdnA6tenoWuZkhvhdGZIagWNesCs2FKIg0P/fcdCvlfPUt
XCvWECGCkXcfyTok3q1A1LYhEka426ERg6on2w+KhsYIUHI60xnYHkO+MLaPeIrd
mhEZdaqWEUlrhXQSnbqowr64ZadK+k5z7724qP2BhbrTiHwMqwc46AkCgYEA3GM/
GGyyw3RrDjLxLB1+KrA0spHtBHUSafVZRsT42VYmJsEGPGArgCGJu4S1DC6qVCsY
bUKE2OzbML4bSIMtYQ2uWq0og7UUK0cbOAv6krfXwGnRgLPAaQUhIGOpe4RtF8Qx
tXZKTGcGslaf8+gzEooKqlGPwvxXs5A6l2gpJpMCgYBEkOu9igZ00ZFAevbmbgEs
rqhntee46mU3jQQPygT8/PxrCNxU5PlIq0npA50za1Zv6h1bBUUjPcoRk+T2M4vt
4jYwIyiIHpih7nEW5eRNsBQrpdvsOpv+nePawi+D+dbmOVk1naGVnf43fa0k9IfC
FIxj1RgG2i2fI3AC+2DLkQKBgQCE0uPSCqDqn51t31Hu7o99ltkLzlr01sIUTiRS
PKBmDD/OF4N0m9lbzdq+w0qCXxWUyKxeHTsHqiiohcrXtweAeMheKgJC7r2LH73N
15pbFqXXd28mjC8onEjMxoP8x2Egc8Qpw3Mf/O/SR9b7HzS4ta2b3LAyKfeJZyGI
4uP6NQKBgHSYtm+O9sJY7ifdjkbVj9l2GdAdzBYZ+4rc+Z6kR5XLcsiVf7NyMmHG
bU0ii1hS3hyEtkpdoB5gG1YVFIR7Tbu7npJGKk8HQRR8Ftjl7o4y6GbthLgeSoxG
0IxtBt1lufbn1jlCtc+coEJPlcwY6DmXdgcXDrV+62FycmYKg850
-----END RSA PRIVATE KEY-----
1 change: 1 addition & 0 deletions test/integration/custom-server/ssh/private-root-ca.srl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
D96A441BA39789DD
27 changes: 27 additions & 0 deletions test/integration/custom-server/ssh/privkey.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA2jd+jc+UTEBT6xa/+uykqsGnhktcflG4Wf09iKx7Apyy6d5J
WaJKo3KdnQ2QzaFTooPlZO7MfUSYfVjiOWG8CjHwjQpyVYWokE/VVwKB/fahK+07
AhpdrR4GQPL6+xpeJrEHkObV6FY+rLXEwPaklW/NTueNGVgMebC5YfMIM6Gbdt1c
1TxOod7uaWST2R/hhd4IxOBWLgAK4TZ2EFfJBmquGqPYDiDJFdcALTWSvLHZkdct
Q9xHaAKjrexGDTOKEQpx7Wgq1+FB8TRbPFU69zuv8RFReISuO1oNImMcj0QvR3dH
WgWkgqZLdel/yKSG+NohWq/SJiSRKGDMROUz7QIDAQABAoIBAQDP7ZcCK2xkZ9tO
o8PUpg6VwqcNONvuZZHi9YHfrHId4BA+9hcweIrkSX9TuixjM7jMnx9C2KQzLNyc
e8g74xvZHxLWYcDmKtCeieN/4BzbUFjs0USr0VG3dmeBFcX+5HYYKhFKihoDI8Le
sOjE8X+MARdBezOglZx1i+ZpJbmH707IFSTYWSzLLGDnRZbXJ0GYCohApO5RhikI
bglpRRzQNERJDVKu4GDcfQXZAVuPawW8QmPSalLrEE1BjAqvELnz4DL717TBERV8
D8RPJa3GG2wJ2GgmuQCuYH1lj5hm+2J6QIYnc4R+Hv5SH0NUUttZwTcsLowAWesV
juFMBoLlAoGBAP8CtSrSpxZOBHR96ocgTMhrkK2ojO6CXOYYlrISlQfwnLflB3Ki
xyLqu2SMYL9It4Gqk2zmQgwx1gRVGZuMfX8gwfIWq1oGrbMmgl5z48j9dLD2+m4M
KeUCsV11ze6aOf07KAdjty33b/qeVuO+j9G7nO8kcd334yFhzF+bE9afAoGBANsQ
PaPXov5iVg8KKuJeAzoZJDmCt7kw1vAzjfZT1Mql4E8a8gf9z9q+pgJLoIKf5Kkd
8FjlSU1atC7AWZEJUPdJj5wFxan85fw37+RhEAaMvzGwwIZT5YK5pOdBMFQVhEnP
ZTvSXzBsefWdr4mlj5uFTB1LcyK1zRAg/WJKxKXzAoGBAO1tPfRC8SKJPQig+60X
26V20Nt+5MhkQ85P8m6VcoBT+/YTnV2URMgzuImjUaiHMaPehyiLMc9czyB1g0Qa
B/ZHL4wQozVMpoj4P8VlLR3DLdRd/0hatt7sJOsZdcTDf15Qp7JJmxGHIZE7vzaI
BCuH/FODoSjDVYuNHNWe81eNAoGAYr5WWpUntmzTB+J4ZCMmZzjP+FBwyjw2ln1W
n1M4VsQgcOffczS4TYykPeKjDl5ObuC85wUrXn/lOjGf7d16Lo1s+1IqwC3r6R25
t4L8+0bUI+zdS29jw+I0b70VsMEmKTMgGbABEk3DR7B1YKFNMzgJkCbjViEGtx93
t6emLnsCgYBQSpK+24/VmIDPqneilQar7bT1Nb+d+XG5Ef0sAEMTY8+LrAfiCDkJ
iBjl7gEZ9GbAkE3lUJoejMvOHX07ahq8viet1EpCpj9cw9RZ5o95cGJECQm6eaye
yzc5U154yq7k72RJYxHdEFH/NrwANjRs7RqTAhgW8grwBjY8gVpY3Q==
-----END RSA PRIVATE KEY-----
56 changes: 36 additions & 20 deletions test/integration/custom-server/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,28 @@ let server

const context = {}

const startServer = async (optEnv = {}, opts) => {
const scriptPath = join(appDir, 'server.js')
context.appPort = appPort = await getPort()
const env = Object.assign(
{ ...process.env },
{ PORT: `${appPort}`, __NEXT_TEST_MODE: 'true' },
optEnv
)

server = await initNextServerScript(
scriptPath,
/ready on/i,
env,
/ReferenceError: options is not defined/,
opts
)
}

describe('Custom Server', () => {
describe.each([
{ title: 'using HTTP', useHttps: false },
{ title: 'using HTTPS', useHttps: false },
ijjk marked this conversation as resolved.
Show resolved Hide resolved
])('Custom Server $title', ({ useHttps }) => {
const startServer = async (optEnv = {}, opts) => {
const scriptPath = join(appDir, 'server.js')
context.appPort = appPort = await getPort()
const env = Object.assign(
{ ...process.env },
{ PORT: `${appPort}`, __NEXT_TEST_MODE: 'true', USE_HTTPS: useHttps },
optEnv
)

server = await initNextServerScript(
scriptPath,
/ready on/i,
env,
/ReferenceError: options is not defined/,
opts
)
}

describe('with dynamic assetPrefix', () => {
beforeAll(() => startServer())
afterAll(() => killApp(server))
Expand Down Expand Up @@ -235,7 +238,20 @@ describe('Custom Server', () => {
expect(stderr).toContain(
'error - unhandledRejection: Error: unhandled rejection'
)
expect(stderr).toContain('server.js:22:22')
expect(stderr).toContain('server.js:31:22')
})
})

describe('with middleware $title', () => {
beforeAll(() => startServer(undefined, undefined, useHttps))
afterAll(() => killApp(server))

it('should read the expected url protocol in middleware', async () => {
const path = '/middleware-augmented'
const response = await fetchViaHTTP(appPort, path)
expect(response.headers.get('x-original-url')).toBe(
`${useHttps ? 'https' : 'http'}://localhost:${appPort}${path}`
)
})
})
})