node-http-server – Blame information for rev 38
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
35 | office | 1 | #!/usr/bin/env node |
2 | |||
3 | /*************************************************************************/ |
||
4 | /* Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 */ |
||
5 | /*************************************************************************/ |
||
6 | |||
38 | office | 7 | const fs = require('fs') |
8 | const stream = require('stream') |
||
9 | const util = require('util') |
||
10 | const tz = require('moment-timezone') |
||
11 | const forge = require('node-forge') |
||
12 | const EventEmitter = require('events').EventEmitter |
||
35 | office | 13 | |
14 | // Cache constructor. |
||
15 | function Cache(config, client, request, response) { |
||
16 | // Create events emitters for logging and data. |
||
38 | office | 17 | EventEmitter.call(this) |
35 | office | 18 | |
19 | // Pass through objects needed for caching. |
||
38 | office | 20 | this.config = config |
21 | this.client = client |
||
22 | this.request = request |
||
23 | this.response = response |
||
24 | } |
||
35 | office | 25 | |
26 | // Cache handling. |
||
27 | Cache.prototype.process = function(resource, input, type) { |
||
38 | office | 28 | EventEmitter.call(this) |
29 | const self = this |
||
35 | office | 30 | |
37 | office | 31 | // Read the resource and cache or not depending on configuration settings. |
35 | office | 32 | fs.stat(resource, (error, stats) => { |
38 | office | 33 | var expires = 0 |
35 | office | 34 | Object.keys(self.config.site.cache).forEach((key) => { |
35 | self.config.site.cache[key].forEach((expire) => { |
||
36 | if (expire.test(resource)) { |
||
38 | office | 37 | expires = key |
35 | office | 38 | } |
38 | office | 39 | }) |
40 | }) |
||
35 | office | 41 | |
42 | switch (self.request.httpVersion) { |
||
43 | case '1.1': // HTTP 1.1 |
||
44 | self.response.setHeader('Cache-Control', |
||
45 | "max-age=" + expires + ", public" |
||
38 | office | 46 | ) |
47 | const sha1 = forge.md.sha1.create() |
||
35 | office | 48 | const data = new stream.Readable({ |
49 | objectMode: true, |
||
50 | read(size) {} |
||
38 | office | 51 | }) |
35 | office | 52 | input |
53 | .on('data', (chunk) => { |
||
38 | office | 54 | sha1.update(chunk) |
55 | data.push(chunk) |
||
35 | office | 56 | }) |
57 | .on('end', () => { |
||
38 | office | 58 | const etag = sha1.digest().toHex() |
35 | office | 59 | |
60 | // Set the ETag for the resource. |
||
38 | office | 61 | self.response.setHeader('ETag', etag) |
35 | office | 62 | |
63 | const ifNoneMatch = Object |
||
64 | .getOwnPropertyNames(self.request.headers) |
||
65 | .filter((header) => header.toUpperCase() === |
||
38 | office | 66 | 'If-None-Match'.toUpperCase()) |
35 | office | 67 | |
68 | const ifModifiedSince = Object |
||
69 | .getOwnPropertyNames(self.request.headers) |
||
70 | .filter((header) => header.toUpperCase() === |
||
38 | office | 71 | 'If-Modified-Since'.toUpperCase()) |
35 | office | 72 | |
73 | if ((ifNoneMatch.length !== 0 && |
||
74 | self.request.headers[ifNoneMatch].toUpperCase() === etag.toUpperCase()) || |
||
75 | (ifModifiedSince.length !== 0 && |
||
76 | tz(self.request.headers[ifModifiedSince]).tz('UTC') < tz(stat.mtime).tz('UTC'))) {> |
||
77 | < tz(stat.mtime).tz('UTC'))) { // Send a cache hit response.> |
||
78 | < tz(stat.mtime).tz('UTC'))) { self.emit('log', {> |
||
79 | < tz(stat.mtime).tz('UTC'))) { message: 'Client: ' +> |
||
80 | < tz(stat.mtime).tz('UTC'))) { self.client.address + ':' +> |
||
81 | < tz(stat.mtime).tz('UTC'))) { self.client.port +> |
||
82 | < tz(stat.mtime).tz('UTC'))) { ' cached resource: ' +> |
||
83 | < tz(stat.mtime).tz('UTC'))) { resource,> |
||
84 | < tz(stat.mtime).tz('UTC'))) { severity: 'info'> |
||
38 | office | 85 | < tz(stat.mtime).tz('UTC'))) { })> |
35 | office | 86 | < tz(stat.mtime).tz('UTC'))) { self.emit('data', {> |
87 | < tz(stat.mtime).tz('UTC'))) { status: 304,> |
||
88 | < tz(stat.mtime).tz('UTC'))) { data: new stream.Readable({> |
||
89 | < tz(stat.mtime).tz('UTC'))) { read(size) {> |
||
38 | office | 90 | < tz(stat.mtime).tz('UTC'))) { this.push(null)> |
35 | office | 91 | < tz(stat.mtime).tz('UTC'))) { }> |
92 | < tz(stat.mtime).tz('UTC'))) { }),> |
||
93 | < tz(stat.mtime).tz('UTC'))) { type: type> |
||
38 | office | 94 | < tz(stat.mtime).tz('UTC'))) { })> |
95 | < tz(stat.mtime).tz('UTC'))) { return> |
||
35 | office | 96 | < tz(stat.mtime).tz('UTC'))) { }> |
97 | |||
98 | < tz(stat.mtime).tz('UTC'))) { // Send the resource.> |
||
99 | < tz(stat.mtime).tz('UTC'))) { self.emit('log', {> |
||
100 | < tz(stat.mtime).tz('UTC'))) { message: 'Client: ' +> |
||
101 | < tz(stat.mtime).tz('UTC'))) { self.client.address + ':' +> |
||
102 | < tz(stat.mtime).tz('UTC'))) { self.client.port +> |
||
103 | < tz(stat.mtime).tz('UTC'))) { ' sent resource: ' +> |
||
104 | < tz(stat.mtime).tz('UTC'))) { resource,> |
||
105 | < tz(stat.mtime).tz('UTC'))) { severity: 'info'> |
||
38 | office | 106 | < tz(stat.mtime).tz('UTC'))) { })> |
107 | < tz(stat.mtime).tz('UTC'))) { data.push(null)> |
||
35 | office | 108 | < tz(stat.mtime).tz('UTC'))) { self.emit('data', {> |
109 | < tz(stat.mtime).tz('UTC'))) { status: 200,> |
||
110 | < tz(stat.mtime).tz('UTC'))) { data: data,> |
||
111 | < tz(stat.mtime).tz('UTC'))) { type: type> |
||
38 | office | 112 | < tz(stat.mtime).tz('UTC'))) { })> |
113 | < tz(stat.mtime).tz('UTC'))) { })> |
||
35 | office | 114 | |
38 | office | 115 | < tz(stat.mtime).tz('UTC'))) { return> |
35 | office | 116 | < tz(stat.mtime).tz('UTC'))) { default:> |
117 | < tz(stat.mtime).tz('UTC'))) { self.response.setHeader('Last-Modified',> |
||
118 | < tz(stat.mtime).tz('UTC'))) { tz(stats.mtime)> |
||
119 | < tz(stat.mtime).tz('UTC'))) { .tz('UTC')> |
||
120 | < tz(stat.mtime).tz('UTC'))) { .format("ddd, DD MMM YYYY HH:mm:ss z")> |
||
38 | office | 121 | < tz(stat.mtime).tz('UTC'))) { )> |
35 | office | 122 | < tz(stat.mtime).tz('UTC'))) { self.response.setHeader('Expires',> |
123 | < tz(stat.mtime).tz('UTC'))) { tz()> |
||
124 | < tz(stat.mtime).tz('UTC'))) { .tz('UTC')> |
||
125 | < tz(stat.mtime).tz('UTC'))) { .add(expires, 'seconds')> |
||
126 | < tz(stat.mtime).tz('UTC'))) { .format("ddd, DD MMM YYYY HH:mm:ss z")> |
||
38 | office | 127 | < tz(stat.mtime).tz('UTC'))) { )> |
35 | office | 128 | < tz(stat.mtime).tz('UTC'))) { // Send the resource.> |
129 | < tz(stat.mtime).tz('UTC'))) { self.emit('log', {> |
||
130 | < tz(stat.mtime).tz('UTC'))) { message: 'Client: ' +> |
||
131 | < tz(stat.mtime).tz('UTC'))) { self.client.address + ':' +> |
||
132 | < tz(stat.mtime).tz('UTC'))) { self.client.port +> |
||
133 | < tz(stat.mtime).tz('UTC'))) { ' sent resource: ' +> |
||
134 | < tz(stat.mtime).tz('UTC'))) { resource,> |
||
135 | < tz(stat.mtime).tz('UTC'))) { severity: 'info'> |
||
38 | office | 136 | < tz(stat.mtime).tz('UTC'))) { })> |
35 | office | 137 | < tz(stat.mtime).tz('UTC'))) { self.emit('data', {> |
138 | < tz(stat.mtime).tz('UTC'))) { status: 200,> |
||
139 | < tz(stat.mtime).tz('UTC'))) { data: input,> |
||
140 | < tz(stat.mtime).tz('UTC'))) { type: type> |
||
38 | office | 141 | < tz(stat.mtime).tz('UTC'))) { })> |
142 | < tz(stat.mtime).tz('UTC'))) { break> |
||
35 | office | 143 | < tz(stat.mtime).tz('UTC'))) { }> |
38 | office | 144 | < tz(stat.mtime).tz('UTC'))) { })> |
35 | office | 145 | |
38 | office | 146 | < tz(stat.mtime).tz('UTC'))) { return this> |
147 | < tz(stat.mtime).tz('UTC'))) {}> |
||
35 | office | 148 | |
38 | office | 149 | < tz(stat.mtime).tz('UTC'))) {util.inherits(Cache, EventEmitter)> |
150 | < tz(stat.mtime).tz('UTC'))) {module.exports = Cache> |