vike 0.4.147-commit-2fa53b2 → 0.4.147-commit-f9a91f3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +1 -1
- package/dist/cjs/node/runtime/renderPage.js +65 -44
- package/dist/cjs/shared/route/resolveRedirects.js +8 -5
- package/dist/cjs/utils/parseUrl-extras.js +6 -1
- package/dist/cjs/utils/projectInfo.js +1 -1
- package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +2 -2
- package/dist/esm/node/runtime/renderPage.js +65 -44
- package/dist/esm/shared/route/resolveRedirects.js +8 -5
- package/dist/esm/utils/parseUrl-extras.d.ts +2 -0
- package/dist/esm/utils/parseUrl-extras.js +5 -0
- package/dist/esm/utils/projectInfo.d.ts +2 -2
- package/dist/esm/utils/projectInfo.js +1 -1
- package/package.json +1 -1
package/dist/cjs/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js
CHANGED
|
@@ -10,7 +10,7 @@ const globalObject = (0, utils_js_1.getGlobalObject)('assertNoInfiniteHttpRedire
|
|
|
10
10
|
redirectGraph: {}
|
|
11
11
|
});
|
|
12
12
|
function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
|
|
13
|
-
if (
|
|
13
|
+
if ((0, utils_js_1.isUriWithProtocol)(urlRedirectTarget)) {
|
|
14
14
|
// We assume that urlRedirectTarget points to an origin that is external (not the same origin), and we can therefore assume that the app doesn't define an infinite loop (in itself).
|
|
15
15
|
// - There isn't a reliable way to check whether the redirect points to an external origin or the same origin. For same origins, we assume/hope the user to pass the URL without origin.
|
|
16
16
|
// ```js
|
|
@@ -39,17 +39,17 @@ async function renderPage(pageContextInit) {
|
|
|
39
39
|
(0, assertArguments_js_1.assertArguments)(...arguments);
|
|
40
40
|
(0, utils_js_1.assert)((0, utils_js_1.hasProp)(pageContextInit, 'urlOriginal', 'string'));
|
|
41
41
|
(0, utils_js_1.assertEnv)();
|
|
42
|
-
if (
|
|
43
|
-
const
|
|
44
|
-
(0, utils_js_1.checkType)(
|
|
45
|
-
return
|
|
42
|
+
if (isIgnoredUrl(pageContextInit.urlOriginal)) {
|
|
43
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
|
|
44
|
+
(0, utils_js_1.checkType)(pageContextHttpResponseNull);
|
|
45
|
+
return pageContextHttpResponseNull;
|
|
46
46
|
}
|
|
47
47
|
const httpRequestId = getRequestId();
|
|
48
|
-
const
|
|
49
|
-
logHttpRequest(
|
|
48
|
+
const { urlOriginal } = pageContextInit;
|
|
49
|
+
logHttpRequest(urlOriginal, httpRequestId);
|
|
50
50
|
globalObject.pendingRequestsCount++;
|
|
51
51
|
const { pageContextReturn, onRequestDone } = await renderPage_wrapper(httpRequestId, () => renderPageAndPrepare(pageContextInit, httpRequestId));
|
|
52
|
-
logHttpResponse(
|
|
52
|
+
logHttpResponse(urlOriginal, httpRequestId, pageContextReturn);
|
|
53
53
|
globalObject.pendingRequestsCount--;
|
|
54
54
|
onRequestDone();
|
|
55
55
|
(0, utils_js_1.checkType)(pageContextReturn);
|
|
@@ -60,8 +60,8 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
|
|
|
60
60
|
// Invalid config
|
|
61
61
|
const handleInvalidConfig = () => {
|
|
62
62
|
(0, loggerRuntime_js_1.logRuntimeInfo)?.(picocolors_1.default.bold(picocolors_1.default.red("Couldn't load configuration: see error above.")), httpRequestId, 'error');
|
|
63
|
-
const
|
|
64
|
-
return
|
|
63
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
|
|
64
|
+
return pageContextHttpResponseNull;
|
|
65
65
|
};
|
|
66
66
|
if (isConfigInvalid_js_1.isConfigInvalid) {
|
|
67
67
|
return handleInvalidConfig();
|
|
@@ -77,8 +77,8 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
|
|
|
77
77
|
// initGlobalContext() and getRenderContext() don't call any user hooks => err isn't thrown from user code
|
|
78
78
|
(0, utils_js_1.assert)(!(0, abort_js_1.isAbortError)(err));
|
|
79
79
|
(0, loggerRuntime_js_1.logRuntimeError)(err, httpRequestId);
|
|
80
|
-
const
|
|
81
|
-
return
|
|
80
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(err, pageContextInit);
|
|
81
|
+
return pageContextHttpResponseNull;
|
|
82
82
|
}
|
|
83
83
|
if (isConfigInvalid_js_1.isConfigInvalid) {
|
|
84
84
|
return handleInvalidConfig();
|
|
@@ -86,15 +86,23 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
|
|
|
86
86
|
else {
|
|
87
87
|
// From now on, renderContext.pageConfigs contains all the configuration data; getVikeConfig() isn't called anymore for this request
|
|
88
88
|
}
|
|
89
|
+
// Check Base URL
|
|
90
|
+
{
|
|
91
|
+
const pageContextHttpResponse = checkBaseUrl(pageContextInit, httpRequestId);
|
|
92
|
+
if (pageContextHttpResponse)
|
|
93
|
+
return pageContextHttpResponse;
|
|
94
|
+
}
|
|
95
|
+
// Normalize URL
|
|
89
96
|
{
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
92
|
-
return
|
|
97
|
+
const pageContextHttpResponse = normalizeUrl(pageContextInit, httpRequestId);
|
|
98
|
+
if (pageContextHttpResponse)
|
|
99
|
+
return pageContextHttpResponse;
|
|
93
100
|
}
|
|
101
|
+
// Permanent redirects (HTTP status code `301`)
|
|
94
102
|
{
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
97
|
-
return
|
|
103
|
+
const pageContextHttpResponse = getPermanentRedirect(pageContextInit, httpRequestId);
|
|
104
|
+
if (pageContextHttpResponse)
|
|
105
|
+
return pageContextHttpResponse;
|
|
98
106
|
}
|
|
99
107
|
return await renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderContext, []);
|
|
100
108
|
}
|
|
@@ -177,8 +185,8 @@ async function renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderC
|
|
|
177
185
|
if (!handled.pageContextReturn) {
|
|
178
186
|
const pageContextAbort = errErrorPage._pageContextAbort;
|
|
179
187
|
(0, utils_js_1.assertWarning)(false, `Failed to render error page because ${picocolors_1.default.cyan(pageContextAbort._abortCall)} was called: make sure ${picocolors_1.default.cyan(pageContextAbort._abortCaller)} doesn't occur while the error page is being rendered.`, { onlyOnce: false });
|
|
180
|
-
const
|
|
181
|
-
return
|
|
188
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
|
|
189
|
+
return pageContextHttpResponseNull;
|
|
182
190
|
}
|
|
183
191
|
// `throw redirect()` / `throw render(url)`
|
|
184
192
|
return handled.pageContextReturn;
|
|
@@ -186,18 +194,28 @@ async function renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderC
|
|
|
186
194
|
if ((0, isNewError_js_1.isNewError)(errErrorPage, errNominalPage)) {
|
|
187
195
|
(0, loggerRuntime_js_1.logRuntimeError)(errErrorPage, httpRequestId);
|
|
188
196
|
}
|
|
189
|
-
const
|
|
190
|
-
return
|
|
197
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
|
|
198
|
+
return pageContextHttpResponseNull;
|
|
191
199
|
}
|
|
192
200
|
return pageContextErrorPage;
|
|
193
201
|
}
|
|
194
202
|
}
|
|
195
|
-
function logHttpRequest(
|
|
203
|
+
function logHttpRequest(urlOriginal, httpRequestId) {
|
|
196
204
|
const clearErrors = globalObject.pendingRequestsCount === 0;
|
|
197
|
-
(0, loggerRuntime_js_1.logRuntimeInfo)?.(
|
|
205
|
+
(0, loggerRuntime_js_1.logRuntimeInfo)?.(getRequestInfoMessage(urlOriginal), httpRequestId, 'info', clearErrors);
|
|
198
206
|
}
|
|
199
|
-
function
|
|
207
|
+
function getRequestInfoMessage(urlOriginal) {
|
|
208
|
+
return `HTTP request: ${picocolors_1.default.bold(urlOriginal)}`;
|
|
209
|
+
}
|
|
210
|
+
function logHttpResponse(urlOriginal, httpRequestId, pageContextReturn) {
|
|
200
211
|
const statusCode = pageContextReturn.httpResponse?.statusCode ?? null;
|
|
212
|
+
{
|
|
213
|
+
// If URL doesn't include Base URL
|
|
214
|
+
const { errorWhileRendering } = pageContextReturn;
|
|
215
|
+
const isSkipped = statusCode === null && (errorWhileRendering === null || errorWhileRendering === undefined);
|
|
216
|
+
if (isSkipped)
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
201
219
|
const isSuccess = statusCode !== null && statusCode >= 200 && statusCode <= 399;
|
|
202
220
|
const isNominal = isSuccess || statusCode === 404;
|
|
203
221
|
const color = (s) => picocolors_1.default.bold(isSuccess ? picocolors_1.default.green(String(s)) : picocolors_1.default.red(String(s)));
|
|
@@ -211,39 +229,30 @@ function logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn) {
|
|
|
211
229
|
.find((header) => header[0] === 'Location');
|
|
212
230
|
(0, utils_js_1.assert)(headerRedirect);
|
|
213
231
|
const urlRedirect = headerRedirect[1];
|
|
214
|
-
|
|
232
|
+
urlOriginal = urlRedirect;
|
|
215
233
|
}
|
|
216
|
-
(0, loggerRuntime_js_1.logRuntimeInfo)?.(`HTTP ${type} ${picocolors_1.default.bold(
|
|
234
|
+
(0, loggerRuntime_js_1.logRuntimeInfo)?.(`HTTP ${type} ${picocolors_1.default.bold(urlOriginal)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
|
|
217
235
|
}
|
|
218
236
|
function getPageContextHttpResponseNullWithError(err, pageContextInit) {
|
|
219
|
-
const
|
|
220
|
-
(0, utils_js_1.objectAssign)(
|
|
221
|
-
(0, utils_js_1.objectAssign)(
|
|
237
|
+
const pageContextHttpResponseNull = {};
|
|
238
|
+
(0, utils_js_1.objectAssign)(pageContextHttpResponseNull, pageContextInit);
|
|
239
|
+
(0, utils_js_1.objectAssign)(pageContextHttpResponseNull, {
|
|
222
240
|
httpResponse: null,
|
|
223
241
|
errorWhileRendering: err
|
|
224
242
|
});
|
|
225
|
-
return
|
|
243
|
+
return pageContextHttpResponseNull;
|
|
226
244
|
}
|
|
227
245
|
function getPageContextHttpResponseNull(pageContextInit) {
|
|
228
|
-
const
|
|
229
|
-
(0, utils_js_1.objectAssign)(
|
|
230
|
-
(0, utils_js_1.objectAssign)(
|
|
246
|
+
const pageContextHttpResponseNull = {};
|
|
247
|
+
(0, utils_js_1.objectAssign)(pageContextHttpResponseNull, pageContextInit);
|
|
248
|
+
(0, utils_js_1.objectAssign)(pageContextHttpResponseNull, {
|
|
231
249
|
httpResponse: null,
|
|
232
250
|
errorWhileRendering: null
|
|
233
251
|
});
|
|
234
|
-
return
|
|
252
|
+
return pageContextHttpResponseNull;
|
|
235
253
|
}
|
|
236
254
|
async function renderPageNominal(pageContext) {
|
|
237
255
|
(0, utils_js_1.objectAssign)(pageContext, { errorWhileRendering: null });
|
|
238
|
-
// Check Base URL
|
|
239
|
-
{
|
|
240
|
-
const { urlWithoutPageContextRequestSuffix } = (0, handlePageContextRequestUrl_js_1.handlePageContextRequestUrl)(pageContext.urlOriginal);
|
|
241
|
-
const hasBaseServer = (0, utils_js_1.parseUrl)(urlWithoutPageContextRequestSuffix, pageContext._baseServer).hasBaseServer || !!pageContext._urlRewrite;
|
|
242
|
-
if (!hasBaseServer) {
|
|
243
|
-
(0, utils_js_1.objectAssign)(pageContext, { httpResponse: null });
|
|
244
|
-
return pageContext;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
256
|
// Route
|
|
248
257
|
{
|
|
249
258
|
const pageContextFromRoute = await (0, index_js_1.route)(pageContext);
|
|
@@ -309,7 +318,7 @@ function getRequestId() {
|
|
|
309
318
|
(0, utils_js_1.assert)(httpRequestId >= 1);
|
|
310
319
|
return httpRequestId;
|
|
311
320
|
}
|
|
312
|
-
function
|
|
321
|
+
function isIgnoredUrl(urlOriginal) {
|
|
313
322
|
const isViteClientRequest = urlOriginal.endsWith('/@vite/client') || urlOriginal.startsWith('/@fs/');
|
|
314
323
|
(0, utils_js_1.assertWarning)(!isViteClientRequest, `The vike middleware renderPage() was called with the URL ${urlOriginal} which is unexpected because the HTTP request should have already been handled by Vite's development middleware. Make sure to 1. install Vite's development middleware and 2. add Vite's middleware *before* Vike's middleware, see https://vike.dev/renderPage`, { onlyOnce: true });
|
|
315
324
|
return (urlOriginal.endsWith('/__vite_ping') ||
|
|
@@ -406,3 +415,15 @@ async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextIn
|
|
|
406
415
|
(0, utils_js_1.assert)(pageContextAbort.abortStatusCode);
|
|
407
416
|
return { pageContextAbort };
|
|
408
417
|
}
|
|
418
|
+
function checkBaseUrl(pageContextInit, httpRequestId) {
|
|
419
|
+
const { baseServer } = (0, globalContext_js_1.getGlobalContext)();
|
|
420
|
+
const { urlOriginal } = pageContextInit;
|
|
421
|
+
const { urlWithoutPageContextRequestSuffix } = (0, handlePageContextRequestUrl_js_1.handlePageContextRequestUrl)(urlOriginal);
|
|
422
|
+
const { hasBaseServer } = (0, utils_js_1.parseUrl)(urlWithoutPageContextRequestSuffix, baseServer);
|
|
423
|
+
if (!hasBaseServer) {
|
|
424
|
+
(0, loggerRuntime_js_1.logRuntimeInfo)?.(`${getRequestInfoMessage(urlOriginal)} skipped because URL ${picocolors_1.default.bold(urlOriginal)} doesn't start with Base URL ${picocolors_1.default.bold(baseServer)} (https://vike.dev/base-url)`, httpRequestId, 'info');
|
|
425
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
|
|
426
|
+
return pageContextHttpResponseNull;
|
|
427
|
+
}
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.resolveRouteStringRedirect = exports.resolveRedirects = void 0;
|
|
7
7
|
const assertIsNotBrowser_js_1 = require("../../utils/assertIsNotBrowser.js");
|
|
8
|
+
const parseUrl_extras_js_1 = require("../../utils/parseUrl-extras.js");
|
|
8
9
|
const utils_js_1 = require("../utils.js");
|
|
9
10
|
const resolveRouteString_js_1 = require("./resolveRouteString.js");
|
|
10
11
|
const picocolors_1 = __importDefault(require("@brillout/picocolors"));
|
|
@@ -23,9 +24,9 @@ exports.resolveRedirects = resolveRedirects;
|
|
|
23
24
|
function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
24
25
|
(0, resolveRouteString_js_1.assertRouteString)(urlSource, `${configSrc} Invalid`);
|
|
25
26
|
(0, utils_js_1.assertUsage)(urlTarget.startsWith('/') ||
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
urlTarget === '*', `${configSrc} Invalid redirection target URL ${picocolors_1.default.cyan(urlTarget)}: the target URL should start with ${picocolors_1.default.cyan('/')}, ${picocolors_1.default.cyan('http
|
|
27
|
+
// Is allowing any protocol a safety issue? https://github.com/vikejs/vike/pull/1292#issuecomment-1828043917
|
|
28
|
+
(0, parseUrl_extras_js_1.isUriWithProtocol)(urlTarget) ||
|
|
29
|
+
urlTarget === '*', `${configSrc} Invalid redirection target URL ${picocolors_1.default.cyan(urlTarget)}: the target URL should start with ${picocolors_1.default.cyan('/')}, a valid protocol (${picocolors_1.default.cyan('https:')}, ${picocolors_1.default.cyan('http:')}, ${picocolors_1.default.cyan('ipfs:')}, ${picocolors_1.default.cyan('magnet:')}, ...), or be ${picocolors_1.default.cyan('*')}`);
|
|
29
30
|
assertParams(urlSource, urlTarget);
|
|
30
31
|
const match = (0, resolveRouteString_js_1.resolveRouteString)(urlSource, urlPathname);
|
|
31
32
|
if (!match)
|
|
@@ -37,10 +38,12 @@ function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
|
37
38
|
}
|
|
38
39
|
urlResolved = urlResolved.replaceAll(key, val);
|
|
39
40
|
});
|
|
40
|
-
|
|
41
|
+
if (!urlResolved.startsWith('mailto:')) {
|
|
42
|
+
(0, utils_js_1.assertUsage)(!urlResolved.includes('@'), 'URL should not contain "@" unless it is a mailto link.');
|
|
43
|
+
}
|
|
41
44
|
if (urlResolved === urlPathname)
|
|
42
45
|
return null;
|
|
43
|
-
(0, utils_js_1.assert)(
|
|
46
|
+
(0, utils_js_1.assert)(urlResolved.startsWith('/') || (0, parseUrl_extras_js_1.isUriWithProtocol)(urlResolved));
|
|
44
47
|
return urlResolved;
|
|
45
48
|
}
|
|
46
49
|
exports.resolveRouteStringRedirect = resolveRouteStringRedirect;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.addUrlOrigin = exports.removeUrlOrigin = exports.modifyUrlPathname = exports.removeBaseServer = exports.normalizeUrlPathname = exports.isBaseAssets = exports.prependBase = void 0;
|
|
3
|
+
exports.isUriWithProtocol = exports.addUrlOrigin = exports.removeUrlOrigin = exports.modifyUrlPathname = exports.removeBaseServer = exports.normalizeUrlPathname = exports.isBaseAssets = exports.prependBase = void 0;
|
|
4
4
|
const parseUrl_js_1 = require("./parseUrl.js");
|
|
5
5
|
const assert_js_1 = require("./assert.js");
|
|
6
6
|
const slice_js_1 = require("./slice.js");
|
|
@@ -103,3 +103,8 @@ function addUrlOrigin(url, origin) {
|
|
|
103
103
|
return urlModified;
|
|
104
104
|
}
|
|
105
105
|
exports.addUrlOrigin = addUrlOrigin;
|
|
106
|
+
function isUriWithProtocol(uri) {
|
|
107
|
+
// https://en.wikipedia.org/wiki/List_of_URI_schemes
|
|
108
|
+
return /^[a-z0-9][a-z0-9\.\+\-]*:/i.test(uri);
|
|
109
|
+
}
|
|
110
|
+
exports.isUriWithProtocol = isUriWithProtocol;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PROJECT_VERSION = exports.projectInfo = void 0;
|
|
4
4
|
const assertSingleInstance_js_1 = require("./assertSingleInstance.js");
|
|
5
|
-
const PROJECT_VERSION = '0.4.147-commit-
|
|
5
|
+
const PROJECT_VERSION = '0.4.147-commit-f9a91f3';
|
|
6
6
|
exports.PROJECT_VERSION = PROJECT_VERSION;
|
|
7
7
|
const projectInfo = {
|
|
8
8
|
projectName: 'Vike',
|
package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { assertNoInfiniteHttpRedirect };
|
|
2
|
-
import { assert, assertUsage, getGlobalObject } from '../../utils.js';
|
|
2
|
+
import { assert, assertUsage, getGlobalObject, isUriWithProtocol } from '../../utils.js';
|
|
3
3
|
import pc from '@brillout/picocolors';
|
|
4
4
|
const globalObject = getGlobalObject('assertNoInfiniteHttpRedirect.ts', {
|
|
5
5
|
redirectGraph: {}
|
|
6
6
|
});
|
|
7
7
|
function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
|
|
8
|
-
if (urlRedirectTarget
|
|
8
|
+
if (isUriWithProtocol(urlRedirectTarget)) {
|
|
9
9
|
// We assume that urlRedirectTarget points to an origin that is external (not the same origin), and we can therefore assume that the app doesn't define an infinite loop (in itself).
|
|
10
10
|
// - There isn't a reliable way to check whether the redirect points to an external origin or the same origin. For same origins, we assume/hope the user to pass the URL without origin.
|
|
11
11
|
// ```js
|
|
@@ -34,17 +34,17 @@ async function renderPage(pageContextInit) {
|
|
|
34
34
|
assertArguments(...arguments);
|
|
35
35
|
assert(hasProp(pageContextInit, 'urlOriginal', 'string'));
|
|
36
36
|
assertEnv();
|
|
37
|
-
if (
|
|
38
|
-
const
|
|
39
|
-
checkType(
|
|
40
|
-
return
|
|
37
|
+
if (isIgnoredUrl(pageContextInit.urlOriginal)) {
|
|
38
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
|
|
39
|
+
checkType(pageContextHttpResponseNull);
|
|
40
|
+
return pageContextHttpResponseNull;
|
|
41
41
|
}
|
|
42
42
|
const httpRequestId = getRequestId();
|
|
43
|
-
const
|
|
44
|
-
logHttpRequest(
|
|
43
|
+
const { urlOriginal } = pageContextInit;
|
|
44
|
+
logHttpRequest(urlOriginal, httpRequestId);
|
|
45
45
|
globalObject.pendingRequestsCount++;
|
|
46
46
|
const { pageContextReturn, onRequestDone } = await renderPage_wrapper(httpRequestId, () => renderPageAndPrepare(pageContextInit, httpRequestId));
|
|
47
|
-
logHttpResponse(
|
|
47
|
+
logHttpResponse(urlOriginal, httpRequestId, pageContextReturn);
|
|
48
48
|
globalObject.pendingRequestsCount--;
|
|
49
49
|
onRequestDone();
|
|
50
50
|
checkType(pageContextReturn);
|
|
@@ -54,8 +54,8 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
|
|
|
54
54
|
// Invalid config
|
|
55
55
|
const handleInvalidConfig = () => {
|
|
56
56
|
logRuntimeInfo?.(pc.bold(pc.red("Couldn't load configuration: see error above.")), httpRequestId, 'error');
|
|
57
|
-
const
|
|
58
|
-
return
|
|
57
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
|
|
58
|
+
return pageContextHttpResponseNull;
|
|
59
59
|
};
|
|
60
60
|
if (isConfigInvalid) {
|
|
61
61
|
return handleInvalidConfig();
|
|
@@ -71,8 +71,8 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
|
|
|
71
71
|
// initGlobalContext() and getRenderContext() don't call any user hooks => err isn't thrown from user code
|
|
72
72
|
assert(!isAbortError(err));
|
|
73
73
|
logRuntimeError(err, httpRequestId);
|
|
74
|
-
const
|
|
75
|
-
return
|
|
74
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(err, pageContextInit);
|
|
75
|
+
return pageContextHttpResponseNull;
|
|
76
76
|
}
|
|
77
77
|
if (isConfigInvalid) {
|
|
78
78
|
return handleInvalidConfig();
|
|
@@ -80,15 +80,23 @@ async function renderPageAndPrepare(pageContextInit, httpRequestId) {
|
|
|
80
80
|
else {
|
|
81
81
|
// From now on, renderContext.pageConfigs contains all the configuration data; getVikeConfig() isn't called anymore for this request
|
|
82
82
|
}
|
|
83
|
+
// Check Base URL
|
|
84
|
+
{
|
|
85
|
+
const pageContextHttpResponse = checkBaseUrl(pageContextInit, httpRequestId);
|
|
86
|
+
if (pageContextHttpResponse)
|
|
87
|
+
return pageContextHttpResponse;
|
|
88
|
+
}
|
|
89
|
+
// Normalize URL
|
|
83
90
|
{
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
86
|
-
return
|
|
91
|
+
const pageContextHttpResponse = normalizeUrl(pageContextInit, httpRequestId);
|
|
92
|
+
if (pageContextHttpResponse)
|
|
93
|
+
return pageContextHttpResponse;
|
|
87
94
|
}
|
|
95
|
+
// Permanent redirects (HTTP status code `301`)
|
|
88
96
|
{
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
return
|
|
97
|
+
const pageContextHttpResponse = getPermanentRedirect(pageContextInit, httpRequestId);
|
|
98
|
+
if (pageContextHttpResponse)
|
|
99
|
+
return pageContextHttpResponse;
|
|
92
100
|
}
|
|
93
101
|
return await renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderContext, []);
|
|
94
102
|
}
|
|
@@ -171,8 +179,8 @@ async function renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderC
|
|
|
171
179
|
if (!handled.pageContextReturn) {
|
|
172
180
|
const pageContextAbort = errErrorPage._pageContextAbort;
|
|
173
181
|
assertWarning(false, `Failed to render error page because ${pc.cyan(pageContextAbort._abortCall)} was called: make sure ${pc.cyan(pageContextAbort._abortCaller)} doesn't occur while the error page is being rendered.`, { onlyOnce: false });
|
|
174
|
-
const
|
|
175
|
-
return
|
|
182
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
|
|
183
|
+
return pageContextHttpResponseNull;
|
|
176
184
|
}
|
|
177
185
|
// `throw redirect()` / `throw render(url)`
|
|
178
186
|
return handled.pageContextReturn;
|
|
@@ -180,18 +188,28 @@ async function renderPageAlreadyPrepared(pageContextInit, httpRequestId, renderC
|
|
|
180
188
|
if (isNewError(errErrorPage, errNominalPage)) {
|
|
181
189
|
logRuntimeError(errErrorPage, httpRequestId);
|
|
182
190
|
}
|
|
183
|
-
const
|
|
184
|
-
return
|
|
191
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
|
|
192
|
+
return pageContextHttpResponseNull;
|
|
185
193
|
}
|
|
186
194
|
return pageContextErrorPage;
|
|
187
195
|
}
|
|
188
196
|
}
|
|
189
|
-
function logHttpRequest(
|
|
197
|
+
function logHttpRequest(urlOriginal, httpRequestId) {
|
|
190
198
|
const clearErrors = globalObject.pendingRequestsCount === 0;
|
|
191
|
-
logRuntimeInfo?.(
|
|
199
|
+
logRuntimeInfo?.(getRequestInfoMessage(urlOriginal), httpRequestId, 'info', clearErrors);
|
|
192
200
|
}
|
|
193
|
-
function
|
|
201
|
+
function getRequestInfoMessage(urlOriginal) {
|
|
202
|
+
return `HTTP request: ${pc.bold(urlOriginal)}`;
|
|
203
|
+
}
|
|
204
|
+
function logHttpResponse(urlOriginal, httpRequestId, pageContextReturn) {
|
|
194
205
|
const statusCode = pageContextReturn.httpResponse?.statusCode ?? null;
|
|
206
|
+
{
|
|
207
|
+
// If URL doesn't include Base URL
|
|
208
|
+
const { errorWhileRendering } = pageContextReturn;
|
|
209
|
+
const isSkipped = statusCode === null && (errorWhileRendering === null || errorWhileRendering === undefined);
|
|
210
|
+
if (isSkipped)
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
195
213
|
const isSuccess = statusCode !== null && statusCode >= 200 && statusCode <= 399;
|
|
196
214
|
const isNominal = isSuccess || statusCode === 404;
|
|
197
215
|
const color = (s) => pc.bold(isSuccess ? pc.green(String(s)) : pc.red(String(s)));
|
|
@@ -205,39 +223,30 @@ function logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn) {
|
|
|
205
223
|
.find((header) => header[0] === 'Location');
|
|
206
224
|
assert(headerRedirect);
|
|
207
225
|
const urlRedirect = headerRedirect[1];
|
|
208
|
-
|
|
226
|
+
urlOriginal = urlRedirect;
|
|
209
227
|
}
|
|
210
|
-
logRuntimeInfo?.(`HTTP ${type} ${pc.bold(
|
|
228
|
+
logRuntimeInfo?.(`HTTP ${type} ${pc.bold(urlOriginal)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
|
|
211
229
|
}
|
|
212
230
|
function getPageContextHttpResponseNullWithError(err, pageContextInit) {
|
|
213
|
-
const
|
|
214
|
-
objectAssign(
|
|
215
|
-
objectAssign(
|
|
231
|
+
const pageContextHttpResponseNull = {};
|
|
232
|
+
objectAssign(pageContextHttpResponseNull, pageContextInit);
|
|
233
|
+
objectAssign(pageContextHttpResponseNull, {
|
|
216
234
|
httpResponse: null,
|
|
217
235
|
errorWhileRendering: err
|
|
218
236
|
});
|
|
219
|
-
return
|
|
237
|
+
return pageContextHttpResponseNull;
|
|
220
238
|
}
|
|
221
239
|
function getPageContextHttpResponseNull(pageContextInit) {
|
|
222
|
-
const
|
|
223
|
-
objectAssign(
|
|
224
|
-
objectAssign(
|
|
240
|
+
const pageContextHttpResponseNull = {};
|
|
241
|
+
objectAssign(pageContextHttpResponseNull, pageContextInit);
|
|
242
|
+
objectAssign(pageContextHttpResponseNull, {
|
|
225
243
|
httpResponse: null,
|
|
226
244
|
errorWhileRendering: null
|
|
227
245
|
});
|
|
228
|
-
return
|
|
246
|
+
return pageContextHttpResponseNull;
|
|
229
247
|
}
|
|
230
248
|
async function renderPageNominal(pageContext) {
|
|
231
249
|
objectAssign(pageContext, { errorWhileRendering: null });
|
|
232
|
-
// Check Base URL
|
|
233
|
-
{
|
|
234
|
-
const { urlWithoutPageContextRequestSuffix } = handlePageContextRequestUrl(pageContext.urlOriginal);
|
|
235
|
-
const hasBaseServer = parseUrl(urlWithoutPageContextRequestSuffix, pageContext._baseServer).hasBaseServer || !!pageContext._urlRewrite;
|
|
236
|
-
if (!hasBaseServer) {
|
|
237
|
-
objectAssign(pageContext, { httpResponse: null });
|
|
238
|
-
return pageContext;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
250
|
// Route
|
|
242
251
|
{
|
|
243
252
|
const pageContextFromRoute = await route(pageContext);
|
|
@@ -303,7 +312,7 @@ function getRequestId() {
|
|
|
303
312
|
assert(httpRequestId >= 1);
|
|
304
313
|
return httpRequestId;
|
|
305
314
|
}
|
|
306
|
-
function
|
|
315
|
+
function isIgnoredUrl(urlOriginal) {
|
|
307
316
|
const isViteClientRequest = urlOriginal.endsWith('/@vite/client') || urlOriginal.startsWith('/@fs/');
|
|
308
317
|
assertWarning(!isViteClientRequest, `The vike middleware renderPage() was called with the URL ${urlOriginal} which is unexpected because the HTTP request should have already been handled by Vite's development middleware. Make sure to 1. install Vite's development middleware and 2. add Vite's middleware *before* Vike's middleware, see https://vike.dev/renderPage`, { onlyOnce: true });
|
|
309
318
|
return (urlOriginal.endsWith('/__vite_ping') ||
|
|
@@ -400,3 +409,15 @@ async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextIn
|
|
|
400
409
|
assert(pageContextAbort.abortStatusCode);
|
|
401
410
|
return { pageContextAbort };
|
|
402
411
|
}
|
|
412
|
+
function checkBaseUrl(pageContextInit, httpRequestId) {
|
|
413
|
+
const { baseServer } = getGlobalContext();
|
|
414
|
+
const { urlOriginal } = pageContextInit;
|
|
415
|
+
const { urlWithoutPageContextRequestSuffix } = handlePageContextRequestUrl(urlOriginal);
|
|
416
|
+
const { hasBaseServer } = parseUrl(urlWithoutPageContextRequestSuffix, baseServer);
|
|
417
|
+
if (!hasBaseServer) {
|
|
418
|
+
logRuntimeInfo?.(`${getRequestInfoMessage(urlOriginal)} skipped because URL ${pc.bold(urlOriginal)} doesn't start with Base URL ${pc.bold(baseServer)} (https://vike.dev/base-url)`, httpRequestId, 'info');
|
|
419
|
+
const pageContextHttpResponseNull = getPageContextHttpResponseNull(pageContextInit);
|
|
420
|
+
return pageContextHttpResponseNull;
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
@@ -2,6 +2,7 @@ export { resolveRedirects };
|
|
|
2
2
|
// For ./resolveRedirects.spec.ts
|
|
3
3
|
export { resolveRouteStringRedirect };
|
|
4
4
|
import { assertIsNotBrowser } from '../../utils/assertIsNotBrowser.js';
|
|
5
|
+
import { isUriWithProtocol } from '../../utils/parseUrl-extras.js';
|
|
5
6
|
import { assert, assertUsage } from '../utils.js';
|
|
6
7
|
import { assertRouteString, resolveRouteString } from './resolveRouteString.js';
|
|
7
8
|
import pc from '@brillout/picocolors';
|
|
@@ -19,9 +20,9 @@ function resolveRedirects(redirects, urlPathname) {
|
|
|
19
20
|
function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
20
21
|
assertRouteString(urlSource, `${configSrc} Invalid`);
|
|
21
22
|
assertUsage(urlTarget.startsWith('/') ||
|
|
22
|
-
|
|
23
|
-
urlTarget
|
|
24
|
-
urlTarget === '*', `${configSrc} Invalid redirection target URL ${pc.cyan(urlTarget)}: the target URL should start with ${pc.cyan('/')}, ${pc.cyan('http
|
|
23
|
+
// Is allowing any protocol a safety issue? https://github.com/vikejs/vike/pull/1292#issuecomment-1828043917
|
|
24
|
+
isUriWithProtocol(urlTarget) ||
|
|
25
|
+
urlTarget === '*', `${configSrc} Invalid redirection target URL ${pc.cyan(urlTarget)}: the target URL should start with ${pc.cyan('/')}, a valid protocol (${pc.cyan('https:')}, ${pc.cyan('http:')}, ${pc.cyan('ipfs:')}, ${pc.cyan('magnet:')}, ...), or be ${pc.cyan('*')}`);
|
|
25
26
|
assertParams(urlSource, urlTarget);
|
|
26
27
|
const match = resolveRouteString(urlSource, urlPathname);
|
|
27
28
|
if (!match)
|
|
@@ -33,10 +34,12 @@ function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
|
33
34
|
}
|
|
34
35
|
urlResolved = urlResolved.replaceAll(key, val);
|
|
35
36
|
});
|
|
36
|
-
|
|
37
|
+
if (!urlResolved.startsWith('mailto:')) {
|
|
38
|
+
assertUsage(!urlResolved.includes('@'), 'URL should not contain "@" unless it is a mailto link.');
|
|
39
|
+
}
|
|
37
40
|
if (urlResolved === urlPathname)
|
|
38
41
|
return null;
|
|
39
|
-
assert(
|
|
42
|
+
assert(urlResolved.startsWith('/') || isUriWithProtocol(urlResolved));
|
|
40
43
|
return urlResolved;
|
|
41
44
|
}
|
|
42
45
|
function assertParams(urlSource, urlTarget) {
|
|
@@ -5,6 +5,7 @@ export { removeBaseServer };
|
|
|
5
5
|
export { modifyUrlPathname };
|
|
6
6
|
export { removeUrlOrigin };
|
|
7
7
|
export { addUrlOrigin };
|
|
8
|
+
export { isUriWithProtocol };
|
|
8
9
|
declare function prependBase(url: string, baseServer: string): string;
|
|
9
10
|
declare function removeBaseServer(url: string, baseServer: string): string;
|
|
10
11
|
declare function isBaseAssets(base: string): boolean;
|
|
@@ -15,3 +16,4 @@ declare function removeUrlOrigin(url: string): {
|
|
|
15
16
|
origin: string | null;
|
|
16
17
|
};
|
|
17
18
|
declare function addUrlOrigin(url: string, origin: string | null): string;
|
|
19
|
+
declare function isUriWithProtocol(uri: string): boolean;
|
|
@@ -5,6 +5,7 @@ export { removeBaseServer };
|
|
|
5
5
|
export { modifyUrlPathname };
|
|
6
6
|
export { removeUrlOrigin };
|
|
7
7
|
export { addUrlOrigin };
|
|
8
|
+
export { isUriWithProtocol };
|
|
8
9
|
import { assertUrlComponents, createUrlFromComponents, isBaseServer, parseUrl } from './parseUrl.js';
|
|
9
10
|
import { assert } from './assert.js';
|
|
10
11
|
import { slice } from './slice.js';
|
|
@@ -100,3 +101,7 @@ function addUrlOrigin(url, origin) {
|
|
|
100
101
|
const urlModified = createUrlFromComponents(origin, pathnameOriginal, searchOriginal, hashOriginal);
|
|
101
102
|
return urlModified;
|
|
102
103
|
}
|
|
104
|
+
function isUriWithProtocol(uri) {
|
|
105
|
+
// https://en.wikipedia.org/wiki/List_of_URI_schemes
|
|
106
|
+
return /^[a-z0-9][a-z0-9\.\+\-]*:/i.test(uri);
|
|
107
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export { projectInfo };
|
|
2
2
|
export type { ProjectTag };
|
|
3
3
|
export { PROJECT_VERSION };
|
|
4
|
-
declare const PROJECT_VERSION: "0.4.147-commit-
|
|
4
|
+
declare const PROJECT_VERSION: "0.4.147-commit-f9a91f3";
|
|
5
5
|
type PackageName = typeof projectInfo.npmPackageName;
|
|
6
6
|
type ProjectVersion = typeof projectInfo.projectVersion;
|
|
7
7
|
type ProjectTag = `[${PackageName}]` | `[${PackageName}@${ProjectVersion}]`;
|
|
8
8
|
declare const projectInfo: {
|
|
9
9
|
projectName: "Vike";
|
|
10
|
-
projectVersion: "0.4.147-commit-
|
|
10
|
+
projectVersion: "0.4.147-commit-f9a91f3";
|
|
11
11
|
npmPackageName: "vike";
|
|
12
12
|
githubRepository: "https://github.com/vikejs/vike";
|
|
13
13
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { projectInfo };
|
|
2
2
|
export { PROJECT_VERSION };
|
|
3
3
|
import { onProjectInfo } from './assertSingleInstance.js';
|
|
4
|
-
const PROJECT_VERSION = '0.4.147-commit-
|
|
4
|
+
const PROJECT_VERSION = '0.4.147-commit-f9a91f3';
|
|
5
5
|
const projectInfo = {
|
|
6
6
|
projectName: 'Vike',
|
|
7
7
|
projectVersion: PROJECT_VERSION,
|