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