@@ -10,13 +10,8 @@ import { stripBasePath } from "./util";
10
10
import { ProjectControlFunction } from "@cocalc/server/projects/control" ;
11
11
import siteUrl from "@cocalc/database/settings/site-url" ;
12
12
import { 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" ;
16
13
import 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" ;
20
15
21
16
const logger = getLogger ( "proxy:handle-request" ) ;
22
17
@@ -84,7 +79,6 @@ export default function init({ projectControl, isPersonal }: Options) {
84
79
// TODO: parseReq is called again in getTarget so need to refactor...
85
80
const { type, project_id } = parsed ;
86
81
if ( type == "files" ) {
87
- dbg ( "handling the request via conat file streaming" ) ;
88
82
if (
89
83
! ( await hasAccess ( {
90
84
project_id,
@@ -96,43 +90,7 @@ export default function init({ projectControl, isPersonal }: Options) {
96
90
) {
97
91
throw Error ( `user does not have read access to project` ) ;
98
92
}
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 ) ;
136
94
return ;
137
95
}
138
96
@@ -182,8 +140,14 @@ export default function init({ projectControl, isPersonal }: Options) {
182
140
await handleProxyRequest ( req , res ) ;
183
141
} catch ( err ) {
184
142
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 { }
187
151
// Not something to log as an error -- just debug; it's normal for it to happen, e.g., when
188
152
// a project isn't running.
189
153
logger . debug ( msg ) ;
0 commit comments