Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / log4js / lib / connect-logger.js
1 "use strict";
2 var levels = require("./levels");
3 var DEFAULT_FORMAT = ':remote-addr - -' +
4   ' ":method :url HTTP/:http-version"' +
5   ' :status :content-length ":referrer"' +
6   ' ":user-agent"';
7 /**
8  * Log requests with the given `options` or a `format` string.
9  *
10  * Options:
11  *
12  *   - `format`        Format string, see below for tokens
13  *   - `level`         A log4js levels instance. Supports also 'auto'
14  *
15  * Tokens:
16  *
17  *   - `:req[header]` ex: `:req[Accept]`
18  *   - `:res[header]` ex: `:res[Content-Length]`
19  *   - `:http-version`
20  *   - `:response-time`
21  *   - `:remote-addr`
22  *   - `:date`
23  *   - `:method`
24  *   - `:url`
25  *   - `:referrer`
26  *   - `:user-agent`
27  *   - `:status`
28  *
29  * @param {String|Function|Object} format or options
30  * @return {Function}
31  * @api public
32  */
33
34 function getLogger(logger4js, options) {
35         if ('object' == typeof options) {
36                 options = options || {};
37         } else if (options) {
38                 options = { format: options };
39         } else {
40                 options = {};
41         }
42
43         var thislogger = logger4js
44   , level = levels.toLevel(options.level, levels.INFO)
45   , fmt = options.format || DEFAULT_FORMAT
46   , nolog = options.nolog ? createNoLogCondition(options.nolog) : null;
47
48   return function (req, res, next) {
49     // mount safety
50     if (req._logging) return next();
51
52                 // nologs
53                 if (nolog && nolog.test(req.originalUrl)) return next();
54                 if (thislogger.isLevelEnabled(level) || options.level === 'auto') {
55
56                         var start = new Date()
57                         , statusCode
58                         , writeHead = res.writeHead
59                         , url = req.originalUrl;
60
61                         // flag as logging
62                         req._logging = true;
63
64                         // proxy for statusCode.
65                         res.writeHead = function(code, headers){
66                                 res.writeHead = writeHead;
67                                 res.writeHead(code, headers);
68                                 res.__statusCode = statusCode = code;
69                                 res.__headers = headers || {};
70
71                                 //status code response level handling
72                                 if(options.level === 'auto'){
73                                         level = levels.INFO;
74                                         if(code >= 300) level = levels.WARN;
75                                         if(code >= 400) level = levels.ERROR;
76                                 } else {
77                                         level = levels.toLevel(options.level, levels.INFO);
78                                 }
79                         };
80
81                         //hook on end request to emit the log entry of the HTTP request.
82                         res.on('finish', function() {
83                                 res.responseTime = new Date() - start;
84                                 //status code response level handling
85                                 if(res.statusCode && options.level === 'auto'){
86                                         level = levels.INFO;
87                                         if(res.statusCode >= 300) level = levels.WARN;
88                                         if(res.statusCode >= 400) level = levels.ERROR;
89                                 }
90                                 if (thislogger.isLevelEnabled(level)) {
91           var combined_tokens = assemble_tokens(req, res, options.tokens || []);
92                                         if (typeof fmt === 'function') {
93                                                 var line = fmt(req, res, function(str){ return format(str, combined_tokens); });
94                                                 if (line) thislogger.log(level, line);
95                                         } else {
96                                                 thislogger.log(level, format(fmt, combined_tokens));
97                                         }
98                                 }
99                         });
100                 }
101
102     //ensure next gets always called
103     next();
104   };
105 }
106
107 /**
108  * Adds custom {token, replacement} objects to defaults,
109  * overwriting the defaults if any tokens clash
110  *
111  * @param  {IncomingMessage} req
112  * @param  {ServerResponse} res
113  * @param  {Array} custom_tokens
114  *    [{ token: string-or-regexp, replacement: string-or-replace-function }]
115  * @return {Array}
116  */
117 function assemble_tokens(req, res, custom_tokens) {
118   var array_unique_tokens = function(array) {
119     var a = array.concat();
120     for(var i=0; i<a.length; ++i) {
121       for(var j=i+1; j<a.length; ++j) {
122         if(a[i].token == a[j].token) { // not === because token can be regexp object
123           a.splice(j--, 1);
124         }
125       }
126     }
127     return a;
128   };
129
130   var default_tokens = [];
131   default_tokens.push({ token: ':url', replacement: getUrl(req) });
132   default_tokens.push({ token: ':protocol', replacement: req.protocol });
133   default_tokens.push({ token: ':hostname', replacement: req.hostname });
134   default_tokens.push({ token: ':method', replacement: req.method });
135   default_tokens.push({ token: ':status', replacement: res.__statusCode || res.statusCode });
136   default_tokens.push({ token: ':response-time', replacement: res.responseTime });
137   default_tokens.push({ token: ':date', replacement: new Date().toUTCString() });
138   default_tokens.push({
139     token: ':referrer',
140     replacement: req.headers.referer || req.headers.referrer || ''
141   });
142   default_tokens.push({
143     token: ':http-version',
144     replacement: req.httpVersionMajor + '.' + req.httpVersionMinor
145   });
146   default_tokens.push({
147     token: ':remote-addr',
148     replacement:
149       req.headers['x-forwarded-for'] ||
150       req.ip ||
151       req._remoteAddress ||
152       (req.socket &&
153         (req.socket.remoteAddress ||
154           (req.socket.socket && req.socket.socket.remoteAddress)
155         )
156       )
157     }
158   );
159   default_tokens.push({ token: ':user-agent', replacement: req.headers['user-agent'] });
160   default_tokens.push({
161     token: ':content-length',
162     replacement:
163       (res._headers && res._headers['content-length']) ||
164       (res.__headers && res.__headers['Content-Length']) ||
165       '-'
166     }
167   );
168   default_tokens.push({ token: /:req\[([^\]]+)\]/g, replacement: function(_, field) {
169     return req.headers[field.toLowerCase()];
170   } });
171   default_tokens.push({ token: /:res\[([^\]]+)\]/g, replacement: function(_, field) {
172     return res._headers ?
173       (res._headers[field.toLowerCase()] || res.__headers[field])
174       : (res.__headers && res.__headers[field]);
175   } });
176
177   return array_unique_tokens(custom_tokens.concat(default_tokens));
178 }
179
180 /**
181  * Return request url path,
182  * adding this function prevents the Cyclomatic Complexity,
183  * for the assemble_tokens function at low, to pass the tests.
184  *
185  * @param  {IncomingMessage} req
186  * @return {String}
187  * @api private
188  */
189
190 function getUrl(req){
191   return req.originalUrl || req.url;
192 }
193 /**
194  * Return formatted log line.
195  *
196  * @param  {String} str
197  * @param  {IncomingMessage} req
198  * @param  {ServerResponse} res
199  * @return {String}
200  * @api private
201  */
202
203 function format(str, tokens) {
204   for (var i = 0; i < tokens.length; i++) {
205     str = str.replace(tokens[i].token, tokens[i].replacement);
206   }
207   return str;
208 }
209
210 /**
211  * Return RegExp Object about nolog
212  *
213  * @param  {String} nolog
214  * @return {RegExp}
215  * @api private
216  *
217  * syntax
218  *  1. String
219  *   1.1 "\\.gif"
220  *         NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.gif?fuga
221  *         LOGGING http://example.com/hoge.agif
222  *   1.2 in "\\.gif|\\.jpg$"
223  *         NOT LOGGING http://example.com/hoge.gif and
224  *           http://example.com/hoge.gif?fuga and http://example.com/hoge.jpg?fuga
225  *         LOGGING http://example.com/hoge.agif,
226  *           http://example.com/hoge.ajpg and http://example.com/hoge.jpg?hoge
227  *   1.3 in "\\.(gif|jpe?g|png)$"
228  *         NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.jpeg
229  *         LOGGING http://example.com/hoge.gif?uid=2 and http://example.com/hoge.jpg?pid=3
230  *  2. RegExp
231  *   2.1 in /\.(gif|jpe?g|png)$/
232  *         SAME AS 1.3
233  *  3. Array
234  *   3.1 ["\\.jpg$", "\\.png", "\\.gif"]
235  *         SAME AS "\\.jpg|\\.png|\\.gif"
236  */
237 function createNoLogCondition(nolog) {
238   var regexp = null;
239
240         if (nolog) {
241     if (nolog instanceof RegExp) {
242       regexp = nolog;
243     }
244
245     if (typeof nolog === 'string') {
246       regexp = new RegExp(nolog);
247     }
248
249     if (Array.isArray(nolog)) {
250       var regexpsAsStrings = nolog.map(
251         function convertToStrings(o) {
252           return o.source ? o.source : o;
253         }
254       );
255       regexp = new RegExp(regexpsAsStrings.join('|'));
256     }
257   }
258
259   return regexp;
260 }
261
262 exports.connectLogger = getLogger;