11import { type EmulatorCDROM } from "../src/emulator/emulator-common" ;
22
3+ type CDROMSpec = {
4+ srcUrl : string ;
5+ totalSize ?: number ;
6+ } ;
7+
38export async function handleRequest ( path : string , method : string ) {
49 const pathPieces = path . split ( "/" ) ;
5- let srcUrl ;
10+ let specStr ;
611 try {
7- srcUrl = atob ( pathPieces [ 2 ] ) ;
12+ specStr = atob ( pathPieces [ 2 ] ) ;
813 } catch ( e ) {
9- return errorResponse ( "Malformed CD-ROM src URL : " + pathPieces [ 2 ] ) ;
14+ return errorResponse ( "Malformed CD-ROM spec : " + pathPieces [ 2 ] ) ;
1015 }
1116
12- if ( ! isValidSrcUrl ( srcUrl ) ) {
13- return errorResponse ( "Unexpected CD-ROM src URL: " + srcUrl ) ;
17+ let spec : CDROMSpec ;
18+ if ( specStr . startsWith ( "{" ) ) {
19+ try {
20+ spec = JSON . parse ( specStr ) ;
21+ } catch ( e ) {
22+ return errorResponse ( "Malformed CD-ROM spec: " + specStr ) ;
23+ }
24+ } else {
25+ // Simple spec, just a URL.
26+ spec = { srcUrl : specStr } ;
27+ }
28+
29+ if ( ! isValidSrcUrl ( spec . srcUrl ) ) {
30+ return errorResponse ( "Unexpected CD-ROM src URL: " + spec . srcUrl ) ;
1431 }
1532
1633 if ( method === "GET" ) {
17- return await handleGET ( pathPieces , srcUrl ) ;
34+ return await handleGET ( pathPieces , spec ) ;
1835 }
1936 if ( method === "PUT" ) {
20- return await handlePUT ( srcUrl ) ;
37+ return await handlePUT ( spec . srcUrl ) ;
2138 }
2239
2340 return errorResponse ( "Method not allowed" , 405 ) ;
@@ -56,7 +73,7 @@ export function isValidSrcUrl(srcUrl: string) {
5673 return false ;
5774}
5875
59- async function handleGET ( pathPieces : string [ ] , srcUrl : string ) {
76+ async function handleGET ( pathPieces : string [ ] , spec : CDROMSpec ) {
6077 const chunkMatch = / ( \d + ) - ( \d + ) .c h u n k $ / . exec ( pathPieces [ 3 ] ) ;
6178 if ( ! chunkMatch ) {
6279 return errorResponse ( "Malformed CD-ROM src chunk: " + pathPieces [ 3 ] ) ;
@@ -69,7 +86,7 @@ async function handleGET(pathPieces: string[], srcUrl: string) {
6986 for ( let retry = 0 ; retry < 3 ; retry ++ ) {
7087 try {
7188 const { chunk, contentLength} = await fetchChunk (
72- srcUrl ,
89+ spec ,
7390 chunkStart ,
7491 chunkEnd
7592 ) ;
@@ -90,7 +107,7 @@ async function handleGET(pathPieces: string[], srcUrl: string) {
90107 }
91108
92109 console . warn ( "CD-ROM fetch failed" , {
93- srcUrl ,
110+ ... spec ,
94111 chunkStart,
95112 chunkEnd,
96113 chunkFetchError,
@@ -156,18 +173,29 @@ async function handlePUT(srcUrl: string) {
156173}
157174
158175async function fetchChunk (
159- srcUrl : string ,
176+ spec : CDROMSpec ,
160177 chunkStart : number ,
161178 chunkEnd : number
162179) {
163- const srcRes = await fetch ( srcUrl , {
180+ // Don't allow Cloudflare to cache requests in large files, since it will attempt
181+ // to read the entire file (as opposed to just the range that we requested).
182+ const isLargeFile =
183+ spec . totalSize !== undefined && spec . totalSize > 250 * 1024 * 1024 ;
184+ const cacheOptions : Partial < RequestInit < RequestInitCfProperties > > =
185+ isLargeFile
186+ ? { cache : "no-store" }
187+ : {
188+ cf : {
189+ cacheEverything : true ,
190+ cacheTtl : 30 * 24 * 60 * 60 ,
191+ } ,
192+ } ;
193+ const srcRes = await fetch ( spec . srcUrl , {
164194 headers : {
165195 "User-Agent" : "Infinite Mac (+https://infinitemac.org)" ,
166196 "Range" : `bytes=${ chunkStart } -${ chunkEnd } ` ,
167197 } ,
168- // Don't allow Cloudflare to cache this request, since it will attempt
169- // to read the entire file (as opposed to jus the range that we requested).
170- cache : "no-store" ,
198+ ...cacheOptions ,
171199 signal : AbortSignal . timeout ( 2000 ) ,
172200 } ) ;
173201
0 commit comments