-
Notifications
You must be signed in to change notification settings - Fork 386
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: support for redirects with 200 status. Fix crashing dev server w… #7034
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,10 +121,14 @@ const formatEdgeFunctionError = (errorBuffer, acceptsHtml) => { | |
}) | ||
} | ||
|
||
function isInternal(url?: string): boolean { | ||
function isInternalFunctions(url?: string): boolean { | ||
return url?.startsWith('/.netlify/') ?? false | ||
} | ||
|
||
function isInternal(url?: string): boolean { | ||
return url?.startsWith('/') ?? false | ||
} | ||
|
||
function isFunction(functionsPort: boolean | number | undefined, url: string) { | ||
return functionsPort && url.match(DEFAULT_FUNCTION_URL_EXPRESSION) | ||
} | ||
|
@@ -201,7 +205,7 @@ const handleAddonUrl = function ({ addonUrl, req, res }) { | |
|
||
// @ts-expect-error TS(7006) FIXME: Parameter 'match' implicitly has an 'any' type. | ||
const isRedirect = function (match) { | ||
return match.status && match.status >= 300 && match.status <= 400 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this is a mistake, 400 should not be included |
||
return match.status && match.status >= 300 && match.status < 400 | ||
} | ||
|
||
// @ts-expect-error TS(7006) FIXME: Parameter 'publicFolder' implicitly has an 'any' t... Remove this comment to see the full error message | ||
|
@@ -415,8 +419,8 @@ const serveRedirect = async function ({ | |
const ct = req.headers['content-type'] ? contentType.parse(req).type : '' | ||
if ( | ||
req.method === 'POST' && | ||
!isInternal(req.url) && | ||
!isInternal(destURL) && | ||
!isInternalFunctions(req.url) && | ||
!isInternalFunctions(destURL) && | ||
(ct.endsWith('/x-www-form-urlencoded') || ct === 'multipart/form-data') | ||
) { | ||
return proxy.web(req, res, { target: options.functionsServer }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. on line 433-437 (GH not allow to leave a comment there, bummer) instead of checking if it's just a static file, or internalUrl which is now And then basically it lands into the if-else check and does the status/url override |
||
|
@@ -431,9 +435,13 @@ const serveRedirect = async function ({ | |
match.force || | ||
(!staticFile && ((!options.framework && destStaticFile) || isInternal(destURL) || matchingFunction)) | ||
) { | ||
// 3xx redirects parsed above, here are 2xx meaning just override the url of proxying page and use the status | ||
// which comes from that url | ||
req.url = destStaticFile ? destStaticFile + dest.search : destURL | ||
const { status } = match | ||
statusValue = status | ||
if (match.force || status !== 200) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. override status code only if forcing or status is not 200, when 200 is just shadowing the page by the url, so it's status should be propagated (e.g. 404 because it's not there or idk 201 because server decided to return 201 by that url) |
||
statusValue = status | ||
} | ||
console.log(`${NETLIFYDEVLOG} Rewrote URL to`, req.url) | ||
} | ||
|
||
|
@@ -450,9 +458,11 @@ const serveRedirect = async function ({ | |
|
||
return proxy.web(req, res, { headers: functionHeaders, target: options.functionsServer }) | ||
} | ||
|
||
if (isImageRequest(req)) { | ||
return imageProxy(req, res) | ||
} | ||
|
||
const addonUrl = getAddonUrl(options.addonsUrls, req) | ||
if (addonUrl) { | ||
return handleAddonUrl({ req, res, addonUrl }) | ||
|
@@ -518,6 +528,8 @@ const initializeProxy = async function ({ | |
}) | ||
|
||
proxy.on('error', (err, req, res, proxyUrl) => { | ||
console.error('Got error from proxy', err) | ||
|
||
// @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message | ||
const options = req.proxyOptions | ||
|
||
|
@@ -632,7 +644,7 @@ const initializeProxy = async function ({ | |
} | ||
} | ||
|
||
if (options.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) { | ||
if (isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here is another change. So we basically want to follow it:
![]() This is browser built-in contents. Location header is there. Browser So, instead, here we are changing the flow for the netlify dev (which is typically runs SSGs in develop mode, not in the production mode) to this: | Target app wants redirect on this route? Follow it This change can be left intact and for instance, I can enable it only for some of the contexts (e.g. for dev server context). WDYT? |
||
req.url = proxyRes.headers.location | ||
return serveRedirect({ | ||
// We don't want to match functions at this point because any redirects | ||
|
@@ -875,7 +887,7 @@ const onRequest = async ( | |
hasFormSubmissionHandler && | ||
functionsServer && | ||
req.method === 'POST' && | ||
!isInternal(req.url) && | ||
!isInternalFunctions(req.url) && | ||
(ct.endsWith('/x-www-form-urlencoded') || ct === 'multipart/form-data') | ||
) { | ||
return proxy.web(req, res, { target: functionsServer }) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,6 @@ | |
command = "npm run serve" | ||
framework = "#custom" | ||
functions = "functions/" | ||
port = 7000 | ||
port = 7001 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 7000 by default on OS X taken by airplay, failed my tests |
||
publish = "out" | ||
targetPort = 1313 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function ExistsPage() { | ||
return <p>Exists page</p> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.netlify |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const http = require('http') | ||
|
||
const server = http.createServer((req, res) => { | ||
const pathname = new URL(req.url, 'http://localhost').pathname | ||
|
||
console.log(`Got ${pathname}`) | ||
|
||
if (pathname === '/') { | ||
res.write('Root page') | ||
res.end() | ||
} else if (pathname === '/test/exists') { | ||
res.writeHead(302, undefined, { location: '/test/exists/' }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. examples of the site which makes redirect, so then in netlify toml we want to land on this page, which then wants to jump to the next |
||
res.end() | ||
} else if (pathname === '/test/exists/') { | ||
res.write('Test exists page') | ||
res.end() | ||
} else if (pathname === '/test/not-allowed') { | ||
res.writeHead(405) | ||
res.write('This not allowed') | ||
res.end() | ||
} else { | ||
res.writeHead(404).write('Page is not found') | ||
res.end() | ||
} | ||
}) | ||
|
||
server.listen(6124, () => { | ||
console.log('Server is Running') | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[dev] | ||
targetPort = 6124 | ||
command = "npm run dev" | ||
|
||
[[redirects]] | ||
from = "/local/*" | ||
to = "/:splat" | ||
status = 200 | ||
|
||
[[redirects]] | ||
from = "/local-force/*" | ||
to = "/:splat" | ||
status = 402 | ||
force = true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "site-with-redirect", | ||
"version": "1.0.0", | ||
"private": true, | ||
"scripts": { | ||
"dev": "node index.js" | ||
}, | ||
"dependencies": {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've separated these 2 methods
All places of usage is using
isInternalFunctions
, and only 1 place which affects URL override use this method