Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3374,7 +3374,7 @@
"@microsoft/vscode-azext-azureutils": "^4.0.0",
"@microsoft/vscode-azext-utils": "^4.0.4",
"@microsoft/vscode-container-client": "^0.5.3",
"@microsoft/vscode-docker-registries": "^0.4.1",
"@microsoft/vscode-docker-registries": "^0.4.2",
"@microsoft/vscode-processutils": "^0.2.1",
"dayjs": "^1.11.7",
"dockerfile-language-server-nodejs": "^0.15.0",
Expand Down
4 changes: 1 addition & 3 deletions src/tree/images/imageChecker/OutdatedImageChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,8 @@ export class OutdatedImageChecker {
private async getLatestImageDigest(registry: ImageRegistry, repo: string, tag: string): Promise<string> {
const manifestResponse = await httpRequest(`${registry.baseUrl}/${repo}/manifests/${tag}`, this.defaultRequestOptions, async (request) => {
if (registry.signRequest) {
return registry.signRequest(request, `repository:library/${repo}:pull`);
await registry.signRequest(request, `repository:library/${repo}:pull`);
}

return request;
});

return manifestResponse.headers.get('docker-content-digest') as string;
Expand Down
10 changes: 5 additions & 5 deletions src/tree/images/imageChecker/registries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import { ImageNameInfo } from '@microsoft/vscode-container-client';
import { URL } from 'url';
import { ociClientId } from '../../../constants';
import { HttpErrorResponse, IOAuthContext, RequestLike, RequestOptionsLike, bearerAuthHeader, getWwwAuthenticateContext, httpRequest } from '../../../utils/httpRequest';
import { HttpErrorResponse, IOAuthContext, RequestOptionsLike, bearerAuthHeader, getWwwAuthenticateContext, httpRequest } from '../../../utils/httpRequest';
import { NormalizedImageNameInfo } from '../NormalizedImageNameInfo';

export interface ImageRegistry {
isMatch: (imageNameInfo: ImageNameInfo) => boolean;
baseUrl: string;
signRequest?(request: RequestLike, scope: string): Promise<RequestLike>;
signRequest?(request: RequestOptionsLike, scope: string): Promise<void>;
}

let dockerHubAuthContext: IOAuthContext | undefined;
Expand All @@ -24,7 +24,7 @@ export const registries: ImageRegistry[] = [
return !!imageNameInfo.originalName && normalizedImageNameInfo.normalizedRegistry === 'docker.io' && normalizedImageNameInfo.normalizedNamespace === 'library';
},
baseUrl: 'https://registry-1.docker.io/v2/library',
signRequest: async (request: RequestLike, scope: string): Promise<RequestLike> => {
signRequest: async (request: RequestOptionsLike, scope: string): Promise<void> => {
if (!dockerHubAuthContext) {
try {
const options: RequestOptionsLike = {
Expand Down Expand Up @@ -59,8 +59,8 @@ export const registries: ImageRegistry[] = [
const tokenResponse = await httpRequest<{ token: string }>(url.toString(), authRequestOptions);
const token = (await tokenResponse.json()).token;

Comment thread
bwateratmsft marked this conversation as resolved.
request.headers.set('Authorization', bearerAuthHeader(token));
return request;
request.headers ??= {};
request.headers['Authorization'] = bearerAuthHeader(token);
}
},
{
Expand Down
20 changes: 9 additions & 11 deletions src/utils/httpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,26 @@ export const enum ErrorHandling {
export async function httpRequest<T>(
url: string,
options?: RequestOptionsLike,
signRequest?: (request: RequestLike) => Promise<RequestLike>,
signRequest?: (request: RequestOptionsLike) => Promise<void>,
errorHandling: ErrorHandling = ErrorHandling.ThrowOnError
): Promise<HttpResponse<T>> {
const requestOptions: RequestInit = options;
const requestOptions: RequestInit = { ...options, headers: { ...options?.headers } };
if (options?.form) {
// URLSearchParams is a silly way to say "it's form data"
requestOptions.body = new URLSearchParams(options.form);
}

let request = new Request(url, requestOptions ?? {});
if (!!requestOptions.body && requestOptions.duplex === undefined) {
// Node's built-in fetch implementation (via undici) requires `duplex: 'half'`
// when sending a request body in this code path, otherwise Node throws an error.
requestOptions.duplex = 'half';
}
Comment thread
bwateratmsft marked this conversation as resolved.
Outdated

if (signRequest) {
request = await signRequest(request) as Request;
await signRequest(requestOptions as RequestOptionsLike);
Comment thread
bwateratmsft marked this conversation as resolved.
}

const response = await fetch(request);
const response = await fetch(url, requestOptions);
Comment thread
bwateratmsft marked this conversation as resolved.

if (errorHandling === ErrorHandling.ReturnErrorResponse || response.ok) {
return new HttpResponse(response, url);
Expand Down Expand Up @@ -111,12 +115,6 @@ export interface RequestOptionsLike {
body?: string;
Comment thread
bwateratmsft marked this conversation as resolved.
}

export interface RequestLike {
url: string;
headers: HeadersLike;
method: string; // This is a string because node-fetch's Request defines it as such
}

export interface HeadersLike {
get(header: string): string | string[];
set(header: string, value: string): void;
Expand Down
Loading