1+ /*
2+ * Copyright (c) 2016-2021 Moddable Tech, Inc.
3+ * Copyright (c) Wilberforce
4+ *
5+ * This file is part of the Moddable SDK.
6+ *
7+ * This work is licensed under the
8+ * Creative Commons Attribution 4.0 International License.
9+ * To view a copy of this license, visit
10+ * <http://creativecommons.org/licenses/by/4.0>.
11+ * or send a letter to Creative Commons, PO Box 1866,
12+ * Mountain View, CA 94042, USA.
13+ *
14+ */
15+
16+ import { Middleware , Server } from "middleware/server" ;
17+ import { ZIP } from "zip"
18+
19+ const mime = new Map ;
20+ mime . set ( "js" , "application/javascript" ) ;
21+ mime . set ( "css" , "text/css" ) ;
22+ mime . set ( "ico" , "image/vnd.microsoft.icon" ) ;
23+ mime . set ( "txt" , "text/plain" ) ;
24+ mime . set ( "htm" , "text/html" ) ;
25+ mime . set ( "html" , "text/html" ) ;
26+ mime . set ( "svg" , "image/svg+xml" ) ;
27+ mime . set ( "png" , "image/png" ) ;
28+ mime . set ( "gif" , "image/gif" ) ;
29+ mime . set ( "webp" , "image/webp" ) ;
30+ mime . set ( "jpg" , "image/jpeg" ) ;
31+ mime . set ( "jpeg" , "image/jpeg" ) ;
32+
33+ export class MiddlewareStaticZip extends Middleware {
34+ constructor ( archive ) {
35+ super ( ) ;
36+
37+ this . archive = new ZIP ( archive ) ;
38+ }
39+
40+ handler ( req , message , value , etc ) {
41+ switch ( message ) {
42+ case Server . status :
43+ // redirect home page
44+ if ( value === '/' ) value = '/index.html' ;
45+ req . path = value ;
46+ try {
47+ req . data = this . archive . file ( req . path . slice ( 1 ) ) ; // drop leading / to match zip content
48+ req . etag = "mod-" + req . data . crc . toString ( 16 ) ;
49+ }
50+ catch {
51+ delete req . data ;
52+ delete req . etag ;
53+ return this . next ?. handler ( req , message , value , etc ) ;
54+ }
55+ break ;
56+
57+ case Server . header :
58+ req . match ||= ( "if-none-match" === value ) && ( req . etag === etc ) ;
59+ return this . next ?. handler ( req , message , value , etc ) ;
60+
61+ case Server . prepareResponse :
62+ if ( req . match ) {
63+ return {
64+ status : 304 ,
65+ headers : [
66+ "ETag" , req . etag ,
67+ ]
68+ } ;
69+ }
70+ if ( ! req . data ) {
71+ trace ( `prepareResponse: missing file ${ req . path } \n` ) ;
72+
73+ return this . next ?. handler ( req , message , value , etc ) ;
74+ }
75+
76+ req . data . current = 0 ;
77+ const result = {
78+ headers : [
79+ "Content-type" , mime . get ( req . path . split ( '.' ) . pop ( ) ) ?? "text/plain" ,
80+ "Content-length" , req . data . length ,
81+ "ETag" , req . etag ,
82+ "Cache-Control" , "max-age=60"
83+ ] ,
84+ body : true
85+ }
86+ if ( 8 === req . data . method ) // Compression Method
87+ result . headers . push ( "Content-Encoding" , "deflate" ) ;
88+ return result ;
89+
90+ case Server . responseFragment :
91+ if ( req . data . current >= req . data . length )
92+ return ;
93+
94+ const chunk = req . data . read ( ArrayBuffer , ( value > 1536 ) ? 1536 : value ) ;
95+ req . data . current += chunk . byteLength ;
96+ return chunk ;
97+ }
98+ }
99+ }
100+
101+ Object . freeze ( mime ) ;
0 commit comments