fluffy – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #!/usr/bin/env node |
2 | |||
3 | /*************************************************************************/ |
||
4 | /* Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 */ |
||
5 | /*************************************************************************/ |
||
6 | |||
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; |
||
13 | |||
14 | // Cache constructor. |
||
15 | function Cache(config, client, request, response) { |
||
16 | // Create events emitters for logging and data. |
||
17 | EventEmitter.call(this); |
||
18 | |||
19 | // Pass through objects needed for caching. |
||
20 | this.config = config; |
||
21 | this.client = client; |
||
22 | this.request = request; |
||
23 | this.response = response; |
||
24 | }; |
||
25 | |||
26 | // Cache handling. |
||
27 | Cache.prototype.process = function(resource, input, type) { |
||
28 | EventEmitter.call(this); |
||
29 | const self = this; |
||
30 | |||
31 | // Read the resource and cache or not depending on configuration settings. |
||
32 | fs.stat(resource, (error, stats) => { |
||
33 | var expires = 0; |
||
34 | Object.keys(self.config.site.cache).forEach((key) => { |
||
35 | self.config.site.cache[key].forEach((expire) => { |
||
36 | if (expire.test(resource)) { |
||
37 | expires = key; |
||
38 | } |
||
39 | }); |
||
40 | }); |
||
41 | |||
42 | switch (self.request.httpVersion) { |
||
43 | case '1.1': // HTTP 1.1 |
||
44 | self.response.setHeader('Cache-Control', |
||
45 | "max-age=" + expires + ", public" |
||
46 | ); |
||
47 | const sha1 = forge.md.sha1.create(); |
||
48 | const data = new stream.Readable({ |
||
49 | objectMode: true, |
||
50 | read(size) {} |
||
51 | }); |
||
52 | input |
||
53 | .on('data', (chunk) => { |
||
54 | sha1.update(chunk); |
||
55 | data.push(chunk); |
||
56 | }) |
||
57 | .on('end', () => { |
||
58 | const etag = sha1.digest().toHex(); |
||
59 | |||
60 | // Set the ETag for the resource. |
||
61 | self.response.setHeader('ETag', etag); |
||
62 | |||
63 | const ifNoneMatch = Object |
||
64 | .getOwnPropertyNames(self.request.headers) |
||
65 | .filter((header) => header.toUpperCase() === |
||
66 | 'If-None-Match'.toUpperCase()); |
||
67 | |||
68 | const ifModifiedSince = Object |
||
69 | .getOwnPropertyNames(self.request.headers) |
||
70 | .filter((header) => header.toUpperCase() === |
||
71 | 'If-Modified-Since'.toUpperCase()); |
||
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'> |
||
85 | < tz(stat.mtime).tz('UTC'))) { });> |
||
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) {> |
||
90 | < tz(stat.mtime).tz('UTC'))) { this.push(null);> |
||
91 | < tz(stat.mtime).tz('UTC'))) { }> |
||
92 | < tz(stat.mtime).tz('UTC'))) { }),> |
||
93 | < tz(stat.mtime).tz('UTC'))) { type: type> |
||
94 | < tz(stat.mtime).tz('UTC'))) { });> |
||
95 | < tz(stat.mtime).tz('UTC'))) { return;> |
||
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'> |
||
106 | < tz(stat.mtime).tz('UTC'))) { });> |
||
107 | < tz(stat.mtime).tz('UTC'))) { data.push(null);> |
||
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> |
||
112 | < tz(stat.mtime).tz('UTC'))) { });> |
||
113 | < tz(stat.mtime).tz('UTC'))) { });> |
||
114 | |||
115 | < tz(stat.mtime).tz('UTC'))) { return;> |
||
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")> |
||
121 | < tz(stat.mtime).tz('UTC'))) { );> |
||
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")> |
||
127 | < tz(stat.mtime).tz('UTC'))) { );> |
||
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'> |
||
136 | < tz(stat.mtime).tz('UTC'))) { });> |
||
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> |
||
141 | < tz(stat.mtime).tz('UTC'))) { });> |
||
142 | < tz(stat.mtime).tz('UTC'))) { break;> |
||
143 | < tz(stat.mtime).tz('UTC'))) { }> |
||
144 | < tz(stat.mtime).tz('UTC'))) { });> |
||
145 | |||
146 | < tz(stat.mtime).tz('UTC'))) { return this;> |
||
147 | < tz(stat.mtime).tz('UTC'))) {};> |
||
148 | |||
149 | < tz(stat.mtime).tz('UTC'))) {util.inherits(Cache, EventEmitter);> |
||
150 | < tz(stat.mtime).tz('UTC'))) {module.exports = Cache;> |