PageRenderTime 23ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/style/assets/js/vendor/file-upload/server/node/server.js

https://gitlab.com/deadgood/sportas
JavaScript | 292 lines | 265 code | 2 blank | 25 comment | 32 complexity | e7f59cfceeb69c7a8c11c5ff22db104f MD5 | raw file
  1. #!/usr/bin/env node
  2. /*
  3. * jQuery File Upload Plugin Node.js Example 2.1.2
  4. * https://github.com/blueimp/jQuery-File-Upload
  5. *
  6. * Copyright 2012, Sebastian Tschan
  7. * https://blueimp.net
  8. *
  9. * Licensed under the MIT license:
  10. * http://www.opensource.org/licenses/MIT
  11. */
  12. /* jshint nomen:false */
  13. /* global require, __dirname, unescape, console */
  14. (function (port) {
  15. 'use strict';
  16. var path = require('path'),
  17. fs = require('fs'),
  18. // Since Node 0.8, .existsSync() moved from path to fs:
  19. _existsSync = fs.existsSync || path.existsSync,
  20. formidable = require('formidable'),
  21. nodeStatic = require('node-static'),
  22. imageMagick = require('imagemagick'),
  23. options = {
  24. tmpDir: __dirname + '/tmp',
  25. publicDir: __dirname + '/public',
  26. uploadDir: __dirname + '/public/files',
  27. uploadUrl: '/files/',
  28. maxPostSize: 11000000000, // 11 GB
  29. minFileSize: 1,
  30. maxFileSize: 10000000000, // 10 GB
  31. acceptFileTypes: /.+/i,
  32. // Files not matched by this regular expression force a download dialog,
  33. // to prevent executing any scripts in the context of the service domain:
  34. inlineFileTypes: /\.(gif|jpe?g|png)$/i,
  35. imageTypes: /\.(gif|jpe?g|png)$/i,
  36. imageVersions: {
  37. 'thumbnail': {
  38. width: 80,
  39. height: 80
  40. }
  41. },
  42. accessControl: {
  43. allowOrigin: '*',
  44. allowMethods: 'OPTIONS, HEAD, GET, POST, PUT, DELETE',
  45. allowHeaders: 'Content-Type, Content-Range, Content-Disposition'
  46. },
  47. /* Uncomment and edit this section to provide the service via HTTPS:
  48. ssl: {
  49. key: fs.readFileSync('/Applications/XAMPP/etc/ssl.key/server.key'),
  50. cert: fs.readFileSync('/Applications/XAMPP/etc/ssl.crt/server.crt')
  51. },
  52. */
  53. nodeStatic: {
  54. cache: 3600 // seconds to cache served files
  55. }
  56. },
  57. utf8encode = function (str) {
  58. return unescape(encodeURIComponent(str));
  59. },
  60. fileServer = new nodeStatic.Server(options.publicDir, options.nodeStatic),
  61. nameCountRegexp = /(?:(?: \(([\d]+)\))?(\.[^.]+))?$/,
  62. nameCountFunc = function (s, index, ext) {
  63. return ' (' + ((parseInt(index, 10) || 0) + 1) + ')' + (ext || '');
  64. },
  65. FileInfo = function (file) {
  66. this.name = file.name;
  67. this.size = file.size;
  68. this.type = file.type;
  69. this.deleteType = 'DELETE';
  70. },
  71. UploadHandler = function (req, res, callback) {
  72. this.req = req;
  73. this.res = res;
  74. this.callback = callback;
  75. },
  76. serve = function (req, res) {
  77. res.setHeader(
  78. 'Access-Control-Allow-Origin',
  79. options.accessControl.allowOrigin
  80. );
  81. res.setHeader(
  82. 'Access-Control-Allow-Methods',
  83. options.accessControl.allowMethods
  84. );
  85. res.setHeader(
  86. 'Access-Control-Allow-Headers',
  87. options.accessControl.allowHeaders
  88. );
  89. var handleResult = function (result, redirect) {
  90. if (redirect) {
  91. res.writeHead(302, {
  92. 'Location': redirect.replace(
  93. /%s/,
  94. encodeURIComponent(JSON.stringify(result))
  95. )
  96. });
  97. res.end();
  98. } else {
  99. res.writeHead(200, {
  100. 'Content-Type': req.headers.accept
  101. .indexOf('application/json') !== -1 ?
  102. 'application/json' : 'text/plain'
  103. });
  104. res.end(JSON.stringify(result));
  105. }
  106. },
  107. setNoCacheHeaders = function () {
  108. res.setHeader('Pragma', 'no-cache');
  109. res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
  110. res.setHeader('Content-Disposition', 'inline; filename="files.json"');
  111. },
  112. handler = new UploadHandler(req, res, handleResult);
  113. switch (req.method) {
  114. case 'OPTIONS':
  115. res.end();
  116. break;
  117. case 'HEAD':
  118. case 'GET':
  119. if (req.url === '/') {
  120. setNoCacheHeaders();
  121. if (req.method === 'GET') {
  122. handler.get();
  123. } else {
  124. res.end();
  125. }
  126. } else {
  127. fileServer.serve(req, res);
  128. }
  129. break;
  130. case 'POST':
  131. setNoCacheHeaders();
  132. handler.post();
  133. break;
  134. case 'DELETE':
  135. handler.destroy();
  136. break;
  137. default:
  138. res.statusCode = 405;
  139. res.end();
  140. }
  141. };
  142. fileServer.respond = function (pathname, status, _headers, files, stat, req, res, finish) {
  143. // Prevent browsers from MIME-sniffing the content-type:
  144. _headers['X-Content-Type-Options'] = 'nosniff';
  145. if (!options.inlineFileTypes.test(files[0])) {
  146. // Force a download dialog for unsafe file extensions:
  147. _headers['Content-Type'] = 'application/octet-stream';
  148. _headers['Content-Disposition'] = 'attachment; filename="' +
  149. utf8encode(path.basename(files[0])) + '"';
  150. }
  151. nodeStatic.Server.prototype.respond
  152. .call(this, pathname, status, _headers, files, stat, req, res, finish);
  153. };
  154. FileInfo.prototype.validate = function () {
  155. if (options.minFileSize && options.minFileSize > this.size) {
  156. this.error = 'File is too small';
  157. } else if (options.maxFileSize && options.maxFileSize < this.size) {
  158. this.error = 'File is too big';
  159. } else if (!options.acceptFileTypes.test(this.name)) {
  160. this.error = 'Filetype not allowed';
  161. }
  162. return !this.error;
  163. };
  164. FileInfo.prototype.safeName = function () {
  165. // Prevent directory traversal and creating hidden system files:
  166. this.name = path.basename(this.name).replace(/^\.+/, '');
  167. // Prevent overwriting existing files:
  168. while (_existsSync(options.uploadDir + '/' + this.name)) {
  169. this.name = this.name.replace(nameCountRegexp, nameCountFunc);
  170. }
  171. };
  172. FileInfo.prototype.initUrls = function (req) {
  173. if (!this.error) {
  174. var that = this,
  175. baseUrl = (options.ssl ? 'https:' : 'http:') +
  176. '//' + req.headers.host + options.uploadUrl;
  177. this.url = this.deleteUrl = baseUrl + encodeURIComponent(this.name);
  178. Object.keys(options.imageVersions).forEach(function (version) {
  179. if (_existsSync(
  180. options.uploadDir + '/' + version + '/' + that.name
  181. )) {
  182. that[version + 'Url'] = baseUrl + version + '/' +
  183. encodeURIComponent(that.name);
  184. }
  185. });
  186. }
  187. };
  188. UploadHandler.prototype.get = function () {
  189. var handler = this,
  190. files = [];
  191. fs.readdir(options.uploadDir, function (err, list) {
  192. list.forEach(function (name) {
  193. var stats = fs.statSync(options.uploadDir + '/' + name),
  194. fileInfo;
  195. if (stats.isFile() && name[0] !== '.') {
  196. fileInfo = new FileInfo({
  197. name: name,
  198. size: stats.size
  199. });
  200. fileInfo.initUrls(handler.req);
  201. files.push(fileInfo);
  202. }
  203. });
  204. handler.callback({files: files});
  205. });
  206. };
  207. UploadHandler.prototype.post = function () {
  208. var handler = this,
  209. form = new formidable.IncomingForm(),
  210. tmpFiles = [],
  211. files = [],
  212. map = {},
  213. counter = 1,
  214. redirect,
  215. finish = function () {
  216. counter -= 1;
  217. if (!counter) {
  218. files.forEach(function (fileInfo) {
  219. fileInfo.initUrls(handler.req);
  220. });
  221. handler.callback({files: files}, redirect);
  222. }
  223. };
  224. form.uploadDir = options.tmpDir;
  225. form.on('fileBegin', function (name, file) {
  226. tmpFiles.push(file.path);
  227. var fileInfo = new FileInfo(file);
  228. fileInfo.safeName();
  229. map[path.basename(file.path)] = fileInfo;
  230. files.push(fileInfo);
  231. }).on('field', function (name, value) {
  232. if (name === 'redirect') {
  233. redirect = value;
  234. }
  235. }).on('file', function (name, file) {
  236. var fileInfo = map[path.basename(file.path)];
  237. fileInfo.size = file.size;
  238. if (!fileInfo.validate()) {
  239. fs.unlink(file.path);
  240. return;
  241. }
  242. fs.renameSync(file.path, options.uploadDir + '/' + fileInfo.name);
  243. if (options.imageTypes.test(fileInfo.name)) {
  244. Object.keys(options.imageVersions).forEach(function (version) {
  245. counter += 1;
  246. var opts = options.imageVersions[version];
  247. imageMagick.resize({
  248. width: opts.width,
  249. height: opts.height,
  250. srcPath: options.uploadDir + '/' + fileInfo.name,
  251. dstPath: options.uploadDir + '/' + version + '/' +
  252. fileInfo.name
  253. }, finish);
  254. });
  255. }
  256. }).on('aborted', function () {
  257. tmpFiles.forEach(function (file) {
  258. fs.unlink(file);
  259. });
  260. }).on('error', function (e) {
  261. console.log(e);
  262. }).on('progress', function (bytesReceived) {
  263. if (bytesReceived > options.maxPostSize) {
  264. handler.req.connection.destroy();
  265. }
  266. }).on('end', finish).parse(handler.req);
  267. };
  268. UploadHandler.prototype.destroy = function () {
  269. var handler = this,
  270. fileName;
  271. if (handler.req.url.slice(0, options.uploadUrl.length) === options.uploadUrl) {
  272. fileName = path.basename(decodeURIComponent(handler.req.url));
  273. if (fileName[0] !== '.') {
  274. fs.unlink(options.uploadDir + '/' + fileName, function (ex) {
  275. Object.keys(options.imageVersions).forEach(function (version) {
  276. fs.unlink(options.uploadDir + '/' + version + '/' + fileName);
  277. });
  278. handler.callback({success: !ex});
  279. });
  280. return;
  281. }
  282. }
  283. handler.callback({success: false});
  284. };
  285. if (options.ssl) {
  286. require('https').createServer(options.ssl, serve).listen(port);
  287. } else {
  288. require('http').createServer(serve).listen(port);
  289. }
  290. }(8888));