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'
19-
20- // XXX: patched Got module for compatability with older VS Code versions (e.g. Cloud9)
21- // `got` has also deprecated `urlToOptions`
22- const patchedGot = got . extend ( {
23- request : ( url , options , callback ) => {
24- if ( url . protocol === 'https:' ) {
25- return https . request ( { ...options , ...urlToOptions ( url ) } , callback )
26- }
27- return http . request ( { ...options , ...urlToOptions ( url ) } , callback )
28- } ,
29- } )
30-
31- /** Promise that resolves/rejects when all streams close. Can also access streams directly. */
32- type FetcherResult = Promise < void > & {
33- /** Download stream piped to `fsStream`. */
34- requestStream : Request // `got` doesn't add the correct types to 'on' for some reason
35- /** Stream writing to the file system. */
36- fsStream : fs . WriteStream
37- }
9+ import { Timeout , CancelEvent } from '../utilities/timeoutUtils'
10+ import request , { RequestError } from '../request'
3811
3912type RequestHeaders = { eTag ?: string ; gZip ?: boolean }
4013
@@ -65,20 +38,8 @@ export class HttpResourceFetcher implements ResourceFetcher {
6538 *
6639 * @param pipeLocation Optionally pipe the download to a file system location
6740 */
68- public get ( ) : Promise < string | undefined >
69- public get ( pipeLocation : string ) : FetcherResult
70- public get ( pipeLocation ?: string ) : Promise < string | undefined > | FetcherResult {
41+ public get ( ) : Promise < string | undefined > {
7142 this . logger . verbose ( `downloading: ${ this . logText ( ) } ` )
72-
73- if ( pipeLocation ) {
74- const result = this . pipeGetRequest ( pipeLocation , this . params . timeout )
75- result . fsStream . on ( 'exit' , ( ) => {
76- this . logger . verbose ( `downloaded: ${ this . logText ( ) } ` )
77- } )
78-
79- return result
80- }
81-
8243 return this . downloadRequest ( )
8344 }
8445
@@ -94,15 +55,15 @@ export class HttpResourceFetcher implements ResourceFetcher {
9455 public async getNewETagContent ( eTag ?: string ) : Promise < { content ?: string ; eTag : string } > {
9556 const response = await this . getResponseFromGetRequest ( this . params . timeout , { eTag, gZip : true } )
9657
97- const eTagResponse = response . headers . etag
58+ const eTagResponse = response . headers . get ( ' etag' )
9859 if ( ! eTagResponse ) {
9960 throw new Error ( `This URL does not support E-Tags. Cannot use this function for: ${ this . url . toString ( ) } ` )
10061 }
10162
10263 // NOTE: Even with use of `gzip` encoding header, the response content is uncompressed.
10364 // Most likely due to the http request library uncompressing it for us.
104- let contents : string | undefined = response . body . toString ( )
105- if ( response . statusCode === 304 ) {
65+ let contents : string | undefined = await response . text ( )
66+ if ( response . status === 304 ) {
10667 // Explanation: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match
10768 contents = undefined
10869 this . logger . verbose ( `E-Tag, ${ eTagResponse } , matched. No content downloaded from: ${ this . url } ` )
@@ -119,7 +80,8 @@ export class HttpResourceFetcher implements ResourceFetcher {
11980 private async downloadRequest ( ) : Promise < string | undefined > {
12081 try {
12182 // HACK(?): receiving JSON as a string without `toString` makes it so we can't deserialize later
122- const contents = ( await this . getResponseFromGetRequest ( this . params . timeout ) ) . body . toString ( )
83+ const resp = await this . getResponseFromGetRequest ( this . params . timeout )
84+ const contents = ( await resp . text ( ) ) . toString ( )
12385 if ( this . params . onSuccess ) {
12486 this . params . onSuccess ( contents )
12587 }
@@ -128,10 +90,10 @@ export class HttpResourceFetcher implements ResourceFetcher {
12890
12991 return contents
13092 } catch ( err ) {
131- const error = err as CancelError | RequestError
93+ const error = err as RequestError
13294 this . logger . verbose (
13395 `Error downloading ${ this . logText ( ) } : %s` ,
134- error . message ?? error . code ?? error . response ?. statusMessage ?? error . response ?. statusCode
96+ error . message ?? error . code ?? error . response . statusText ?? error . response . status
13597 )
13698 return undefined
13799 }
@@ -145,56 +107,30 @@ export class HttpResourceFetcher implements ResourceFetcher {
145107 getLogger ( ) . debug ( `Download for "${ this . logText ( ) } " ${ event . agent === 'user' ? 'cancelled' : 'timed out' } ` )
146108 }
147109
148- // TODO: make pipeLocation a vscode.Uri
149- private pipeGetRequest ( pipeLocation : string , timeout ?: Timeout ) : FetcherResult {
150- const requester = isCloud9 ( ) ? patchedGot : got
151- const requestStream = requester . stream ( this . url , { headers : this . buildRequestHeaders ( ) } )
152- const fsStream = fs . createWriteStream ( pipeLocation )
153-
154- const done = new Promise < void > ( ( resolve , reject ) => {
155- const pipe = stream . pipeline ( requestStream , fsStream , ( err ) => {
156- if ( err instanceof RequestError ) {
157- return reject ( Object . assign ( new Error ( 'Failed to download file' ) , { code : err . code } ) )
158- }
159- err ? reject ( err ) : resolve ( )
160- } )
161-
162- const cancelListener = timeout ?. token . onCancellationRequested ( ( event ) => {
163- this . logCancellation ( event )
164- pipe . destroy ( new CancellationError ( event . agent ) )
165- } )
166-
167- pipe . on ( 'close' , ( ) => cancelListener ?. dispose ( ) )
168- } )
169-
170- return Object . assign ( done , { requestStream, fsStream } )
171- }
172-
173- private async getResponseFromGetRequest ( timeout ?: Timeout , headers ?: RequestHeaders ) : Promise < Response < string > > {
174- const requester = isCloud9 ( ) ? patchedGot : got
175- const promise = requester ( this . url , {
110+ private async getResponseFromGetRequest ( timeout ?: Timeout , headers ?: RequestHeaders ) : Promise < Response > {
111+ const req = request . fetch ( 'GET' , this . url , {
176112 headers : this . buildRequestHeaders ( headers ) ,
177113 } )
178114
179115 const cancelListener = timeout ?. token . onCancellationRequested ( ( event ) => {
180116 this . logCancellation ( event )
181- promise . cancel ( new CancellationError ( event . agent ) . message )
117+ req . cancel ( )
182118 } )
183119
184- return promise . finally ( ( ) => cancelListener ?. dispose ( ) )
120+ return req . response . finally ( ( ) => cancelListener ?. dispose ( ) )
185121 }
186122
187123 private buildRequestHeaders ( requestHeaders ?: RequestHeaders ) : Headers {
188- const headers : Headers = { }
124+ const headers = new Headers ( )
189125
190- headers [ 'User-Agent' ] = VSCODE_EXTENSION_ID . awstoolkit
126+ headers . set ( 'User-Agent' , VSCODE_EXTENSION_ID . awstoolkit )
191127
192128 if ( requestHeaders ?. eTag !== undefined ) {
193- headers [ 'If-None-Match' ] = requestHeaders . eTag
129+ headers . set ( 'If-None-Match' , requestHeaders . eTag )
194130 }
195131
196132 if ( requestHeaders ?. gZip ) {
197- headers [ 'Accept-Encoding' ] = 'gzip'
133+ headers . set ( 'Accept-Encoding' , 'gzip' )
198134 }
199135
200136 return headers
0 commit comments