99
*/
100
async fetch(url: string): Promise<IAgentHostNetworkFetchResult> {
102
>
const host = target.hostname;
103
>
104
>
// DNS: resolve both address families so a host that only answers on one is visible.
105
>
const [dnsIpv4, dnsIpv6] = await Promise.all([
106
>
resolveDns(host, 4),
107
>
resolveDns(host, 6),
108
>
]);
109
>
110
>
// Proxy resolution (for reporting; IRequestService resolves its own proxy internally).
111
>
let proxyUrl: string | undefined;
112
>
try {
113
>
proxyUrl = await this._proxyResolver.resolveProxy(url);
114
>
} catch (err) {
115
this._logService.debug(`[AgentHost] Network diagnostics: proxy resolution for ${url} failed: ${errorMessage(err)}`);
116
}
118
>
const base = {
119
>
url,
120
>
proxyUrl,
121
>
dnsIpv4, dnsIpv6,
122
>
};
123
>
124
>
// Reachability: a GET through IRequestService, which applies VS Code's proxy,
125
>
// strictSSL, and certificate handling — the path the rest of VS Code uses.
126
>
const probeStart = Date.now();
127
>
try {
128
>
const context = await this._requestService.request({
129
>
url,
130
>
type: 'GET',
131
>
timeout: PROBE_TIMEOUT_MS,
132
>
callSite: NO_FETCH_TELEMETRY,
133
>
}, CancellationToken.None);
134
const body = (await streamToBuffer(context.stream)).toString();
135
return {
136
...base,
137
statusCode: context.res.statusCode,
139
>
durationMs: Date.now() - probeStart,
140
>
};
141
>
} catch (err) {
142
>
return {
143
>
...base,
144
>
error: errorMessage(err),
145
>
durationMs: Date.now() - probeStart,
146
>
};
147
>
}
148
>
}
149
}
150
152
>
return new Promise((resolve, reject) => {
153
>
lookup(host, { family }, (err, address) => err ? reject(err) : resolve(address));
154
>
});
155
>
}
156
158
>
const start = Date.now();
159
>
try {
160
>
const address = await withTimeout(dnsLookup(host, family), PROBE_TIMEOUT_MS);
161
>
return { address, durationMs: Date.now() - start };
162
>
} catch (err) {
163
return { durationMs: Date.now() - start, error: errorMessage(err) };
164
}
166
168
>
return new Promise<T>((resolve, reject) => {
169
>
const timer = setTimeout(() => reject(new Error(`Timed out after ${ms / 1000}s`)), ms);
170
>
promise.then(
171
>
value => { clearTimeout(timer); resolve(value); },
172
>
err => { clearTimeout(timer); reject(err); },
173
>
);
174
>
});
175
>
}
176
178
>
const seen = new Set<unknown>();
179
>
function collect(error: unknown): string {
180
>
if (seen.has(error)) {
181
return '';
182
}
184
>
if (!(error instanceof Error)) {
185
return String(error);
186
}
188
>
error.cause ? collect(error.cause) : '',
189
>
...(error instanceof AggregateError ? error.errors.map(collect) : []),
190
>
].filter(Boolean).join(', ');
191
>
return details ? `${error.message}: ${details}` : error.message;
192
>
}
193
>
return collect(error);
194
>
}