(stat)
| 227 | |
| 228 | |
| 229 | function serve(stat) { |
| 230 | // Do a MIME lookup, fall back to octet-stream and handle gzip |
| 231 | // and brotli special case. |
| 232 | const defaultType = opts.contentType || 'application/octet-stream'; |
| 233 | let contentType = mime.lookup(file, defaultType); |
| 234 | const range = (req.headers && req.headers.range); |
| 235 | const lastModified = (new Date(stat.mtime)).toUTCString(); |
| 236 | const etag = generateEtag(stat, weakEtags); |
| 237 | let cacheControl = cache; |
| 238 | let stream = null; |
| 239 | if (contentType && isTextFile(contentType)) { |
| 240 | if (stat.size < buffer.constants.MAX_LENGTH) { |
| 241 | const bytes = fs.readFileSync(file); |
| 242 | const sniffedEncoding = htmlEncodingSniffer(bytes, { |
| 243 | defaultEncoding: 'UTF-8' |
| 244 | }); |
| 245 | contentType += `; charset=${sniffedEncoding}`; |
| 246 | stream = Readable.from(bytes) |
| 247 | } else { |
| 248 | // Assume text types are utf8 |
| 249 | contentType += '; charset=UTF-8'; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | if (file === gzippedFile) { // is .gz picked up |
| 254 | res.setHeader('Content-Encoding', 'gzip'); |
| 255 | // strip gz ending and lookup mime type |
| 256 | contentType = mime.lookup(path.basename(file, '.gz'), defaultType); |
| 257 | } else if (file === brotliFile) { // is .br picked up |
| 258 | res.setHeader('Content-Encoding', 'br'); |
| 259 | // strip br ending and lookup mime type |
| 260 | contentType = mime.lookup(path.basename(file, '.br'), defaultType); |
| 261 | } |
| 262 | |
| 263 | if (typeof cacheControl === 'function') { |
| 264 | cacheControl = cache(pathname); |
| 265 | } |
| 266 | if (typeof cacheControl === 'number') { |
| 267 | cacheControl = `max-age=${cacheControl}`; |
| 268 | } |
| 269 | |
| 270 | if (range) { |
| 271 | const total = stat.size; |
| 272 | const parts = range.trim().replace(/bytes=/, '').split('-'); |
| 273 | const partialstart = parts[0]; |
| 274 | const partialend = parts[1]; |
| 275 | const start = parseInt(partialstart, 10); |
| 276 | const end = Math.min( |
| 277 | total - 1, |
| 278 | partialend ? parseInt(partialend, 10) : total - 1 |
| 279 | ); |
| 280 | const chunksize = (end - start) + 1; |
| 281 | let fstream = null; |
| 282 | |
| 283 | if (start > end || isNaN(start) || isNaN(end)) { |
| 284 | status['416'](res, next); |
| 285 | return; |
| 286 | } |
no test coverage detected
searching dependent graphs…