33 * SPDX-License-Identifier: Apache-2.0
44 */
55
6- import * as fs from 'fs' // eslint-disable-line no-restricted-imports
7- import * as http from 'http'
8- import * as https from 'https'
9- import * as stream from 'stream'
10- import got , { Response , RequestError , CancelError } from 'got'
11- import urlToOptions from 'got/dist/source/core/utils/url-to-options'
12- import Request from 'got/dist/source/core'
136import { VSCODE_EXTENSION_ID } from '../extensions'
147import { getLogger , Logger } from '../logger'
158import { ResourceFetcher } from './resourcefetcher'
16- import { Timeout , CancellationError , CancelEvent } from '../utilities/timeoutUtils'
17- import { isCloud9 } from '../extensionUtilities'
18- import { Headers } from 'got/dist/source/core'
9+ import { Timeout , CancelEvent } from '../utilities/timeoutUtils'
10+ import request , { RequestError } from '../request'
1911import { withRetries } from '../utilities/functionUtils'
2012
21- // XXX: patched Got module for compatability with older VS Code versions (e.g. Cloud9)
22- // `got` has also deprecated `urlToOptions`
23- const patchedGot = got . extend ( {
24- request : ( url , options , callback ) => {
25- if ( url . protocol === 'https:' ) {
26- return https . request ( { ...options , ...urlToOptions ( url ) } , callback )
27- }
28- return http . request ( { ...options , ...urlToOptions ( url ) } , callback )
29- } ,
30- } )
31-
32- /** Promise that resolves/rejects when all streams close. Can also access streams directly. */
33- type FetcherResult = Promise < void > & {
34- /** Download stream piped to `fsStream`. */
35- requestStream : Request // `got` doesn't add the correct types to 'on' for some reason
36- /** Stream writing to the file system. */
37- fsStream : fs . WriteStream
38- }
39-
4013type RequestHeaders = { eTag ?: string ; gZip ?: boolean }
4114
4215export class HttpResourceFetcher implements ResourceFetcher {
@@ -66,20 +39,8 @@ export class HttpResourceFetcher implements ResourceFetcher {
6639 *
6740 * @param pipeLocation Optionally pipe the download to a file system location
6841 */
69- public get ( ) : Promise < string | undefined >
70- public get ( pipeLocation : string ) : FetcherResult
71- public get ( pipeLocation ?: string ) : Promise < string | undefined > | FetcherResult {
42+ public get ( ) : Promise < string | undefined > {
7243 this . logger . verbose ( `downloading: ${ this . logText ( ) } ` )
73-
74- if ( pipeLocation ) {
75- const result = this . pipeGetRequest ( pipeLocation , this . params . timeout )
76- result . fsStream . on ( 'exit' , ( ) => {
77- this . logger . verbose ( `downloaded: ${ this . logText ( ) } ` )
78- } )
79-
80- return result
81- }
82-
8344 return this . downloadRequest ( )
8445 }
8546
@@ -95,15 +56,15 @@ export class HttpResourceFetcher implements ResourceFetcher {
9556 public async getNewETagContent ( eTag ?: string ) : Promise < { content ?: string ; eTag : string } > {
9657 const response = await this . getResponseFromGetRequest ( this . params . timeout , { eTag, gZip : true } )
9758
98- const eTagResponse = response . headers . etag
59+ const eTagResponse = response . headers . get ( ' etag' )
9960 if ( ! eTagResponse ) {
10061 throw new Error ( `This URL does not support E-Tags. Cannot use this function for: ${ this . url . toString ( ) } ` )
10162 }
10263
10364 // NOTE: Even with use of `gzip` encoding header, the response content is uncompressed.
10465 // Most likely due to the http request library uncompressing it for us.
105- let contents : string | undefined = response . body . toString ( )
106- if ( response . statusCode === 304 ) {
66+ let contents : string | undefined = await response . text ( )
67+ if ( response . status === 304 ) {
10768 // Explanation: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match
10869 contents = undefined
10970 this . logger . verbose ( `E-Tag, ${ eTagResponse } , matched. No content downloaded from: ${ this . url } ` )
@@ -120,7 +81,8 @@ export class HttpResourceFetcher implements ResourceFetcher {
12081 private async downloadRequest ( ) : Promise < string | undefined > {
12182 try {
12283 // HACK(?): receiving JSON as a string without `toString` makes it so we can't deserialize later
123- const contents = ( await this . getResponseFromGetRequest ( this . params . timeout ) ) . body . toString ( )
84+ const resp = await this . getResponseFromGetRequest ( this . params . timeout )
85+ const contents = ( await resp . text ( ) ) . toString ( )
12486 if ( this . params . onSuccess ) {
12587 this . params . onSuccess ( contents )
12688 }
@@ -129,10 +91,10 @@ export class HttpResourceFetcher implements ResourceFetcher {
12991
13092 return contents
13193 } catch ( err ) {
132- const error = err as CancelError | RequestError
94+ const error = err as RequestError
13395 this . logger . verbose (
13496 `Error downloading ${ this . logText ( ) } : %s` ,
135- error . message ?? error . code ?? error . response ?. statusMessage ?? error . response ?. statusCode
97+ error . message ?? error . code ?? error . response . statusText ?? error . response . status
13698 )
13799 return undefined
138100 }
@@ -146,56 +108,30 @@ export class HttpResourceFetcher implements ResourceFetcher {
146108 getLogger ( ) . debug ( `Download for "${ this . logText ( ) } " ${ event . agent === 'user' ? 'cancelled' : 'timed out' } ` )
147109 }
148110
149- // TODO: make pipeLocation a vscode.Uri
150- private pipeGetRequest ( pipeLocation : string , timeout ?: Timeout ) : FetcherResult {
151- const requester = isCloud9 ( ) ? patchedGot : got
152- const requestStream = requester . stream ( this . url , { headers : this . buildRequestHeaders ( ) } )
153- const fsStream = fs . createWriteStream ( pipeLocation )
154-
155- const done = new Promise < void > ( ( resolve , reject ) => {
156- const pipe = stream . pipeline ( requestStream , fsStream , ( err ) => {
157- if ( err instanceof RequestError ) {
158- return reject ( Object . assign ( new Error ( 'Failed to download file' ) , { code : err . code } ) )
159- }
160- err ? reject ( err ) : resolve ( )
161- } )
162-
163- const cancelListener = timeout ?. token . onCancellationRequested ( ( event ) => {
164- this . logCancellation ( event )
165- pipe . destroy ( new CancellationError ( event . agent ) )
166- } )
167-
168- pipe . on ( 'close' , ( ) => cancelListener ?. dispose ( ) )
169- } )
170-
171- return Object . assign ( done , { requestStream, fsStream } )
172- }
173-
174- private async getResponseFromGetRequest ( timeout ?: Timeout , headers ?: RequestHeaders ) : Promise < Response < string > > {
175- const requester = isCloud9 ( ) ? patchedGot : got
176- const promise = requester ( this . url , {
111+ private async getResponseFromGetRequest ( timeout ?: Timeout , headers ?: RequestHeaders ) : Promise < Response > {
112+ const req = request . fetch ( 'GET' , this . url , {
177113 headers : this . buildRequestHeaders ( headers ) ,
178114 } )
179115
180116 const cancelListener = timeout ?. token . onCancellationRequested ( ( event ) => {
181117 this . logCancellation ( event )
182- promise . cancel ( new CancellationError ( event . agent ) . message )
118+ req . cancel ( )
183119 } )
184120
185- return promise . finally ( ( ) => cancelListener ?. dispose ( ) )
121+ return req . response . finally ( ( ) => cancelListener ?. dispose ( ) )
186122 }
187123
188124 private buildRequestHeaders ( requestHeaders ?: RequestHeaders ) : Headers {
189- const headers : Headers = { }
125+ const headers = new Headers ( )
190126
191- headers [ 'User-Agent' ] = VSCODE_EXTENSION_ID . awstoolkit
127+ headers . set ( 'User-Agent' , VSCODE_EXTENSION_ID . awstoolkit )
192128
193129 if ( requestHeaders ?. eTag !== undefined ) {
194- headers [ 'If-None-Match' ] = requestHeaders . eTag
130+ headers . set ( 'If-None-Match' , requestHeaders . eTag )
195131 }
196132
197133 if ( requestHeaders ?. gZip ) {
198- headers [ 'Accept-Encoding' ] = 'gzip'
134+ headers . set ( 'Accept-Encoding' , 'gzip' )
199135 }
200136
201137 return headers
0 commit comments