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.
@@ -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 (urlRedirectTarget.startsWith('http')) {
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 (skipRequest(pageContextInit.urlOriginal)) {
43
- const pageContextHttpReponseNull = getPageContextHttpResponseNull(pageContextInit);
44
- (0, utils_js_1.checkType)(pageContextHttpReponseNull);
45
- return pageContextHttpReponseNull;
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 urlToShowToUser = pageContextInit.urlOriginal;
49
- logHttpRequest(urlToShowToUser, httpRequestId);
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(urlToShowToUser, httpRequestId, pageContextReturn);
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 pageContextHttpReponseNull = getPageContextHttpResponseNull(pageContextInit);
64
- return pageContextHttpReponseNull;
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 pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(err, pageContextInit);
81
- return pageContextHttpReponseNull;
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 pageContextHttpReponse = normalizeUrl(pageContextInit, httpRequestId);
91
- if (pageContextHttpReponse)
92
- return pageContextHttpReponse;
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 pageContextHttpReponse = getPermanentRedirect(pageContextInit, httpRequestId);
96
- if (pageContextHttpReponse)
97
- return pageContextHttpReponse;
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 pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
181
- return pageContextHttpReponseNull;
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 pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
190
- return pageContextHttpReponseNull;
197
+ const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
198
+ return pageContextHttpResponseNull;
191
199
  }
192
200
  return pageContextErrorPage;
193
201
  }
194
202
  }
195
- function logHttpRequest(urlToShowToUser, httpRequestId) {
203
+ function logHttpRequest(urlOriginal, httpRequestId) {
196
204
  const clearErrors = globalObject.pendingRequestsCount === 0;
197
- (0, loggerRuntime_js_1.logRuntimeInfo)?.(`HTTP request: ${picocolors_1.default.bold(urlToShowToUser)}`, httpRequestId, 'info', clearErrors);
205
+ (0, loggerRuntime_js_1.logRuntimeInfo)?.(getRequestInfoMessage(urlOriginal), httpRequestId, 'info', clearErrors);
198
206
  }
199
- function logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn) {
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
- urlToShowToUser = urlRedirect;
232
+ urlOriginal = urlRedirect;
215
233
  }
216
- (0, loggerRuntime_js_1.logRuntimeInfo)?.(`HTTP ${type} ${picocolors_1.default.bold(urlToShowToUser)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
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 pageContextHttpReponseNull = {};
220
- (0, utils_js_1.objectAssign)(pageContextHttpReponseNull, pageContextInit);
221
- (0, utils_js_1.objectAssign)(pageContextHttpReponseNull, {
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 pageContextHttpReponseNull;
243
+ return pageContextHttpResponseNull;
226
244
  }
227
245
  function getPageContextHttpResponseNull(pageContextInit) {
228
- const pageContextHttpReponseNull = {};
229
- (0, utils_js_1.objectAssign)(pageContextHttpReponseNull, pageContextInit);
230
- (0, utils_js_1.objectAssign)(pageContextHttpReponseNull, {
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 pageContextHttpReponseNull;
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 skipRequest(urlOriginal) {
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
- urlTarget.startsWith('http://') ||
27
- urlTarget.startsWith('https://') ||
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://')}, ${picocolors_1.default.cyan('https://')}, or be ${picocolors_1.default.cyan('*')}`);
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
- (0, utils_js_1.assert)(!urlResolved.includes('@'));
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)(urlTarget.startsWith('/') || urlTarget.startsWith('http'));
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-2fa53b2';
5
+ const PROJECT_VERSION = '0.4.147-commit-f9a91f3';
6
6
  exports.PROJECT_VERSION = PROJECT_VERSION;
