happy-dom 16.6.0 → 16.7.1
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/cjs/browser/DefaultBrowserSettings.cjs +3 -1
- package/cjs/browser/DefaultBrowserSettings.cjs.map +1 -1
- package/cjs/browser/DefaultBrowserSettings.d.ts.map +1 -1
- package/cjs/browser/types/IBrowserSettings.d.ts +9 -1
- package/cjs/browser/types/IBrowserSettings.d.ts.map +1 -1
- package/cjs/browser/types/IOptionalBrowserSettings.d.ts +9 -1
- package/cjs/browser/types/IOptionalBrowserSettings.d.ts.map +1 -1
- package/cjs/cookie/CookieContainer.cjs +13 -10
- package/cjs/cookie/CookieContainer.cjs.map +1 -1
- package/cjs/cookie/CookieContainer.d.ts +2 -1
- package/cjs/cookie/CookieContainer.d.ts.map +1 -1
- package/cjs/cookie/DefaultCookie.cjs +20 -0
- package/cjs/cookie/DefaultCookie.cjs.map +1 -0
- package/cjs/cookie/DefaultCookie.d.ts +4 -0
- package/cjs/cookie/DefaultCookie.d.ts.map +1 -0
- package/cjs/cookie/ICookie.d.ts +1 -1
- package/cjs/cookie/ICookie.d.ts.map +1 -1
- package/cjs/cookie/ICookieContainer.d.ts +1 -1
- package/cjs/cookie/ICookieContainer.d.ts.map +1 -1
- package/cjs/cookie/IOptionalCookie.cjs +3 -0
- package/cjs/cookie/IOptionalCookie.cjs.map +1 -0
- package/cjs/cookie/IOptionalCookie.d.ts +13 -0
- package/cjs/cookie/IOptionalCookie.d.ts.map +1 -0
- package/cjs/cookie/urilities/CookieStringUtility.cjs +4 -10
- package/cjs/cookie/urilities/CookieStringUtility.cjs.map +1 -1
- package/cjs/cookie/urilities/CookieStringUtility.d.ts.map +1 -1
- package/cjs/fetch/Fetch.cjs +62 -9
- package/cjs/fetch/Fetch.cjs.map +1 -1
- package/cjs/fetch/Fetch.d.ts +7 -1
- package/cjs/fetch/Fetch.d.ts.map +1 -1
- package/cjs/fetch/SyncFetch.cjs +45 -1
- package/cjs/fetch/SyncFetch.cjs.map +1 -1
- package/cjs/fetch/SyncFetch.d.ts +6 -0
- package/cjs/fetch/SyncFetch.d.ts.map +1 -1
- package/cjs/fetch/types/IVirtualServer.cjs +3 -0
- package/cjs/fetch/types/IVirtualServer.cjs.map +1 -0
- package/cjs/fetch/types/IVirtualServer.d.ts +8 -0
- package/cjs/fetch/types/IVirtualServer.d.ts.map +1 -0
- package/cjs/fetch/utilities/VirtualServerUtility.cjs +83 -0
- package/cjs/fetch/utilities/VirtualServerUtility.cjs.map +1 -0
- package/cjs/fetch/utilities/VirtualServerUtility.d.ts +30 -0
- package/cjs/fetch/utilities/VirtualServerUtility.d.ts.map +1 -0
- package/cjs/index.cjs +10 -8
- package/cjs/index.cjs.map +1 -1
- package/cjs/index.d.ts +9 -5
- package/cjs/index.d.ts.map +1 -1
- package/lib/browser/DefaultBrowserSettings.d.ts.map +1 -1
- package/lib/browser/DefaultBrowserSettings.js +3 -1
- package/lib/browser/DefaultBrowserSettings.js.map +1 -1
- package/lib/browser/types/IBrowserSettings.d.ts +9 -1
- package/lib/browser/types/IBrowserSettings.d.ts.map +1 -1
- package/lib/browser/types/IOptionalBrowserSettings.d.ts +9 -1
- package/lib/browser/types/IOptionalBrowserSettings.d.ts.map +1 -1
- package/lib/cookie/CookieContainer.d.ts +2 -1
- package/lib/cookie/CookieContainer.d.ts.map +1 -1
- package/lib/cookie/CookieContainer.js +13 -10
- package/lib/cookie/CookieContainer.js.map +1 -1
- package/lib/cookie/DefaultCookie.d.ts +4 -0
- package/lib/cookie/DefaultCookie.d.ts.map +1 -0
- package/lib/cookie/DefaultCookie.js +15 -0
- package/lib/cookie/DefaultCookie.js.map +1 -0
- package/lib/cookie/ICookie.d.ts +1 -1
- package/lib/cookie/ICookie.d.ts.map +1 -1
- package/lib/cookie/ICookieContainer.d.ts +1 -1
- package/lib/cookie/ICookieContainer.d.ts.map +1 -1
- package/lib/cookie/IOptionalCookie.d.ts +13 -0
- package/lib/cookie/IOptionalCookie.d.ts.map +1 -0
- package/lib/cookie/IOptionalCookie.js +2 -0
- package/lib/cookie/IOptionalCookie.js.map +1 -0
- package/lib/cookie/urilities/CookieStringUtility.d.ts.map +1 -1
- package/lib/cookie/urilities/CookieStringUtility.js +4 -10
- package/lib/cookie/urilities/CookieStringUtility.js.map +1 -1
- package/lib/fetch/Fetch.d.ts +7 -1
- package/lib/fetch/Fetch.d.ts.map +1 -1
- package/lib/fetch/Fetch.js +62 -9
- package/lib/fetch/Fetch.js.map +1 -1
- package/lib/fetch/SyncFetch.d.ts +6 -0
- package/lib/fetch/SyncFetch.d.ts.map +1 -1
- package/lib/fetch/SyncFetch.js +45 -1
- package/lib/fetch/SyncFetch.js.map +1 -1
- package/lib/fetch/types/IVirtualServer.d.ts +8 -0
- package/lib/fetch/types/IVirtualServer.d.ts.map +1 -0
- package/lib/fetch/types/IVirtualServer.js +2 -0
- package/lib/fetch/types/IVirtualServer.js.map +1 -0
- package/lib/fetch/utilities/VirtualServerUtility.d.ts +30 -0
- package/lib/fetch/utilities/VirtualServerUtility.d.ts.map +1 -0
- package/lib/fetch/utilities/VirtualServerUtility.js +77 -0
- package/lib/fetch/utilities/VirtualServerUtility.js.map +1 -0
- package/lib/index.d.ts +9 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/browser/DefaultBrowserSettings.ts +3 -1
- package/src/browser/types/IBrowserSettings.ts +10 -1
- package/src/browser/types/IOptionalBrowserSettings.ts +10 -1
- package/src/cookie/CookieContainer.ts +19 -11
- package/src/cookie/DefaultCookie.ts +17 -0
- package/src/cookie/ICookie.ts +1 -3
- package/src/cookie/ICookieContainer.ts +1 -1
- package/src/cookie/IOptionalCookie.ts +16 -0
- package/src/cookie/urilities/CookieStringUtility.ts +4 -11
- package/src/fetch/Fetch.ts +91 -12
- package/src/fetch/SyncFetch.ts +60 -1
- package/src/fetch/types/IVirtualServer.ts +7 -0
- package/src/fetch/utilities/VirtualServerUtility.ts +89 -0
- package/src/index.ts +15 -7
@@ -0,0 +1,17 @@
|
|
1
|
+
import CookieSameSiteEnum from './enums/CookieSameSiteEnum.js';
|
2
|
+
import ICookie from './ICookie.js';
|
3
|
+
|
4
|
+
export default <ICookie>{
|
5
|
+
// Required
|
6
|
+
key: null,
|
7
|
+
originURL: null,
|
8
|
+
|
9
|
+
// Optional
|
10
|
+
value: null,
|
11
|
+
domain: '',
|
12
|
+
path: '',
|
13
|
+
expires: null,
|
14
|
+
httpOnly: false,
|
15
|
+
secure: false,
|
16
|
+
sameSite: CookieSameSiteEnum.lax
|
17
|
+
};
|
package/src/cookie/ICookie.ts
CHANGED
@@ -3,10 +3,8 @@ import CookieSameSiteEnum from './enums/CookieSameSiteEnum.js';
|
|
3
3
|
export default interface ICookie {
|
4
4
|
// Required
|
5
5
|
key: string;
|
6
|
-
value: string | null;
|
7
6
|
originURL: URL;
|
8
|
-
|
9
|
-
// Optional
|
7
|
+
value: string | null;
|
10
8
|
domain: string;
|
11
9
|
path: string;
|
12
10
|
expires: Date | null;
|
@@ -22,5 +22,5 @@ export default interface ICookieContainer {
|
|
22
22
|
* @param [httpOnly] "true" if only http cookies should be returned.
|
23
23
|
* @returns Cookies.
|
24
24
|
*/
|
25
|
-
getCookies(url: URL | null, httpOnly
|
25
|
+
getCookies(url: URL | null, httpOnly?: boolean): ICookie[];
|
26
26
|
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import CookieSameSiteEnum from './enums/CookieSameSiteEnum.js';
|
2
|
+
|
3
|
+
export default interface IOptionalCookie {
|
4
|
+
// Required
|
5
|
+
key: string;
|
6
|
+
originURL: URL;
|
7
|
+
|
8
|
+
// Optional
|
9
|
+
value?: string | null;
|
10
|
+
domain?: string;
|
11
|
+
path?: string;
|
12
|
+
expires?: Date | null;
|
13
|
+
httpOnly?: boolean;
|
14
|
+
secure?: boolean;
|
15
|
+
sameSite?: CookieSameSiteEnum;
|
16
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import CookieSameSiteEnum from '../enums/CookieSameSiteEnum.js';
|
2
2
|
import URL from '../../url/URL.js';
|
3
3
|
import ICookie from '../ICookie.js';
|
4
|
+
import DefaultCookie from '../DefaultCookie.js';
|
4
5
|
|
5
6
|
/**
|
6
7
|
* Cookie string.
|
@@ -20,20 +21,12 @@ export default class CookieStringUtility {
|
|
20
21
|
const key = index !== -1 ? part.slice(0, index).trim() : part.trim();
|
21
22
|
const value = index !== -1 ? part.slice(index + 1).trim() : null;
|
22
23
|
|
23
|
-
const cookie: ICookie = {
|
24
|
+
const cookie: ICookie = Object.assign({}, DefaultCookie, {
|
24
25
|
// Required
|
25
26
|
key,
|
26
27
|
value,
|
27
|
-
originURL
|
28
|
-
|
29
|
-
// Optional
|
30
|
-
domain: '',
|
31
|
-
path: '',
|
32
|
-
expires: null,
|
33
|
-
httpOnly: false,
|
34
|
-
secure: false,
|
35
|
-
sameSite: CookieSameSiteEnum.lax
|
36
|
-
};
|
28
|
+
originURL
|
29
|
+
});
|
37
30
|
|
38
31
|
// Invalid if key is empty.
|
39
32
|
if (!cookie.key) {
|
package/src/fetch/Fetch.ts
CHANGED
@@ -8,6 +8,8 @@ import HTTP, { IncomingMessage } from 'http';
|
|
8
8
|
import HTTPS from 'https';
|
9
9
|
import Zlib from 'zlib';
|
10
10
|
import URL from '../url/URL.js';
|
11
|
+
import FS from 'fs';
|
12
|
+
import Path from 'path';
|
11
13
|
import { Socket } from 'net';
|
12
14
|
import Stream from 'stream';
|
13
15
|
import DataURIParser from './data-uri/DataURIParser.js';
|
@@ -27,6 +29,7 @@ import FetchHTTPSCertificate from './certificate/FetchHTTPSCertificate.js';
|
|
27
29
|
import { Buffer } from 'buffer';
|
28
30
|
import FetchBodyUtility from './utilities/FetchBodyUtility.js';
|
29
31
|
import IFetchInterceptor from './types/IFetchInterceptor.js';
|
32
|
+
import VirtualServerUtility from './utilities/VirtualServerUtility.js';
|
30
33
|
|
31
34
|
const LAST_CHUNK = Buffer.from('0\r\n\r\n');
|
32
35
|
|
@@ -51,7 +54,7 @@ export default class Fetch {
|
|
51
54
|
private nodeResponse: IncomingMessage | null = null;
|
52
55
|
private response: Response | null = null;
|
53
56
|
private responseHeaders: Headers | null = null;
|
54
|
-
private interceptor
|
57
|
+
private interceptor: IFetchInterceptor | null;
|
55
58
|
private request: Request;
|
56
59
|
private redirectCount = 0;
|
57
60
|
private disableCache: boolean;
|
@@ -111,17 +114,27 @@ export default class Fetch {
|
|
111
114
|
*/
|
112
115
|
public async send(): Promise<Response> {
|
113
116
|
FetchRequestReferrerUtility.prepareRequest(new URL(this.#window.location.href), this.request);
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
|
118
|
+
if (this.interceptor?.beforeAsyncRequest) {
|
119
|
+
const taskID = this.#browserFrame[PropertySymbol.asyncTaskManager].startTask();
|
120
|
+
const response = await this.interceptor.beforeAsyncRequest({
|
121
|
+
request: this.request,
|
122
|
+
window: this.#window
|
123
|
+
});
|
124
|
+
this.#browserFrame[PropertySymbol.asyncTaskManager].endTask(taskID);
|
125
|
+
if (response instanceof Response) {
|
126
|
+
return response;
|
127
|
+
}
|
122
128
|
}
|
129
|
+
|
123
130
|
FetchRequestValidationUtility.validateSchema(this.request);
|
124
131
|
|
132
|
+
const virtualServerResponse = await this.getVirtualServerResponse();
|
133
|
+
|
134
|
+
if (virtualServerResponse) {
|
135
|
+
return virtualServerResponse;
|
136
|
+
}
|
137
|
+
|
125
138
|
if (this.request.signal.aborted) {
|
126
139
|
throw new this.#window.DOMException(
|
127
140
|
'The operation was aborted.',
|
@@ -171,7 +184,7 @@ export default class Fetch {
|
|
171
184
|
const compliesWithCrossOriginPolicy = await this.compliesWithCrossOriginPolicy();
|
172
185
|
|
173
186
|
if (!compliesWithCrossOriginPolicy) {
|
174
|
-
this.#
|
187
|
+
this.#browserFrame?.page?.console.warn(
|
175
188
|
`Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at "${this.request.url}".`
|
176
189
|
);
|
177
190
|
throw new this.#window.DOMException(
|
@@ -270,6 +283,62 @@ export default class Fetch {
|
|
270
283
|
return response;
|
271
284
|
}
|
272
285
|
|
286
|
+
/**
|
287
|
+
* Returns virtual server response.
|
288
|
+
*
|
289
|
+
* @returns Response.
|
290
|
+
*/
|
291
|
+
private async getVirtualServerResponse(): Promise<Response | null> {
|
292
|
+
const filePath = VirtualServerUtility.getFilepath(this.#window, this.request.url);
|
293
|
+
|
294
|
+
if (!filePath) {
|
295
|
+
return null;
|
296
|
+
}
|
297
|
+
|
298
|
+
if (this.request.method !== 'GET') {
|
299
|
+
this.#browserFrame?.page?.console.error(
|
300
|
+
`${this.request.method} ${this.request.url} 404 (Not Found)`
|
301
|
+
);
|
302
|
+
return VirtualServerUtility.getNotFoundResponse(this.#window);
|
303
|
+
}
|
304
|
+
|
305
|
+
const taskID = this.#browserFrame[PropertySymbol.asyncTaskManager].startTask();
|
306
|
+
let buffer: Buffer;
|
307
|
+
|
308
|
+
try {
|
309
|
+
const stat = await FS.promises.stat(filePath);
|
310
|
+
buffer = await FS.promises.readFile(
|
311
|
+
stat.isDirectory() ? Path.join(filePath, 'index.html') : filePath
|
312
|
+
);
|
313
|
+
} catch (error) {
|
314
|
+
this.#browserFrame?.page?.console.error(
|
315
|
+
`${this.request.method} ${this.request.url} 404 (Not Found)`
|
316
|
+
);
|
317
|
+
|
318
|
+
this.#browserFrame[PropertySymbol.asyncTaskManager].endTask(taskID);
|
319
|
+
|
320
|
+
return VirtualServerUtility.getNotFoundResponse(this.#window);
|
321
|
+
}
|
322
|
+
|
323
|
+
this.#browserFrame[PropertySymbol.asyncTaskManager].endTask(taskID);
|
324
|
+
|
325
|
+
const body = new this.#window.ReadableStream({
|
326
|
+
start(controller) {
|
327
|
+
setTimeout(() => {
|
328
|
+
controller.enqueue(buffer);
|
329
|
+
controller.close();
|
330
|
+
});
|
331
|
+
}
|
332
|
+
});
|
333
|
+
|
334
|
+
const response = new this.#window.Response(body);
|
335
|
+
|
336
|
+
response[PropertySymbol.buffer] = buffer;
|
337
|
+
(<string>response.url) = this.request.url;
|
338
|
+
|
339
|
+
return response;
|
340
|
+
}
|
341
|
+
|
273
342
|
/**
|
274
343
|
* Checks if the request complies with the Cross-Origin policy.
|
275
344
|
*
|
@@ -410,7 +479,17 @@ export default class Fetch {
|
|
410
479
|
})
|
411
480
|
: undefined;
|
412
481
|
this.#browserFrame[PropertySymbol.asyncTaskManager].endTask(taskID);
|
413
|
-
|
482
|
+
const returnResponse =
|
483
|
+
interceptedResponse instanceof Response ? interceptedResponse : response;
|
484
|
+
|
485
|
+
// The browser outputs errors to the console when the response is not ok.
|
486
|
+
if (returnResponse instanceof Response && !returnResponse.ok) {
|
487
|
+
this.#browserFrame?.page?.console.error(
|
488
|
+
`${this.request.method} ${this.request.url} ${returnResponse.status} (${returnResponse.statusText})`
|
489
|
+
);
|
490
|
+
}
|
491
|
+
|
492
|
+
resolve(returnResponse);
|
414
493
|
};
|
415
494
|
this.reject = (error: Error): void => {
|
416
495
|
this.#browserFrame[PropertySymbol.asyncTaskManager].endTask(taskID);
|
@@ -517,7 +596,7 @@ export default class Fetch {
|
|
517
596
|
*/
|
518
597
|
private onError(error: Error): void {
|
519
598
|
this.finalizeRequest();
|
520
|
-
this.#
|
599
|
+
this.#browserFrame?.page?.console.error(error);
|
521
600
|
this.reject(
|
522
601
|
new this.#window.DOMException(
|
523
602
|
`Failed to execute "fetch()" on "Window" with URL "${this.request.url}": ${error.message}`,
|
package/src/fetch/SyncFetch.ts
CHANGED
@@ -3,6 +3,8 @@ import * as PropertySymbol from '../PropertySymbol.js';
|
|
3
3
|
import IRequestInfo from './types/IRequestInfo.js';
|
4
4
|
import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum.js';
|
5
5
|
import URL from '../url/URL.js';
|
6
|
+
import FS from 'fs';
|
7
|
+
import Path from 'path';
|
6
8
|
import Request from './Request.js';
|
7
9
|
import IBrowserFrame from '../browser/types/IBrowserFrame.js';
|
8
10
|
import BrowserWindow from '../window/BrowserWindow.js';
|
@@ -21,6 +23,7 @@ import FetchResponseRedirectUtility from './utilities/FetchResponseRedirectUtili
|
|
21
23
|
import FetchCORSUtility from './utilities/FetchCORSUtility.js';
|
22
24
|
import Fetch from './Fetch.js';
|
23
25
|
import IFetchInterceptor from './types/IFetchInterceptor.js';
|
26
|
+
import VirtualServerUtility from './utilities/VirtualServerUtility.js';
|
24
27
|
|
25
28
|
interface ISyncHTTPResponse {
|
26
29
|
error: string;
|
@@ -96,6 +99,7 @@ export default class SyncFetch {
|
|
96
99
|
*/
|
97
100
|
public send(): ISyncResponse {
|
98
101
|
FetchRequestReferrerUtility.prepareRequest(new URL(this.#window.location.href), this.request);
|
102
|
+
|
99
103
|
const beforeRequestResponse = this.interceptor?.beforeSyncRequest
|
100
104
|
? this.interceptor.beforeSyncRequest({
|
101
105
|
request: this.request,
|
@@ -105,8 +109,15 @@ export default class SyncFetch {
|
|
105
109
|
if (typeof beforeRequestResponse === 'object') {
|
106
110
|
return beforeRequestResponse;
|
107
111
|
}
|
112
|
+
|
108
113
|
FetchRequestValidationUtility.validateSchema(this.request);
|
109
114
|
|
115
|
+
const virtualServerResponse = this.getVirtualServerResponse();
|
116
|
+
|
117
|
+
if (virtualServerResponse) {
|
118
|
+
return virtualServerResponse;
|
119
|
+
}
|
120
|
+
|
110
121
|
if (this.request.signal.aborted) {
|
111
122
|
throw new this.#window.DOMException(
|
112
123
|
'The operation was aborted.',
|
@@ -256,6 +267,47 @@ export default class SyncFetch {
|
|
256
267
|
};
|
257
268
|
}
|
258
269
|
|
270
|
+
/**
|
271
|
+
* Returns virtual server response.
|
272
|
+
*
|
273
|
+
* @returns Response.
|
274
|
+
*/
|
275
|
+
private getVirtualServerResponse(): ISyncResponse | null {
|
276
|
+
const filePath = VirtualServerUtility.getFilepath(this.#window, this.request.url);
|
277
|
+
|
278
|
+
if (!filePath) {
|
279
|
+
return null;
|
280
|
+
}
|
281
|
+
|
282
|
+
if (this.request.method !== 'GET') {
|
283
|
+
this.#browserFrame?.page?.console.error(
|
284
|
+
`${this.request.method} ${this.request.url} 404 (Not Found)`
|
285
|
+
);
|
286
|
+
return VirtualServerUtility.getNotFoundSyncResponse(this.#window);
|
287
|
+
}
|
288
|
+
|
289
|
+
let buffer: Buffer;
|
290
|
+
try {
|
291
|
+
const stat = FS.statSync(filePath);
|
292
|
+
buffer = FS.readFileSync(stat.isDirectory() ? Path.join(filePath, 'index.html') : filePath);
|
293
|
+
} catch {
|
294
|
+
this.#browserFrame?.page?.console.error(
|
295
|
+
`${this.request.method} ${this.request.url} 404 (Not Found)`
|
296
|
+
);
|
297
|
+
return VirtualServerUtility.getNotFoundSyncResponse(this.#window);
|
298
|
+
}
|
299
|
+
|
300
|
+
return {
|
301
|
+
status: 200,
|
302
|
+
statusText: '',
|
303
|
+
ok: true,
|
304
|
+
url: this.request.url,
|
305
|
+
redirected: false,
|
306
|
+
headers: new this.#window.Headers(),
|
307
|
+
body: buffer
|
308
|
+
};
|
309
|
+
}
|
310
|
+
|
259
311
|
/**
|
260
312
|
* Checks if the request complies with the Cross-Origin policy.
|
261
313
|
*
|
@@ -443,7 +495,14 @@ export default class SyncFetch {
|
|
443
495
|
request: this.request
|
444
496
|
})
|
445
497
|
: undefined;
|
446
|
-
|
498
|
+
const returnResponse =
|
499
|
+
typeof interceptedResponse === 'object' ? interceptedResponse : redirectedResponse;
|
500
|
+
if (!returnResponse.ok) {
|
501
|
+
this.#browserFrame?.page?.console.error(
|
502
|
+
`${this.request.method} ${this.request.url} ${returnResponse.status} (${returnResponse.statusText})`
|
503
|
+
);
|
504
|
+
}
|
505
|
+
return returnResponse;
|
447
506
|
}
|
448
507
|
|
449
508
|
/**
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import BrowserWindow from '../../window/BrowserWindow.js';
|
2
|
+
import WindowBrowserContext from '../../window/WindowBrowserContext.js';
|
3
|
+
import Path from 'path';
|
4
|
+
import Response from '../Response.js';
|
5
|
+
import ISyncResponse from '../types/ISyncResponse.js';
|
6
|
+
|
7
|
+
const NOT_FOUND_HTML =
|
8
|
+
'<html><head><title>Happy DOM Virtual Server - 404 Not Found</title></head><body><h1>Happy DOM Virtual Server - 404 Not Found</h1></body></html>';
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Virtual server utility.
|
12
|
+
*/
|
13
|
+
export default class VirtualServerUtility {
|
14
|
+
/**
|
15
|
+
* Returns the filesystem path for a request URL if it matches a virtual server.
|
16
|
+
*
|
17
|
+
* @param window Window.
|
18
|
+
* @param requestURL Request URL.
|
19
|
+
*/
|
20
|
+
public static getFilepath(window: BrowserWindow, requestURL: string): string | null {
|
21
|
+
const browserSettings = new WindowBrowserContext(window).getSettings();
|
22
|
+
if (!browserSettings || !browserSettings.fetch.virtualServers) {
|
23
|
+
return null;
|
24
|
+
}
|
25
|
+
for (const virtualServer of browserSettings.fetch.virtualServers) {
|
26
|
+
let baseURL: URL;
|
27
|
+
if (typeof virtualServer.url === 'string') {
|
28
|
+
const url = new URL(
|
29
|
+
virtualServer.url[virtualServer.url.length - 1] === '/'
|
30
|
+
? virtualServer.url.slice(0, -1)
|
31
|
+
: virtualServer.url,
|
32
|
+
window.location.origin
|
33
|
+
);
|
34
|
+
if (requestURL.startsWith(url.href)) {
|
35
|
+
baseURL = url;
|
36
|
+
}
|
37
|
+
} else if (virtualServer.url instanceof RegExp) {
|
38
|
+
const match = requestURL.match(virtualServer.url);
|
39
|
+
if (match) {
|
40
|
+
baseURL = new URL(
|
41
|
+
match[0][match[0].length - 1] === '/' ? match[0].slice(0, -1) : match[0],
|
42
|
+
window.location.origin
|
43
|
+
);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
if (baseURL) {
|
47
|
+
const path = requestURL.slice(baseURL.href.length).split('?')[0].split('#')[0];
|
48
|
+
return Path.join(Path.resolve(virtualServer.directory), path.replaceAll('/', Path.sep));
|
49
|
+
}
|
50
|
+
}
|
51
|
+
return null;
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Returns a 404 response.
|
56
|
+
*
|
57
|
+
* @param window Window.
|
58
|
+
* @returns 404 response.
|
59
|
+
*/
|
60
|
+
public static getNotFoundResponse(window: BrowserWindow): Response {
|
61
|
+
return new window.Response(NOT_FOUND_HTML, {
|
62
|
+
status: 404,
|
63
|
+
statusText: 'Not Found',
|
64
|
+
headers: {
|
65
|
+
'Content-Type': 'text/html'
|
66
|
+
}
|
67
|
+
});
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Returns a 404 response.
|
72
|
+
*
|
73
|
+
* @param window Window.
|
74
|
+
* @returns 404 response.
|
75
|
+
*/
|
76
|
+
public static getNotFoundSyncResponse(window: BrowserWindow): ISyncResponse {
|
77
|
+
return <ISyncResponse>{
|
78
|
+
status: 404,
|
79
|
+
statusText: 'Not Found',
|
80
|
+
ok: false,
|
81
|
+
url: null,
|
82
|
+
redirected: false,
|
83
|
+
headers: new window.Headers({
|
84
|
+
'Content-Type': 'text/html'
|
85
|
+
}),
|
86
|
+
body: Buffer.from(NOT_FOUND_HTML)
|
87
|
+
};
|
88
|
+
}
|
89
|
+
}
|
package/src/index.ts
CHANGED
@@ -16,6 +16,7 @@ import VirtualConsole from './console/VirtualConsole.js';
|
|
16
16
|
import VirtualConsolePrinter from './console/VirtualConsolePrinter.js';
|
17
17
|
import VirtualConsoleLogLevelEnum from './console/enums/VirtualConsoleLogLevelEnum.js';
|
18
18
|
import VirtualConsoleLogTypeEnum from './console/enums/VirtualConsoleLogTypeEnum.js';
|
19
|
+
import CookieSameSiteEnum from './cookie/enums/CookieSameSiteEnum.js';
|
19
20
|
import CSSRule from './css/CSSRule.js';
|
20
21
|
import CSSStyleSheet from './css/CSSStyleSheet.js';
|
21
22
|
import CSSStyleDeclaration from './css/declaration/CSSStyleDeclaration.js';
|
@@ -28,6 +29,8 @@ import CSSStyleRule from './css/rules/CSSStyleRule.js';
|
|
28
29
|
import CSSSupportsRule from './css/rules/CSSSupportsRule.js';
|
29
30
|
import CustomElementRegistry from './custom-element/CustomElementRegistry.js';
|
30
31
|
import DOMParser from './dom-parser/DOMParser.js';
|
32
|
+
import DOMRect from './dom/DOMRect.js';
|
33
|
+
import DOMRectReadOnly from './dom/DOMRectReadOnly.js';
|
31
34
|
import DataTransfer from './event/DataTransfer.js';
|
32
35
|
import DataTransferItem from './event/DataTransferItem.js';
|
33
36
|
import DataTransferItemList from './event/DataTransferItemList.js';
|
@@ -74,8 +77,6 @@ import Comment from './nodes/comment/Comment.js';
|
|
74
77
|
import DocumentFragment from './nodes/document-fragment/DocumentFragment.js';
|
75
78
|
import DocumentType from './nodes/document-type/DocumentType.js';
|
76
79
|
import Document from './nodes/document/Document.js';
|
77
|
-
import DOMRect from './dom/DOMRect.js';
|
78
|
-
import DOMRectReadOnly from './dom/DOMRectReadOnly.js';
|
79
80
|
import Element from './nodes/element/Element.js';
|
80
81
|
import HTMLCollection from './nodes/element/HTMLCollection.js';
|
81
82
|
import HTMLAnchorElement from './nodes/html-anchor-element/HTMLAnchorElement.js';
|
@@ -188,10 +189,12 @@ import type IBrowserFrame from './browser/types/IBrowserFrame.js';
|
|
188
189
|
import type IBrowserPage from './browser/types/IBrowserPage.js';
|
189
190
|
import type IBrowserSettings from './browser/types/IBrowserSettings.js';
|
190
191
|
import type IOptionalBrowserSettings from './browser/types/IOptionalBrowserSettings.js';
|
192
|
+
import type ICookie from './cookie/ICookie.js';
|
193
|
+
import type IOptionalCookie from './cookie/IOptionalCookie.js';
|
191
194
|
import type IEventInit from './event/IEventInit.js';
|
192
|
-
import type TEventListener from './event/TEventListener.js';
|
193
195
|
import type ITouchInit from './event/ITouchInit.js';
|
194
196
|
import type IUIEventInit from './event/IUIEventInit.js';
|
197
|
+
import type TEventListener from './event/TEventListener.js';
|
195
198
|
import type IAnimationEventInit from './event/events/IAnimationEventInit.js';
|
196
199
|
import type IClipboardEventInit from './event/events/IClipboardEventInit.js';
|
197
200
|
import type ICustomEventInit from './event/events/ICustomEventInit.js';
|
@@ -206,10 +209,9 @@ import type IProgressEventInit from './event/events/IProgressEventInit.js';
|
|
206
209
|
import type ISubmitEventInit from './event/events/ISubmitEventInit.js';
|
207
210
|
import type ITouchEventInit from './event/events/ITouchEventInit.js';
|
208
211
|
import type IWheelEventInit from './event/events/IWheelEventInit.js';
|
212
|
+
import type IVirtualServer from './fetch/types/IVirtualServer.js';
|
209
213
|
|
210
214
|
export type {
|
211
|
-
IFetchInterceptor,
|
212
|
-
ISyncResponse,
|
213
215
|
IAnimationEventInit,
|
214
216
|
IBrowser,
|
215
217
|
IBrowserContext,
|
@@ -217,10 +219,11 @@ export type {
|
|
217
219
|
IBrowserPage,
|
218
220
|
IBrowserSettings,
|
219
221
|
IClipboardEventInit,
|
222
|
+
ICookie,
|
220
223
|
ICustomEventInit,
|
221
224
|
IErrorEventInit,
|
222
225
|
IEventInit,
|
223
|
-
|
226
|
+
IFetchInterceptor,
|
224
227
|
IFocusEventInit,
|
225
228
|
IHashChangeEventInit,
|
226
229
|
IInputEventInit,
|
@@ -228,12 +231,16 @@ export type {
|
|
228
231
|
IMediaQueryListInit,
|
229
232
|
IMouseEventInit,
|
230
233
|
IOptionalBrowserSettings,
|
234
|
+
IOptionalCookie,
|
231
235
|
IProgressEventInit,
|
232
236
|
ISubmitEventInit,
|
237
|
+
ISyncResponse,
|
233
238
|
ITouchEventInit,
|
234
239
|
ITouchInit,
|
235
240
|
IUIEventInit,
|
236
|
-
|
241
|
+
IVirtualServer,
|
242
|
+
IWheelEventInit,
|
243
|
+
TEventListener
|
237
244
|
};
|
238
245
|
|
239
246
|
export {
|
@@ -253,6 +260,7 @@ export {
|
|
253
260
|
ClipboardEvent,
|
254
261
|
ClipboardItem,
|
255
262
|
Comment,
|
263
|
+
CookieSameSiteEnum,
|
256
264
|
CSSContainerRule,
|
257
265
|
CSSFontFaceRule,
|
258
266
|
CSSKeyframeRule,
|