topbit 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +128 -0
  2. package/README.cn.md +1562 -0
  3. package/README.md +1272 -0
  4. package/bin/app.js +17 -0
  5. package/bin/loadinfo.sh +18 -0
  6. package/bin/new-ctl.js +230 -0
  7. package/bin/newapp.js +22 -0
  8. package/cache/allow.js +130 -0
  9. package/cache/errserv.js +45 -0
  10. package/cache/minserv.js +167 -0
  11. package/cache/router.js +84 -0
  12. package/cache/rsa/localhost-cert.pem +19 -0
  13. package/cache/rsa/localhost-privkey.pem +28 -0
  14. package/cache/servsock.js +286 -0
  15. package/cache/sni.js +66 -0
  16. package/demo/allow.js +98 -0
  17. package/demo/group-api.js +161 -0
  18. package/demo/group-api2.js +109 -0
  19. package/demo/log.js +118 -0
  20. package/demo/memlimit.js +31 -0
  21. package/demo/min.js +7 -0
  22. package/demo/serv.js +15 -0
  23. package/images/middleware.jpg +0 -0
  24. package/images/titbit-middleware.png +0 -0
  25. package/images/titbit.png +0 -0
  26. package/package.json +38 -8
  27. package/src/bodyparser.js +420 -0
  28. package/src/connfilter.js +125 -0
  29. package/src/context1.js +166 -0
  30. package/src/context2.js +179 -0
  31. package/src/ctxpool.js +38 -0
  32. package/src/ext.js +318 -0
  33. package/src/fastParseUrl.js +426 -0
  34. package/src/headerLimit.js +18 -0
  35. package/src/http1.js +337 -0
  36. package/src/http2.js +337 -0
  37. package/src/httpc.js +251 -0
  38. package/src/loader/loader.js +999 -0
  39. package/src/logger.js +32 -0
  40. package/src/loggermsg.js +349 -0
  41. package/src/makeId.js +200 -0
  42. package/src/midcore.js +213 -0
  43. package/src/middleware1.js +104 -0
  44. package/src/middleware2.js +121 -0
  45. package/src/monitor.js +380 -0
  46. package/src/movefile.js +30 -0
  47. package/src/optionsCheck.js +54 -0
  48. package/src/randstring.js +23 -0
  49. package/src/router.js +682 -0
  50. package/src/sendmsg.js +27 -0
  51. package/src/strong.js +72 -0
  52. package/src/token/token.js +462 -0
  53. package/src/topbit.js +1291 -0
  54. package/src/versionCheck.js +31 -0
  55. package/test/test-bigctx.js +29 -0
  56. package/test/test-daemon-args.js +7 -0
  57. package/test/test-find.js +69 -0
  58. package/test/test-helper.js +81 -0
  59. package/test/test-route-sort.js +71 -0
  60. package/test/test-route.js +49 -0
  61. package/test/test-route2.js +51 -0
  62. package/test/test-run-args.js +7 -0
  63. package/test/test-url.js +52 -0
  64. package/tmp/buff-code +134 -0
  65. package/tmp/devplan +9 -0
  66. package/tmp/evt-test.js +34 -0
  67. package/tmp/fastParseUrl.js +302 -0
  68. package/tmp/router-rule.js +559 -0
  69. package/tmp/test-cdps.js +122 -0
  70. package/tmp/titbit.js +1286 -0
  71. package/main.js +0 -0
