Support Content-Length and Last-Modified for webview local resources (#125994)

Closes #125992
This commit is contained in:
Wojciech Nawrocki 2021-06-11 16:27:56 -07:00 committed by GitHub
parent 3c1fa1b286
commit 28f0fc47d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 7 deletions

View file

@ -543,6 +543,7 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
mime: result.mimeType,
data: buffer,
etag: result.etag,
mtime: result.mtime
});
}
case WebviewResourceResponse.Type.NotModified:
@ -552,6 +553,7 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
status: 304, // not modified
path: uri.path,
mime: result.mimeType,
mtime: result.mtime
});
}
case WebviewResourceResponse.Type.AccessDenied:

View file

@ -100,7 +100,9 @@ class RequestStore {
/**
* Map of requested paths to responses.
* @typedef {{ type: 'response', body: any, mime: string, etag: string | undefined, } | { type: 'not-modified', mime: string } | undefined} ResourceResponse
* @typedef {{ type: 'response', body: Uint8Array, mime: string, etag: string | undefined, mtime: number | undefined } |
* { type: 'not-modified', mime: string, mtime: number | undefined } |
* undefined} ResourceResponse
* @type {RequestStore<ResourceResponse>}
*/
const resourceRequestStore = new RequestStore();
@ -142,12 +144,12 @@ sw.addEventListener('message', async (event) => {
switch (data.status) {
case 200:
{
response = { type: 'response', body: data.data, mime: data.mime, etag: data.etag };
response = { type: 'response', body: data.data, mime: data.mime, etag: data.etag, mtime: data.mtime };
break;
}
case 304:
{
response = { type: 'not-modified', mime: data.mime };
response = { type: 'not-modified', mime: data.mime, mtime: data.mtime };
break;
}
}
@ -233,15 +235,19 @@ async function processResourceRequest(event, requestUrl) {
}
}
/** @type {Record<String, string>} */
/** @type {Record<string, string>} */
const headers = {
'Content-Type': entry.mime,
'Content-Length': entry.body.byteLength.toString(),
'Access-Control-Allow-Origin': '*',
};
if (entry.etag) {
headers['ETag'] = entry.etag;
headers['Cache-Control'] = 'no-cache';
}
if (entry.mtime) {
headers['Last-Modified'] = new Date(entry.mtime).toUTCString();
}
const response = new Response(entry.body, {
status: 200,
headers

View file

@ -22,6 +22,7 @@ export namespace WebviewResourceResponse {
constructor(
public readonly stream: VSBufferReadableStream,
public readonly etag: string | undefined,
public readonly mtime: number | undefined,
public readonly mimeType: string,
) { }
}
@ -34,6 +35,7 @@ export namespace WebviewResourceResponse {
constructor(
public readonly mimeType: string,
public readonly mtime: number | undefined,
) { }
}
@ -50,7 +52,7 @@ export async function loadLocalResource(
logService: ILogService,
token: CancellationToken,
): Promise<WebviewResourceResponse.StreamResponse> {
logService.debug(`loadLocalResource - being. requestUri=${requestUri}`);
logService.debug(`loadLocalResource - begin. requestUri=${requestUri}`);
const resourceToLoad = getResourceToLoad(requestUri, options.roots);
@ -64,14 +66,14 @@ export async function loadLocalResource(
try {
const result = await fileService.readFileStream(resourceToLoad, { etag: options.ifNoneMatch });
return new WebviewResourceResponse.StreamSuccess(result.value, result.etag, mime);
return new WebviewResourceResponse.StreamSuccess(result.value, result.etag, result.mtime, mime);
} catch (err) {
if (err instanceof FileOperationError) {
const result = err.fileOperationResult;
// NotModified status is expected and can be handled gracefully
if (result === FileOperationResult.FILE_NOT_MODIFIED_SINCE) {
return new WebviewResourceResponse.NotModified(mime);
return new WebviewResourceResponse.NotModified(mime, err.options?.mtime);
}
}