node-http-server – Diff between revs 14 and 15
?pathlinks?
Rev 14 | Rev 15 | |||
---|---|---|---|---|
Line 9... | Line 9... | |||
9 | const fs = require('fs'); |
9 | const fs = require('fs'); |
|
10 | const mime = require('mime'); |
10 | const mime = require('mime'); |
|
11 | const auth = require("http-auth"); |
11 | const auth = require("http-auth"); |
|
Line 12... | Line 12... | |||
12 | |
12 | |
|
13 | // Checks whether userPath is a child of rootPath. |
13 | // Checks whether userPath is a child of rootPath. |
|
- | 14 | function isRooted(userPath, rootPath, separator, callback) { |
||
14 | function isRooted(userPath, rootPath, separator) { |
15 | process.nextTick(() => { |
|
15 | userPath = userPath.split(separator).filter(Boolean); |
16 | userPath = userPath.split(separator).filter(Boolean); |
|
16 | rootPath = rootPath.split(separator).filter(Boolean); |
17 | rootPath = rootPath.split(separator).filter(Boolean); |
|
17 | return userPath.length >= rootPath.length && |
18 | callback(userPath.length >= rootPath.length && |
|
- | 19 | rootPath.every((e, i) => e === userPath[i])); |
||
18 | rootPath.every((e, i) => e === userPath[i]); |
20 | }); |
|
Line 19... | Line 21... | |||
19 | } |
21 | } |
|
20 | |
22 | |
|
21 | // Serves files. |
23 | // Serves files. |
|
22 | function files(config, request, response, resource, callback) { |
- | ||
23 | // Check if the file is accessible. |
24 | function files(config, request, response, resource, callback) { |
|
24 | process.nextTick(() => { |
25 | // Check if the file is accessible. |
|
25 | fs.access(resource, fs.constants.R_OK, (error) => { |
26 | fs.access(resource, fs.constants.R_OK, (error) => { |
|
26 | if (error) { |
27 | if (error) { |
|
27 | response.statusCode = 403; |
28 | response.statusCode = 403; |
|
Line 43... | Line 44... | |||
43 | response.statusCode = 500; |
44 | response.statusCode = 500; |
|
44 | response.end(); |
45 | response.end(); |
|
45 | }); |
46 | }); |
|
Line 46... | Line 47... | |||
46 | |
47 | |
|
47 | }); |
- | ||
48 | }); |
48 | }); |
|
Line 49... | Line 49... | |||
49 | } |
49 | } |
|
50 | |
50 | |
|
51 | // Serves a directory index. |
- | ||
52 | function index(config, request, response, resource, callback) { |
- | ||
53 | process.nextTick(() => { |
51 | // Serves a directory listing or the document index in case it exists. |
|
54 | const root = path.resolve(resource, config.site.index); |
52 | function index(config, request, response, resource, root, callback) { |
|
55 | fs.stat(root, (error, stats) => { |
53 | fs.stat(root, (error, stats) => { |
|
56 | if (error) { |
54 | if (error) { |
|
57 | fs.readdir(resource, (error, paths) => { |
55 | fs.readdir(resource, (error, paths) => { |
|
Line 78... | Line 76... | |||
78 | }); |
76 | }); |
|
Line 79... | Line 77... | |||
79 | |
77 | |
|
80 | return; |
78 | return; |
|
Line -... | Line 79... | |||
- | 79 | } |
||
81 | } |
80 | |
|
82 | |
81 | // Serve the document index. |
|
83 | fs.access(resource, fs.constants.R_OK, (error) => { |
82 | fs.access(resource, fs.constants.R_OK, (error) => { |
|
84 | if (error) { |
83 | if (error) { |
|
85 | process.nextTick(() => { |
84 | process.nextTick(() => { |
|
Line 108... | Line 107... | |||
108 | response.statusCode = 500; |
107 | response.statusCode = 500; |
|
109 | response.end(); |
108 | response.end(); |
|
110 | }); |
109 | }); |
|
Line 111... | Line 110... | |||
111 | |
110 | |
|
112 | }); |
- | ||
113 | |
- | ||
114 | }); |
111 | }); |
|
115 | }); |
112 | }); |
|
Line 116... | Line 113... | |||
116 | } |
113 | } |
|
117 | |
114 | |
|
118 | // Determines whether the requested resource is a directory or a file. |
- | ||
119 | function serve(config, request, response, resource, callback) { |
115 | // Determines whether the requested resource is a directory or a file. |
|
120 | process.nextTick(() => { |
116 | function serve(config, request, response, resource, callback) { |
|
121 | fs.stat(resource, (error, stats) => { |
117 | fs.stat(resource, (error, stats) => { |
|
122 | // Document does not exist. |
118 | // Document does not exist. |
|
123 | if (error) { |
119 | if (error) { |
|
124 | response.statusCode = 404; |
120 | response.statusCode = 404; |
|
125 | response.end(); |
121 | response.end(); |
|
Line 126... | Line 122... | |||
126 | return; |
122 | return; |
|
127 | } |
123 | } |
|
128 | |
124 | |
|
129 | switch (stats.isDirectory()) { |
125 | switch (stats.isDirectory()) { |
|
130 | case true: // Directory is requested so provide directory indexes. |
126 | case true: // Directory is requested so provide directory indexes. |
|
131 | index(config, request, response, resource, callback) |
127 | index(config, request, response, resource, path.resolve(resource, config.site.index), callback) |
|
132 | break; |
128 | break; |
|
133 | default: // Browser requesting file. |
129 | default: // Browser requesting file. |
|
134 | files(config, request, response, resource, callback); |
130 | files(config, request, response, resource, callback); |
|
135 | break; |
- | ||
136 | } |
131 | break; |
|
Line 137... | Line 132... | |||
137 | }); |
132 | } |
|
138 | }); |
133 | }); |
|
139 | } |
134 | } |
|
Line 169... | Line 164... | |||
169 | .join('/'); |
164 | .join('/'); |
|
170 | const resource = trimmedPath === '/' ? |
165 | const resource = trimmedPath === '/' ? |
|
171 | path.join(root, trimmedPath) : |
166 | path.join(root, trimmedPath) : |
|
172 | path.resolve(root, trimmedPath); |
167 | path.resolve(root, trimmedPath); |
|
Line 173... | Line 168... | |||
173 | |
168 | |
|
- | 169 | isRooted(resource, root, path.sep, (rooted) => { |
||
174 | if (!isRooted(resource, root, path.sep)) { |
170 | if (!rooted) { |
|
175 | process.nextTick(() => { |
171 | process.nextTick(() => { |
|
176 | callback('Attempted path traversal: ' + |
172 | callback('Attempted path traversal: ' + |
|
177 | requestAddress.address + ':' + |
173 | requestAddress.address + ':' + |
|
178 | requestAddress.port + |
174 | requestAddress.port + |
|
Line 184... | Line 180... | |||
184 | response.statusCode = 404; |
180 | response.statusCode = 404; |
|
185 | response.end(); |
181 | response.end(); |
|
186 | return; |
182 | return; |
|
187 | } |
183 | } |
|
Line -... | Line 184... | |||
- | 184 | |
||
188 | |
185 | // Check if the requested path requires authentication. |
|
189 | switch (config.auth.locations.some( |
186 | switch (config.auth.locations.some( |
|
190 | (authPath) => authPath.toUpperCase() === requestedURL.pathname.toUpperCase())) { |
187 | (authPath) => authPath.toUpperCase() === requestedURL.pathname.toUpperCase())) { |
|
191 | case true: |
188 | case true: |
|
192 | // Requested location requires authentication. |
189 | // Requested location requires authentication. |
|
Line 215... | Line 212... | |||
215 | }); |
212 | }); |
|
216 | serve(config, request, response, resource, callback); |
213 | serve(config, request, response, resource, callback); |
|
217 | break; |
214 | break; |
|
218 | } |
215 | } |
|
219 | }); |
216 | }); |
|
- | 217 | }); |
||
220 | } |
218 | } |
|
221 | }; |
219 | }; |