@@ -5,6 +5,7 @@ import * as https from "https";
5
5
import * as net from "net" ;
6
6
import * as path from "path" ;
7
7
import * as querystring from "querystring" ;
8
+ import { Readable } from "stream" ;
8
9
import * as tls from "tls" ;
9
10
import * as url from "url" ;
10
11
import * as util from "util" ;
@@ -67,6 +68,8 @@ import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from
67
68
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService" ;
68
69
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api" ;
69
70
71
+ const tarFs = localRequire < typeof import ( "tar-fs" ) > ( "tar-fs/index" ) ;
72
+
70
73
export enum HttpCode {
71
74
Ok = 200 ,
72
75
Redirect = 302 ,
@@ -89,7 +92,9 @@ export interface Response {
89
92
content ?: string | Buffer ;
90
93
filePath ?: string ;
91
94
headers ?: http . OutgoingHttpHeaders ;
95
+ mime ?: string ;
92
96
redirect ?: string ;
97
+ stream ?: Readable ;
93
98
}
94
99
95
100
export interface LoginPayload {
@@ -185,11 +190,21 @@ export abstract class Server {
185
190
) : Promise < Response > ;
186
191
187
192
protected async getResource ( ...parts : string [ ] ) : Promise < Response > {
193
+ const filePath = this . ensureAuthorizedFilePath ( ...parts ) ;
194
+ return { content : await util . promisify ( fs . readFile ) ( filePath ) , filePath } ;
195
+ }
196
+
197
+ protected async getTarredResource ( ...parts : string [ ] ) : Promise < Response > {
198
+ const filePath = this . ensureAuthorizedFilePath ( ...parts ) ;
199
+ return { stream : tarFs . pack ( filePath ) , filePath, mime : "application/tar" } ;
200
+ }
201
+
202
+ protected ensureAuthorizedFilePath ( ...parts : string [ ] ) : string {
188
203
const filePath = path . join ( ...parts ) ;
189
204
if ( ! this . isAllowedRequestPath ( filePath ) ) {
190
205
throw new HttpError ( "Unauthorized" , HttpCode . Unauthorized ) ;
191
206
}
192
- return { content : await util . promisify ( fs . readFile ) ( filePath ) , filePath } ;
207
+ return filePath ;
193
208
}
194
209
195
210
protected withBase ( request : http . IncomingMessage , path : string ) : string {
@@ -211,13 +226,21 @@ export abstract class Server {
211
226
const parsedUrl = request . url ? url . parse ( request . url , true ) : { query : { } } ;
212
227
const payload = await this . preHandleRequest ( request , parsedUrl ) ;
213
228
response . writeHead ( payload . redirect ? HttpCode . Redirect : payload . code || HttpCode . Ok , {
214
- "Content-Type" : getMediaMime ( payload . filePath ) ,
229
+ "Content-Type" : payload . mime || getMediaMime ( payload . filePath ) ,
215
230
...( payload . redirect ? { Location : this . withBase ( request , payload . redirect ) } : { } ) ,
216
231
...( request . headers [ "service-worker" ] ? { "Service-Worker-Allowed" : this . options . basePath || "/" } : { } ) ,
217
232
...( payload . cache ? { "Cache-Control" : "public, max-age=31536000" } : { } ) ,
218
233
...payload . headers ,
219
234
} ) ;
220
- response . end ( payload . content ) ;
235
+ if ( payload . stream ) {
236
+ payload . stream . on ( "error" , ( error : NodeJS . ErrnoException ) => {
237
+ response . writeHead ( error . code === "ENOENT" ? HttpCode . NotFound : HttpCode . ServerError ) ;
238
+ response . end ( error . message ) ;
239
+ } ) ;
240
+ payload . stream . pipe ( response ) ;
241
+ } else {
242
+ response . end ( payload . content ) ;
243
+ }
221
244
} catch ( error ) {
222
245
if ( error . code === "ENOENT" || error . code === "EISDIR" ) {
223
246
error = new HttpError ( "Not found" , HttpCode . NotFound ) ;
@@ -484,6 +507,11 @@ export class MainServer extends Server {
484
507
return this . getResource ( parsedUrl . query . path ) ;
485
508
}
486
509
break ;
510
+ case "/tar" :
511
+ if ( typeof parsedUrl . query . path === "string" ) {
512
+ return this . getTarredResource ( parsedUrl . query . path ) ;
513
+ }
514
+ break ;
487
515
case "/webview" :
488
516
if ( requestPath . indexOf ( "/vscode-resource" ) === 0 ) {
489
517
return this . getResource ( requestPath . replace ( / ^ \/ v s c o d e - r e s o u r c e / , "" ) ) ;
0 commit comments