7
7
  const projectInfo = {
8
8
  projectName: 'Vike',
@@ -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.startsWith('http')) {
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 (skipRequest(pageContextInit.urlOriginal)) {
38
- const pageContextHttpReponseNull = getPageContextHttpResponseNull(pageContextInit);
39
- checkType(pageContextHttpReponseNull);
40
- return pageContextHttpReponseNull;
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 urlToShowToUser = pageContextInit.urlOriginal;
44
- logHttpRequest(urlToShowToUser, httpRequestId);
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(urlToShowToUser, httpRequestId, pageContextReturn);
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 pageContextHttpReponseNull = getPageContextHttpResponseNull(pageContextInit);
58
- return pageContextHttpReponseNull;
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 pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(err, pageContextInit);
75
- return pageContextHttpReponseNull;
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 pageContextHttpReponse = normalizeUrl(pageContextInit, httpRequestId);
85
- if (pageContextHttpReponse)
86
- return pageContextHttpReponse;
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 pageContextHttpReponse = getPermanentRedirect(pageContextInit, httpRequestId);
90
- if (pageContextHttpReponse)
91
- return pageContextHttpReponse;
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 pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
175
- return pageContextHttpReponseNull;
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 pageContextHttpReponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
184
- return pageContextHttpReponseNull;
191
+ const pageContextHttpResponseNull = getPageContextHttpResponseNullWithError(errNominalPage, pageContextInit);
192
+ return pageContextHttpResponseNull;
185
193
  }
186
194
  return pageContextErrorPage;
187
195
  }
188
196
  }
189
- function logHttpRequest(urlToShowToUser, httpRequestId) {
197
+ function logHttpRequest(urlOriginal, httpRequestId) {
190
198
  const clearErrors = globalObject.pendingRequestsCount === 0;
191
- logRuntimeInfo?.(`HTTP request: ${pc.bold(urlToShowToUser)}`, httpRequestId, 'info', clearErrors);
199
+ logRuntimeInfo?.(getRequestInfoMessage(urlOriginal), httpRequestId, 'info', clearErrors);
192
200
  }
193
- function logHttpResponse(urlToShowToUser, httpRequestId, pageContextReturn) {
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
- urlToShowToUser = urlRedirect;
226
+ urlOriginal = urlRedirect;
209
227
  }
210
- logRuntimeInfo?.(`HTTP ${type} ${pc.bold(urlToShowToUser)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
228
+ logRuntimeInfo?.(`HTTP ${type} ${pc.bold(urlOriginal)} ${color(statusCode ?? 'ERR')}`, httpRequestId, isNominal ? 'info' : 'error');
211
229
  }
212
230
  function getPageContextHttpResponseNullWithError(err, pageContextInit) {
213
- const pageContextHttpReponseNull = {};
214
- objectAssign(pageContextHttpReponseNull, pageContextInit);
215
- objectAssign(pageContextHttpReponseNull, {
231
+ const pageContextHttpResponseNull = {};
232
+ objectAssign(pageContextHttpResponseNull, pageContextInit);
233
+ objectAssign(pageContextHttpResponseNull, {
216
234
  httpResponse: null,
217
235
  errorWhileRendering: err
218
236
  });
219
- return pageContextHttpReponseNull;
237
+ return pageContextHttpResponseNull;
220
238
  }
221
239
  function getPageContextHttpResponseNull(pageContextInit) {
222
- const pageContextHttpReponseNull = {};
223
- objectAssign(pageContextHttpReponseNull, pageContextInit);
224
- objectAssign(pageContextHttpReponseNull, {
240
+ const pageContextHttpResponseNull = {};
241
+ objectAssign(pageContextHttpResponseNull, pageContextInit);
242
+ objectAssign(pageContextHttpResponseNull, {
225
243
  httpResponse: null,
226
244
  errorWhileRendering: null
227
245
  });
228
- return pageContextHttpReponseNull;
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 skipRequest(urlOriginal) {
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
- urlTarget.startsWith('http://') ||
23
- urlTarget.startsWith('https://') ||
24
- urlTarget === '*', `${configSrc} Invalid redirection target URL ${pc.cyan(urlTarget)}: the target URL should start with ${pc.cyan('/')}, ${pc.cyan('http://')}, ${pc.cyan('https://')}, or be ${pc.cyan('*')}`);
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
- assert(!urlResolved.includes('@'));
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(urlTarget.startsWith('/') || urlTarget.startsWith('http'));
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-2fa53b2";
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-2fa53b2";
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-2fa53b2';
4
+ const PROJECT_VERSION = '0.4.147-commit-f9a91f3';
5
5
  const projectInfo = {
6
6
  projectName: 'Vike',
7
7
  projectVersion: PROJECT_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.147-commit-2fa53b2",
3
+ "version": "0.4.147-commit-f9a91f3",
4
4
  "scripts": {
5
5
  "dev": "tsc --watch",
6
6
  "build": "rimraf dist/ && pnpm run build:esm && pnpm run build:cjs",