11'use strict' ;
22
33const path = require ( 'path' )
4- , fs = require ( 'fs' )
5- , zlib = require ( 'zlib' )
64 , events = require ( 'harken' )
75 , mime = require ( 'mime' )
8- , brotli = require ( 'iltorb' )
96 , routeStore = require ( './routeStore' )
107 , matchSimpleRoute = require ( './matchSimpleRoute' )
118 , isWildCardRoute = require ( './isWildCardRoute' )
129 , parseWildCardRoute = require ( './parseWildCardRoute' )
1310 , setupStaticRoutes = require ( './serverSetup' )
1411 , setSecurityHeaders = require ( '../security' )
12+ , handleStaticFile = require ( './handleStaticFile' )
1513
16- , not = require ( '../utils' ) . not
1714 , send = require ( '../utils' ) . send
1815 , setStatus = require ( '../utils' ) . setStatus
1916 , parsePath = require ( '../utils' ) . parsePath
20- , getCompression = require ( '../utils' ) . getCompression
2117 , redirect = require ( '../utils' ) . redirect
2218 , contains = require ( '../utils' ) . contains
2319
2420 , statsd = require ( '../utils/statsd' )
2521
26- , succesStatus = 200
27- , unmodifiedStatus = 304 ;
22+ , succesStatus = 200 ;
2823
2924module . exports = ( routesJson , config ) => {
3025 const publicPath = config . publicPath
31- , maxAge = config . maxAge
3226 , routePath = config . routePath
3327 , publicFolders = setupStaticRoutes ( routePath , publicPath )
34- , statsdClient = config . statsd === false ? false : statsd . create ( config . statsd ) ;
28+ , statsdClient = config . statsd === false ? false : statsd . create ( config . statsd )
29+
30+ , setupStatsdListeners = ( res , sendStatsd , cleanup ) => {
31+ if ( statsdClient ) {
32+ // Add response listeners
33+ res . once ( 'finish' , sendStatsd ) ;
34+ res . once ( 'error' , cleanup ) ;
35+ res . once ( 'close' , cleanup ) ;
36+ }
37+ } ;
3538
3639 routeStore . parse ( routesJson ) ;
3740
@@ -41,14 +44,13 @@ module.exports = (routesJson, config) => {
4144 , pathParsed = parsePath ( req . url )
4245 , pathname = pathParsed . pathname
4346 , simpleRoute = matchSimpleRoute ( pathname , method , routeStore . getStandard ( ) )
44- , expires = new Date ( ) . getTime ( )
4547 , connection = {
4648 req : req
4749 , res : resIn
4850 , query : pathParsed . query
4951 , params : { }
52+ , path : pathParsed
5053 }
51- , compression = getCompression ( req . headers [ 'accept-encoding' ] , config )
5254 , statsdStartTime = new Date ( ) . getTime ( )
5355
5456 , cleanupStatsd = ( ) => {
@@ -86,25 +88,18 @@ module.exports = (routesJson, config) => {
8688 cleanupStatsd ( ) ;
8789 } ;
8890
89- let file
90- , routeInfo
91+ let routeInfo
9192 , res = resIn ;
9293
93- // set up the statsd timing listeners
94- if ( statsdClient ) {
95- // Add response listeners
96- res . once ( 'finish' , sendStatsd ) ;
97- res . once ( 'error' , cleanupStatsd ) ;
98- res . once ( 'close' , cleanupStatsd ) ;
99- }
94+ // set up the statsd timing listeners
95+ setupStatsdListeners ( res , sendStatsd , cleanupStatsd ) ;
10096
10197 // add .setStatus to response
10298 res . setStatus = setStatus ;
10399
104100 // add .send to the response
105101 res . send = send ( req , config ) ;
106102 res . redirect = redirect ( req ) ;
107-
108103 res = setSecurityHeaders ( config , req , res ) ;
109104
110105 // match the first part of the url... for public stuff
@@ -115,101 +110,8 @@ module.exports = (routesJson, config) => {
115110 // the accept-encoding header. So (gzip/deflate/no compression)
116111 res . setHeader ( 'Vary' , 'Accept-Encoding' ) ;
117112
118- file = path . join ( publicPath , pathname ) ;
119113 // read in the file and stream it to the client
120- fs . stat ( file , ( err , exists ) => {
121- if ( ! err && exists . isFile ( ) ) {
122-
123- events . required ( [ `etag:check:${ file } ` , `etag:get:${ file } ` ] , ( valid ) => {
124- if ( valid [ 0 ] ) { // does the etag match? YES
125- res . statusCode = unmodifiedStatus ;
126- return res . end ( ) ;
127- }
128- // No match...
129- res . setHeader ( 'ETag' , valid [ 1 ] ) ; // the etag is item 2 in the array
130-
131- if ( req . method . toLowerCase ( ) === 'head' ) {
132- res . writeHead ( succesStatus , {
133- 'Content-Type' : mime . getType ( pathname )
134- , 'Cache-Control' : `maxage=${ maxAge } `
135- , Expires : new Date ( expires + maxAge ) . toUTCString ( )
136- , 'Content-Encoding' : compression
137- } ) ;
138-
139- res . end ( ) ;
140- } else if ( not ( compression === 'none' ) ) {
141- // we have compression!
142- res . writeHead ( succesStatus , {
143- 'Content-Type' : mime . getType ( pathname )
144- , 'Cache-Control' : `maxage=${ maxAge } `
145- , Expires : new Date ( expires + maxAge ) . toUTCString ( )
146- , 'Content-Encoding' : compression
147- } ) ;
148-
149- if ( compression === 'deflate' ) {
150- fs . stat ( `${ file } .def` , ( errDef , existsDef ) => {
151- if ( ! errDef && existsDef . isFile ( ) ) {
152- fs . createReadStream ( `${ file } .def` ) . pipe ( res ) ;
153- } else {
154- // no compressed file yet...
155- fs . createReadStream ( file ) . pipe ( zlib . createDeflate ( ) )
156- . pipe ( res ) ;
157-
158- fs . createReadStream ( file ) . pipe ( zlib . createDeflate ( ) )
159- . pipe ( fs . createWriteStream ( `${ file } .def` ) ) ;
160- }
161- } ) ;
162- } else if ( compression === 'br' ) {
163- // brotli compression handling
164- fs . stat ( `${ file } .brot` , ( errBrotli , existsBrotli ) => {
165- if ( ! errBrotli && existsBrotli . isFile ( ) ) {
166- fs . createReadStream ( `${ file } .brot` ) . pipe ( res ) ;
167- } else {
168- // no compressed file yet...
169- fs . createReadStream ( file ) . pipe ( brotli . compressStream ( ) )
170- . pipe ( res ) ;
171-
172- fs . createReadStream ( file ) . pipe ( brotli . compressStream ( ) )
173- . pipe ( fs . createWriteStream ( `${ file } .brot` ) ) ;
174- }
175- } ) ;
176- } else {
177- fs . stat ( `${ file } .tgz` , ( errTgz , existsTgz ) => {
178- if ( ! errTgz && existsTgz . isFile ( ) ) {
179- fs . createReadStream ( `${ file } .tgz` ) . pipe ( res ) ;
180- } else {
181- // no compressed file yet...
182- fs . createReadStream ( file ) . pipe ( zlib . createGzip ( ) )
183- . pipe ( res ) ;
184-
185- fs . createReadStream ( file ) . pipe ( zlib . createGzip ( ) )
186- . pipe ( fs . createWriteStream ( `${ file } .tgz` ) ) ;
187- }
188- } ) ;
189- }
190-
191- events . emit ( 'static:served' , pathname ) ;
192-
193- } else {
194- // no compression carry on...
195- // return with the correct heders for the file type
196- res . writeHead ( succesStatus , {
197- 'Content-Type' : mime . getType ( pathname )
198- , 'Cache-Control' : `maxage=${ maxAge } `
199- , Expires : new Date ( expires + maxAge ) . toUTCString ( )
200- } ) ;
201- fs . createReadStream ( file ) . pipe ( res ) ;
202- events . emit ( 'static:served' , pathname ) ;
203- }
204- } ) ;
205-
206- events . emit ( 'etag:check' , { file : file , etag : req . headers [ 'if-none-match' ] } ) ;
207-
208- } else {
209- events . emit ( 'static:missing' , pathname ) ;
210- events . emit ( 'error:404' , connection ) ;
211- }
212- } ) ;
114+ handleStaticFile ( path . join ( publicPath , pathname ) , connection , config ) ;
213115
214116 } else if ( simpleRoute !== null ) {
215117 // matches a route in the routes.json
@@ -225,7 +127,6 @@ module.exports = (routesJson, config) => {
225127 } else if ( isWildCardRoute ( pathname , method , routeStore . getWildcard ( ) ) ) {
226128 // matches a route in the routes.json file that has params
227129 routeInfo = parseWildCardRoute ( pathname , routeStore . getWildcard ( ) ) ;
228-
229130 connection . params = routeInfo . values ;
230131
231132 // emit the event for the url minus params and include the params
0 commit comments