UNPKG

7.65 kBJavaScriptView Raw
1/**
2 * @license
3 * MOST Web Framework 2.0 Codename Blueshift
4 * Copyright (c) 2017, THEMOST LP All rights reserved
5 *
6 * Use of this source code is governed by an BSD-3-Clause license that can be
7 * found in the LICENSE file at https://themost.io/license
8 */
9var formidable = require('formidable');
10var _ = require('lodash');
11var TraceUtils = require('@themost/common/utils').TraceUtils;
12
13/**
14 * @class UnknownValue
15 * @constructor
16 */
17function UnknownValue() {
18 //
19}
20
21UnknownValue.prototype.valueOf = function() { return null; };
22
23UnknownValue.prototype.toJSON = function() { return null; };
24
25UnknownValue.DateTimeRegex = /^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?([+-](\d+):(\d+))?$/;
26UnknownValue.BooleanTrueRegex = /^true$/i;
27UnknownValue.BooleanFalseRegex = /^false$/i;
28UnknownValue.NullRegex = /^null$/i;
29UnknownValue.UndefinedRegex = /^undefined$/i;
30UnknownValue.IntegerRegex =/^[-+]?\d+$/;
31UnknownValue.FloatRegex =/^[+-]?\d+(\.\d+)?$/;
32/**
33 * @class UnknownPropertyDescriptor
34 * @constructor
35 */
36function UnknownPropertyDescriptor(obj, name) {
37 Object.defineProperty(this, 'value', { configurable:false, enumerable:true, get: function() { return obj[name]; }, set: function(value) { obj[name]=value; } });
38 Object.defineProperty(this, 'name', { configurable:false, enumerable:true, get: function() { return name; } });
39}
40/**
41 * @param {string} value
42 */
43UnknownValue.convert = function(value) {
44 var result;
45 if ((typeof value === 'string'))
46 {
47 if (value.length===0) {
48 result = value
49 }
50 if (value.match(UnknownValue.BooleanTrueRegex)) {
51 result = true;
52 }
53 else if (value.match(UnknownValue.BooleanFalseRegex)) {
54 result = false;
55 }
56 else if (value.match(UnknownValue.NullRegex) || value.match(UnknownValue.UndefinedRegex)) {
57 result = null;
58 }
59 else if (value.match(UnknownValue.IntegerRegex)) {
60 result = parseInt(value);
61 }
62 else if (value.match(UnknownValue.FloatRegex)) {
63 result = parseFloat(value);
64 }
65 else if (value.match(UnknownValue.DateTimeRegex)) {
66 result = new Date(Date.parse(value));
67 }
68 else {
69 result = value;
70 }
71 }
72 else {
73 result = value;
74 }
75 return result;
76};
77
78
79
80/**
81 * @class PostHandler
82 * @constructor
83 * @implements BeginRequestHandler
84 */
85function PostHandler() {
86
87}
88
89/**
90 *
91 * @param {*} origin
92 * @param {string} expr
93 * @param {string} value
94 * @param {*=} options
95 * @returns {*}
96 * @private
97 */
98function extend(origin, expr, value, options) {
99
100 options = options || { convertValues:false };
101 //find base notation
102 var match = /(^\w+)\[/.exec(expr), name, descriptor, expr1;
103 if (match) {
104 //get property name
105 name = match[1];
106 //validate array property
107 if (/^\d+$/g.test(name)) {
108 //property is an array
109 if (!_.isArray(origin.value))
110 origin.value = [];
111 // get new expression
112 expr1 = expr.substr(match.index + match[1].length);
113 extend(origin, expr1, value, options);
114 }
115 else {
116 //set property value (unknown)
117 origin[name] = origin[name] || new UnknownValue();
118 descriptor = new UnknownPropertyDescriptor(origin, name);
119 // get new expression
120 expr1 = expr.substr(match.index + match[1].length);
121 extend(descriptor, expr1, value, options);
122 }
123 }
124 else if (expr.indexOf('[')===0) {
125 //get property
126 var re = /\[(.*?)\]/g;
127 match = re.exec(expr);
128 if (match) {
129 name = match[1];
130 // get new expression
131 expr1 = expr.substr(match.index + match[0].length);
132 if (/^\d+$/g.test(name)) {
133 //property is an array
134 if (!_.isArray(origin.value))
135 origin.value = [];
136 }
137 if (expr1.length===0) {
138 if (origin.value instanceof UnknownValue) {
139 origin.value = {};
140 }
141 var typedValue;
142 //convert string value
143 if ((typeof value === 'string') && options.convertValues) {
144 typedValue = UnknownValue.convert(value);
145 }
146 else {
147 typedValue = value;
148 }
149 if (_.isArray(origin.value))
150 origin.value.push(typedValue);
151 else
152 origin.value[name] = typedValue;
153 }
154 else {
155 if (origin.value instanceof UnknownValue) {
156 origin.value = { };
157 }
158 origin.value[name] = origin.value[name] || new UnknownValue();
159 descriptor = new UnknownPropertyDescriptor(origin.value, name);
160 extend(descriptor, expr1, value, options);
161 }
162 }
163 else {
164 throw new Error('Invalid object property notation. Expected [name]');
165 }
166 }
167 else if (/^[\w-]*$/.test(expr)) {
168 if (options.convertValues)
169 origin[expr] = UnknownValue.convert(value);
170 else
171 origin[expr] = value;
172 }
173 else {
174 throw new Error('Invalid object property notation. Expected property[name] or [name]');
175 }
176 return origin;
177}
178
179/**
180 * Parses a form object and returns form parameters as object e.g. user[name]=user&user1[password]=1234 returns user: { name: 'user1', password:'1234'}
181 * @param form
182 * @private
183 */
184function parseForm(form) {
185 var result = {};
186 if (typeof form === 'undefined' || form===null)
187 return result;
188 var keys = Object.keys(form);
189 keys.forEach(function(key) {
190 if (form.hasOwnProperty(key))
191 {
192 extend(result, key, form[key]);
193 }
194 });
195 return result;
196}
197
198PostHandler.prototype.beginRequest = function(context, callback) {
199 try {
200 var request = context.request;
201 //extend params object (parse form data)
202 if (typeof request.socket === 'undefined') {
203 callback();
204 }
205 else {
206 request.headers = request.headers || {};
207 if (/^application\/x-www-form-urlencoded/i.test(request.headers['content-type'])) {
208 //use formidable to parse request data
209 var f = new formidable.IncomingForm();
210 f.parse(request, function (err, form, files) {
211 if (err) {
212 callback(err);
213 return;
214 }
215 try {
216 //add form
217 if (form) {
218 _.assign(context.params, parseForm(form));
219 }
220 //add files
221 if (files)
222 _.assign(context.params, files);
223 callback();
224 }
225 catch (e) {
226 callback(e);
227 }
228 });
229 }
230 else {
231 callback();
232 }
233
234 }
235 }
236 catch (err) {
237 TraceUtils.log(err);
238 callback(new Error("An internal server error occured while parsing request data."));
239 }
240
241};
242
243if (typeof exports !== 'undefined') {
244 exports.UnknownValue = UnknownValue;
245 exports.PostHandler = PostHandler;
246 exports.createInstance = function() {
247 return new PostHandler();
248 };
249}
\No newline at end of file