@@ -0,0 +1,559 @@
1
+ 'use strict';
2
+
3
+ let RULE_REGEXP = 1
4
+ let RULE_ARRAY = 2
5
+
6
+ class router {
7
+
8
+ constructor (options = {}) {
9
+ this.ignoreSlash = true;
10
+
11
+ this.maxPath = 1024;
12
+
13
+ this.count = 0;
14
+
15
+ this.apiTable = {
16
+ GET : {},
17
+ POST : {},
18
+ PUT : {},
19
+ DELETE : {},
20
+ OPTIONS : {},
21
+ HEAD : {},
22
+ PATCH : {},
23
+ TRACE : {}
24
+ };
25
+
26
+ /**
27
+ * 2020.7.31 优化方案:
28
+ * 通过数组记录每个类型带参数请求的路由,这样可以直接遍历。
29
+ * */
30
+ this.argsRoute = {
31
+ GET : [],
32
+ POST : [],
33
+ PUT : [],
34
+ DELETE : [],
35
+ OPTIONS : [],
36
+ HEAD : [],
37
+ PATCH : [],
38
+ TRACE : []
39
+ };
40
+
41
+ this.methods = Object.keys(this.apiTable);
42
+
43
+ //记录api的分组,只有在分组内的路径才会去处理,
44
+ //这是为了避免不是通过分组添加但是仍然使用和分组相同前缀的路由也被当作分组内路由处理。
45
+ this.apiGroup = {};
46
+
47
+ this.nameTable = {};
48
+
49
+ if (options.ignoreSlash !== undefined) {
50
+ this.ignoreSlash = options.ignoreSlash;
51
+ }
52
+
53
+ this.path_preg = /^[a-z0-9_\-\/\:\*\.\@]{1,500}$/i;
54
+ }
55
+
56
+ fmtArgsString (p) {
57
+ let arr = [];
58
+ let count = 1;
59
+ for (let a of p.routeArr) {
60
+ if (a[0] === ':') {
61
+ arr.push(':x' + count);
62
+ count++;
63
+ } else {
64
+ arr.push(a);
65
+ }
66
+ }
67
+ return arr.join('/');
68
+ }
69
+
70
+ compareArgsPath(a, b) {
71
+ return this.fmtArgsString(a) === this.fmtArgsString(b);
72
+ }
73
+
74
+ conflictCheck (p, path, method) {
75
+ let routes = this.apiTable[method];
76
+ if (routes.length === 0 || !p.isArgs) return true;
77
+
78
+ let r
79
+ for (let k in routes) {
80
+ r = routes[k]
81
+ if (!r.isArgs || r.routeArr.length !== p.routeArr.length) continue;
82
+
83
+ if (this.compareArgsPath(r, p)) {
84
+ console.error(`\x1b[7;31;47mError: ${method} ${path} 和已有路由 ${k} 模式冲突。 \x1b[0m\n`);
85
+ throw new Error(`${path} 和 ${k}模式一致,存在冲突。`);
86
+ }
87
+ }
88
+
89
+ return true;
90
+ }
91
+
92
+ //检查路由参数的规则限制
93
+ checkRule(p) {
94
+ if (!p.rule) return true
95
+ if (typeof p.rule !== 'object') {
96
+ p.rule = null
97
+ return false
98
+ }
99
+
100
+ if (p.isArgs) {
101
+ for (let a of p.routePath) {
102
+ if (!a.isArgs) continue
103
+
104
+ if (!p.rule[a.name]) continue
105
+
106
+ if (p.rule[a.name] instanceof RegExp) {
107
+ a.hasRule = true
108
+ a.ruleType = RULE_REGEXP
109
+ }
110
+ else if (Array.isArray(p.rule[a.name])) {
111
+ a.hasRule = true
112
+ a.ruleType = RULE_ARRAY
113
+ p.rule[a.name].__htable__ = {}
114
+ for (let k of p.rule[a.name]) {
115
+ p.rule[a.name].__htable__[k] = true
116
+ }
117
+ }
118
+ }
119
+ } else {
120
+ //*路由只有一个参数,所以直接验证数据类型即可
121
+ p.ruleType = null
122
+ p.hasRule = false
123
+ if (p.rule instanceof RegExp) {
124
+ p.hasRule = true
125
+ p.ruleType = RULE_REGEXP
126
+ } else if (Array.isArray(p.rule)) {
127
+ p.hasRule = true
128
+ p.ruleType = RULE_ARRAY
129
+ p.__htable__ = {}
130
+ for (let k of p.rule) {
131
+ p.__htable__[k] = true
132
+ }
133
+ }
134
+
135
+ }
136
+
137
+ return true
138
+ }
139
+
140
+ //预解析路由参数并记录,保证查找的性能
141
+ parsePathParam (p, path, method) {
142
+ if (p.isArgs) {
143
+ //记录参数名称映射,不必在匹配时进行substring
144
+ for (let i = 0; i < p.routeArr.length; i++) {
145
+ p.routePath.push({
146
+ path: p.routeArr[i],
147
+ isArgs: p.routeArr[i][0] === ':',
148
+ name: p.routeArr[i][0] === ':' ? p.routeArr[i].substring(1) : p.routeArr[i],
149
+ hasRule: false
150
+ });
151
+
152
+ if (p.routeArr[i][0] != ':') {
153
+ continue;
154
+ }
155
+
156
+ if (p.routeArr[i].length < 2) {
157
+ throw new Error(`${path} : 参数不能没有名称,请在:后添加名称`);
158
+ }
159
+ }
160
+ this.conflictCheck(p, path, method);
161
+ } else {
162
+ let starCount = 0;
163
+ for (let i = 0; i < path.length; i++) {
164
+ if (path[i] == '*') {
165
+ starCount += 1;
166
+ }
167
+ }
168
+ if (starCount > 1) {
169
+ throw new Error(`${path} : 多个 * 导致冲突`);
170
+ }
171
+ p.starPrePath = path.substring(0, path.length - 1);
172
+ p.starLength = p.starPrePath.length;
173
+ for (let i = 0; i < p.routeArr.length; i++) {
174
+ p.routePath.push({path: p.routeArr[i], isStar: p.routeArr[i] === '*'})
175
+ }
176
+ }
177
+
178
+ this.checkRule(p);
179
+ }
180
+
181
+ /*
182
+ 由于在路由匹配时会使用/分割路径,所以在添加路由时先处理好。
183
+ 允许:表示变量,*表示任何路由,但是二者不能共存,因为无法知道后面的是变量还是路由。
184
+ 比如:/static/*可以作为静态文件所在目录,但是后面的就直接作为*表示的路径,
185
+ 并不进行参数解析。
186
+ */
187
+ /**
188
+ * @param {string} path 路由字符串
189
+ * @param {string} method 请求方法类型
190
+ * @param {function} callback 执行请求的回调函数
191
+ * @param {string} name 请求名称,可以不填写
192
+ * @param {string|bool} group 路由归为哪一组,可以是字符串,
193
+ * 或者是bool值true表示使用/分割的第一个字符串。
194
+ */
195
+ addPath (path, method, callback, name = '') {
196
+ if (typeof callback !== 'function' || callback.constructor.name !== 'AsyncFunction')
197
+ {
198
+ throw new Error(`${method} ${path}: 回调函数必须使用async声明`);
199
+ }
200
+
201
+ let api_path = path.trim()
202
+ if (api_path === '') {
203
+ api_path = '/';
204
+ }
205
+
206
+ if (!this.path_preg.test(api_path)) {
207
+ throw new Error(`路由字符串 ${path} 存在非法字符,路由字符串允许 字母 数字 - _ : * /\n`);
208
+ }
209
+
210
+ if (api_path[0] !== '/') { api_path = `/${api_path}`; }
211
+
212
+ if (api_path.length > 1 && api_path[api_path.length-1] == '/' && this.ignoreSlash) {
213
+ api_path = api_path.substring(0, api_path.length-1);
214
+ }
215
+
216
+ let group = '';
217
+ let rule = null;
218
+ if (typeof name === 'object') {
219
+ if (name.rule !== undefined) rule = name.rule;
220
+
221
+ if (name.group !==undefined) {
222
+ group = name.group;
223
+ }
224
+ if (name.name !== undefined) {
225
+ name = name.name;
226
+ } else {
227
+ name = '';
228
+ }
229
+
230
+ } else if (typeof name === 'string') {
231
+ if (name.length > 1 && name[0] == '@') {
232
+ group = name.substring(1);
233
+ name = '';
234
+ }
235
+ } else {
236
+ name = '';
237
+ }
238
+
239
+ let add_req = {
240
+ isArgs: false,
241
+ isStar: false,
242
+ routeArr: [],
243
+ routePath: [],
244
+ starPrePath : '',
245
+ starLength : 0,
246
+ reqCall: callback,
247
+ name : name,
248
+ group : '',
249
+ path: api_path,
250
+ rule: rule
251
+ };
252
+
253
+ if (api_path.indexOf(':') >= 0) {
254
+ add_req.isArgs = true;
255
+ }
256
+
257
+ if (api_path.indexOf('*') >= 0) {
258
+ add_req.isStar = true;
259
+ if (api_path[api_path.length - 1] != '*') {
260
+ throw new Error(`${api_path} : 任意匹配参数 * 只能出现在最后`);
261
+ }
262
+ }
263
+
264
+ if (add_req.isStar && add_req.isArgs) {
265
+ console.error(`\x1b[7;31;47mError: path中 : 和 * 不能同时出现 \x1b[0m\n`);
266
+ throw new Error(`${api_path} 参数 : 和 * 不能同时出现`);
267
+ }
268
+
269
+ if (name !== '' && this.nameTable[name]) {
270
+ throw new Error(`路由命名${name} 已经存在。`);
271
+ }
272
+
273
+ add_req.routeArr = api_path.split('/').filter(p => p.length > 0);
274
+ if(typeof group === 'string' && group.length > 0) {
275
+ add_req.group = group;
276
+ }
277
+
278
+ if (add_req.isArgs || add_req.isStar) {
279
+ this.parsePathParam(add_req, api_path, method);
280
+ }
281
+
282
+ if (add_req.group !== '') {
283
+ if (this.apiGroup[add_req.group] === undefined) {
284
+ this.apiGroup[add_req.group] = [];
285
+ }
286
+ this.apiGroup[add_req.group].push({
287
+ method: method,
288
+ path: api_path
289
+ });
290
+ }
291
+
292
+ if (this.methods.indexOf(method) >= 0) {
293
+ if (this.apiTable[method][api_path]) {
294
+ throw new Error(`${api_path}冲突,多次添加`);
295
+ }
296
+
297
+ this.count += 1;
298
+
299
+ this.apiTable[method][api_path] = add_req;
300
+ if (name.length > 0) {
301
+ this.nameTable[name] = api_path;
302
+ }
303
+ //记录带参数路由
304
+ if (add_req.isArgs || add_req.isStar) {
305
+ this.argsRoute[method].push(add_req);
306
+ }
307
+ }
308
+ }
309
+
310
+ get (api_path, callback, name='') {
311
+ this.addPath(api_path, 'GET', callback, name);
312
+ }
313
+
314
+ post (api_path, callback, name='') {
315
+ this.addPath(api_path, 'POST', callback, name);
316
+ }
317
+
318
+ put (api_path, callback, name='') {
319
+ this.addPath(api_path, 'PUT', callback, name);
320
+ }
321
+
322
+ delete (api_path, callback, name='') {
323
+ this.addPath(api_path, 'DELETE', callback, name);
324
+ }
325
+
326
+ options (api_path, callback, name = '') {
327
+ this.addPath(api_path, 'OPTIONS', callback, name);
328
+ }
329
+
330
+ patch (api_path, callback, name = '') {
331
+ this.addPath(api_path, 'PATCH', callback, name);
332
+ }
333
+
334
+ head (api_path, callback, name = '') {
335
+ this.addPath(api_path, 'HEAD', callback, name);
336
+ }
337
+
338
+ trace (api_path, callback, name = '') {
339
+ this.addPath(api_path, 'TRACE', callback, name);
340
+ }
341
+
342
+ /**
343
+ * @param [array] marr method数组,示例['GET','HEAD']。
344
+ * @param {string} api_path 路由字符串。
345
+ * @param {function} callback 请求处理回调函数,必须是async声明。
346
+ * @param {string} name 请求命名,默认为空字符串,可以不写。
347
+ * */
348
+ map (marr, api_path, callback, name='') {
349
+ for(let i = 0; i < marr.length; i++) {
350
+ this.addPath(api_path, marr[i], callback, name);
351
+ }
352
+ }
353
+
354
+ any (api_path, callback, name='') {
355
+ this.map(this.methods, api_path, callback, name);
356
+ }
357
+
358
+ group () {
359
+ return this.apiGroup;
360
+ }
361
+
362
+ routeTable () {
363
+ return this.apiTable;
364
+ }
365
+
366
+ /** 清理路由表等 */
367
+ clear() {
368
+ for(let k in this.apiTable) {
369
+ this.apiTable[k] = {};
370
+ this.argsRoute[k] = [];
371
+ }
372
+ this.apiGroup = {};
373
+ this.nameTable = {};
374
+ }
375
+
376
+ /**
377
+ * 输出路由表
378
+ */
379
+ printTable() {
380
+ console.log(this.getTable());
381
+ }
382
+
383
+ getTable () {
384
+ let rtext = '';
385
+ let ptmp = '';
386
+
387
+ for (let k in this.apiTable) {
388
+ for (let p in this.apiTable[k]) {
389
+ ptmp = `${k} `;
390
+ rtext += `${ptmp.substring(0,8)} ---- ${p}\n`;
391
+ }
392
+ }
393
+ return rtext;
394
+ }
395
+
396
+ /**
397
+ * findPath只是用来查找带参数的路由。
398
+ * @param {string} path 路由字符串。
399
+ * @param {string} method 请求类型。
400
+ */
401
+ findPath (path, method) {
402
+ if (!this.apiTable[method]) {
403
+ return null;
404
+ }
405
+
406
+ let path_split = path.split('/').filter(p => p.length > 0);
407
+ if (path_split.length > 9) {
408
+ return null;
409
+ }
410
+
411
+ let next = 0;
412
+ let args = {};
413
+ let r = null;
414
+ let margs = this.argsRoute[method];
415
+ let alength = margs.length;
416
+ let cur_path;
417
+
418
+ for (let i=0; i < alength; i++) {
419
+ r = margs[i];
420
+
421
+ if ( (r.routePath.length !== path_split.length && r.isStar === false)
422
+ || (r.isStar && r.routePath.length > path_split.length+1) )
423
+ {
424
+ continue;
425
+ }
426
+
427
+ next = false;
428
+
429
+ if (r.isStar) {
430
+ for (let i = 0; i < r.routePath.length; i++) {
431
+ cur_path = r.routePath[i];
432
+ if(!cur_path.isStar && cur_path.path !== path_split[i]) {
433
+ next = true;
434
+ break;
435
+ }
436
+ }
437
+
438
+ if (!next) {
439
+ args.starPath = path.substring(r.starLength);
440
+
441
+ if (r.hasRule) {
442
+ if (r.ruleType === RULE_ARRAY) {
443
+ if (!r.__htable__[args.starPath]) {
444
+ next = true;
445
+ break;
446
+ }
447
+ } else {
448
+ if (!r.rule.test(args.starPath)) {
449
+ next = true;
450
+ break;
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ } else {
457
+ for (let i=0; i < r.routePath.length; i++) {
458
+ cur_path = r.routePath[i];
459
+ if (!cur_path.isArgs && cur_path.path !== path_split[i]) {
460
+ next = true;
461
+ break;
462
+ }
463
+ }
464
+ //如果next为false,则表示匹配成功,此时解析出所有的参数。
465
+ if (!next) {
466
+ for (let i=0; i < r.routePath.length; i++) {
467
+ cur_path = r.routePath[i];
468
+ if (cur_path.isArgs) {
469
+ if (cur_path.hasRule) {
470
+ //console.log('check rule: ', cur_path.name)
471
+ if (cur_path.ruleType === RULE_ARRAY) {
472
+ if (!r.rule[cur_path.name].__htable__[path_split[i]]) {
473
+ next = true;
474
+ break;
475
+ }
476
+ } else {
477
+ if (!r.rule[cur_path.name].test(path_split[i])) {
478
+ next = true;
479
+ break;
480
+ }
481
+ }
482
+ }
483
+ //console.log('--ok')
484
+ args[ cur_path.name ] = path_split[i];
485
+ }
486
+ }
487
+ }
488
+
489
+ } // end else
490
+
491
+ if (next) continue;
492
+
493
+ return {key: r.path, args: args};
494
+ }
495
+ return null;
496
+ }
497
+
498
+ /**
499
+ *
500
+ * @param {string} path
501
+ * @param {string} method
502
+ */
503
+ findRealPath (path, method) {
504
+
505
+ if (path.length > this.maxPath) {
506
+ return null;
507
+ }
508
+
509
+ if (this.apiTable[method] === undefined) {
510
+ return null;
511
+ }
512
+
513
+ let route_path = null;
514
+
515
+ if (this.ignoreSlash && path.length > 1 && path[path.length-1] === '/') {
516
+ path = path.substring(0, path.length-1);
517
+ }
518
+
519
+ let mp = this.apiTable[method][path];
520
+
521
+ if (mp !== undefined) {
522
+ route_path = path;
523
+ }
524
+
525
+ if (route_path && (mp.isArgs || mp.isStar) ) {
526
+ route_path = null;
527
+ }
528
+
529
+ let parg = null;
530
+ if (route_path === null) {
531
+ parg = this.findPath(path, method);
532
+ } else {
533
+ parg = {args : {}, key: route_path};
534
+ }
535
+
536
+ if (parg !== null) {
537
+ parg.reqcall = this.apiTable[method][parg.key];
538
+ }
539
+
540
+ return parg;
541
+ }
542
+
543
+ }
544
+
545
+ module.exports = router;
546
+
547
+ /* setPre(pre) {
548
+ if (pre.trim().length > 0 && pre != '/') {
549
+ pre = pre.trim();
550
+ if (pre[0] != '/') {
551
+ pre = `/${pre}`;
552
+ }
553
+ if (pre[ pre.length-1 ] == '/') {
554
+ pre = pre.substring(0, pre.length-1);
555
+ }
556
+
557
+ this.pre = pre;
558
+ }
559
+ } */
@@ -0,0 +1,122 @@
1
+ 'use strict'
2
+ let flength = 'form-data'.length
3
+
4
+ function parse_cdps(cdps) {
5
+ let rk = flength
6
+ if (cdps.substring(0, rk) !== 'form-data') return false;
7
+ while (cdps[rk] === ';' || cdps[rk] === ' ')rk++
8
+ let cdpobj = {};
9
+ let statestr = cdps.substring(rk)
10
+ let cstart=0, i,k,q='';
11
+ let cindex = 0;
12
+
13
+ let state_length = statestr.length
14
+
15
+ while(cindex < state_length) {
16
+ cindex = statestr.indexOf('=', cindex)
17
+ if (cindex < 0) break
18
+
19
+ i = cindex + 1
20
+ while (statestr[i] === ' ') i++
21
+
22
+ q = statestr[i]
23
+
24
+ if (q === ';') {
25
+ k = i
26
+ //name= 说明没有数据的值
27
+ cdpobj[statestr.substring(cstart, cindex)] = ''
28
+ k++
29
+ } else if (q) {
30
+ if (q === '"' || q === "'") {
31
+ i++
32
+ } else {q = ''}
33
+ k = i
34
+ while (k < state_length) {
35
+ if (statestr[k] === '\\') k+=2
36
+
37
+ if ((!q && statestr[k] === ';') || (q && statestr[k] === q)) {
38
+ cdpobj[statestr.substring(cstart, cindex)] = statestr.substring(i, k)
39
+ k++
40
+ break
41
+ }
42
+ k++
43
+ }
44
+ if (k === state_length){
45
+ cdpobj[statestr.substring(cstart, cindex)] = statestr.substring(i, k)
46
+ }
47
+ } else if (!q) break
48
+
49
+ cindex = k
50
+ while (cindex < state_length && (statestr[cindex] === ' ' || statestr[cindex] === ';')) {
51
+ cindex++
52
+ }
53
+
54
+ cstart = cindex
55
+ }
56
+
57
+ return cdpobj
58
+ }
59
+
60
+ let bodyparser = require('../lib/bodyparser')
61
+
62
+ let bp = new bodyparser()
63
+
64
+ let arr = [
65
+ 'form-data; name="image"; filename="oko.jpg"',
66
+ 'form-data; name="file;image"; filename="ako.jpg;a.jpg"',
67
+ `form-data; name="file;image"; filename='ako.jpg;a.jpg'`,
68
+ 'form-data name="file;image"; filename="ako.jpg;a.jpg"',
69
+ 'form-data; name=file;image; filename="ako.jpg;a.jpg',
70
+ 'form-data; name=file;image; filename="ako.jpg;a.jpg";',
71
+ 'form-data; name="file;image";;; filename="ako.jpg;a.jpg"=;; = 123',
72
+ 'form-data;;; name=file;image = ;;;; filename = "ako.jpg;a.jpg',
73
+ 'form-data;;; name=file;image = ;;;; filename == = "ako.jpg;a.jpg',
74
+ `form-data;;; name="^**&**)\\""""""'''""";filename = "ako.jpg;a.jpg`,
75
+ `form-data;;;; dsdsf;df;ew;few;few;fewf;ewf=11;filename=`,
76
+ `form-data;;;; name="filename=%22"; filename="name=;;;;;(()((*&(*^&^&^\\\\'"`,
77
+ `form-data;;;; name='''''''''';;;;`,
78
+ `form-data;;;;;;; a=12 ;;;wqwqr;; xxx =====1`,
79
+ `form-data; ======;=123=;=;=;\"qwdqwd""="qqf";\"fqwf=qd';=;=;;;;====123;23;1232`,
80
+ `form-data; ======;a"===";x;"y;y z " = "123"`,
81
+ `form-data; ======''''''s;;;sd;f;ef;w;;12;1e21-e12e==q;dqw;e`,
82
+ `form-data; fhiefhewiufiuewfoiuewfoewjfoiewfjoi;;;;;name=''''';;;;filename=ffff''`,
83
+ `form-data; - = 123; = = =; = 123; wefwe=f`
84
+ ]
85
+
86
+ arr.forEach(x => {
87
+ console.log(x)
88
+ console.log(bp.parseFormData(x), '\n')
89
+ })
90
+
91
+ for (let i = 0; i < 15; i++) {
92
+ arr = arr.concat(arr)
93
+ }
94
+
95
+ console.log(arr.length)
96
+ console.log(bp.parseFormData('form-data; name=\'file;image;\' filename="ako.jpg;a.jpg";'))
97
+
98
+ let oo = 0
99
+
100
+ console.time('cdps')
101
+ arr.forEach(x => {
102
+ oo = bp.parseFormData(x)
103
+ })
104
+ console.timeEnd('cdps')
105
+
106
+ console.time('cdpss')
107
+ arr.forEach(x => {
108
+ let dlist = x.split(';')
109
+ let ind = 0
110
+ let curobj = {}
111
+ let cstr
112
+ for (let a of dlist) {
113
+ ind = a.indexOf('=')
114
+ if (ind < 0) continue
115
+ cstr = a.substring(ind+1).trim()
116
+ curobj[a.substring(0, ind).trim()] = cstr.substring(1, cstr.length-1)
117
+ }
118
+ /* console.log(x, '\n')
119
+ console.log(parse_cdps(x))
120
+ console.log('\n\n') */
121
+ })
122
+ console.timeEnd('cdpss')