@@ -10,13 +10,8 @@ import { stripBasePath } from "./util";
1010import { ProjectControlFunction } from "@cocalc/server/projects/control" ;
1111import siteUrl from "@cocalc/database/settings/site-url" ;
1212import { parseReq } from "./parse" ;
13- import { readFile as readProjectFile } from "@cocalc/conat/files/read" ;
14- import { path_split } from "@cocalc/util/misc" ;
15- import { once } from "@cocalc/util/async-utils" ;
1613import hasAccess from "./check-for-access-to-project" ;
17- import mime from "mime-types" ;
18-
19- const DANGEROUS_CONTENT_TYPE = new Set ( [ "image/svg+xml" /*, "text/html"*/ ] ) ;
14+ import { handleFileDownload } from "./file-download" ;
2015
2116const logger = getLogger ( "proxy:handle-request" ) ;
2217
@@ -84,7 +79,6 @@ export default function init({ projectControl, isPersonal }: Options) {
8479 // TODO: parseReq is called again in getTarget so need to refactor...
8580 const { type, project_id } = parsed ;
8681 if ( type == "files" ) {
87- dbg ( "handling the request via conat file streaming" ) ;
8882 if (
8983 ! ( await hasAccess ( {
9084 project_id,
@@ -96,43 +90,7 @@ export default function init({ projectControl, isPersonal }: Options) {
9690 ) {
9791 throw Error ( `user does not have read access to project` ) ;
9892 }
99- const i = url . indexOf ( "files/" ) ;
100- const compute_server_id = req . query . id ?? 0 ;
101- let j = url . lastIndexOf ( "?" ) ;
102- if ( j == - 1 ) {
103- j = url . length ;
104- }
105- const path = decodeURIComponent ( url . slice ( i + "files/" . length , j ) ) ;
106- dbg ( "conat: get file" , { project_id, path, compute_server_id, url } ) ;
107- const fileName = path_split ( path ) . tail ;
108- const contentType = mime . lookup ( fileName ) ;
109- if (
110- req . query . download != null ||
111- DANGEROUS_CONTENT_TYPE . has ( contentType )
112- ) {
113- const fileNameEncoded = encodeURIComponent ( fileName )
114- . replace ( / [ ' ( ) ] / g, escape )
115- . replace ( / \* / g, "%2A" ) ;
116- res . setHeader (
117- "Content-disposition" ,
118- `attachment; filename*=UTF-8''${ fileNameEncoded } ` ,
119- ) ;
120- }
121- res . setHeader ( "Content-type" , contentType ) ;
122- for await ( const chunk of await readProjectFile ( {
123- project_id,
124- compute_server_id,
125- path,
126- // allow a long download time (1 hour), since files can be large and
127- // networks can be slow.
128- maxWait : 1000 * 60 * 60 ,
129- } ) ) {
130- if ( ! res . write ( chunk ) ) {
131- // backpressure -- wait for it to resolve
132- await once ( res , "drain" ) ;
133- }
134- }
135- res . end ( ) ;
93+ await handleFileDownload ( req , res , url , project_id ) ;
13694 return ;
13795 }
13896
@@ -182,8 +140,14 @@ export default function init({ projectControl, isPersonal }: Options) {
182140 await handleProxyRequest ( req , res ) ;
183141 } catch ( err ) {
184142 const msg = `WARNING: error proxying request ${ req . url } -- ${ err } ` ;
185- res . writeHead ( 426 , { "Content-Type" : "text/html" } ) ;
186- res . end ( msg ) ;
143+ try {
144+ // this will fail if handleProxyRequest already wrote a header, so we
145+ // try/catch it.
146+ res . writeHead ( 500 , { "Content-Type" : "text/html" } ) ;
147+ } catch { }
148+ try {
149+ res . end ( msg ) ;
150+ } catch { }
187151 // Not something to log as an error -- just debug; it's normal for it to happen, e.g., when
188152 // a project isn't running.
189153 logger . debug ( msg ) ;
0 commit comments