-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
183 lines (150 loc) · 6.11 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//
// NewsWatcher application
//
//
// "require" statements to bring in needed Node Modules
// mongodb://bzappasodi:megastar12@ds031915.mlab.com:31915/newswatcherdb
var express = require('express'); // For route handlers and templates to serve up.
var path = require('path'); // Populating the path property of the request
var logger = require('morgan'); // HTTP request logging
var bodyParser = require('body-parser'); // Easy access to the HTTP request body
var cp = require('child_process'); // Forking a separate Node.js processes
var responseTime = require('response-time'); // For code timing checks for performance logging
var assert = require('assert'); // assert testing of values
var helmet = require('helmet'); // Helmet module for HTTP header hack mitigations
var RateLimit = require('express-rate-limit'); // IP based rate limiter
var config = require('./config');
var users = require('./routes/users');
var session = require('./routes/session');
var sharedNews = require('./routes/sharedNews');
var app = express();
app.enable('trust proxy'); // Since we are behind Nginx load balancing with Elastic Beanstalk
var limiter = new RateLimit({
windowMs: 15*60*1000, // 15 minutes
max: 200, // limit each IP to 100 requests per windowMs
delayMs: 0 // disable delaying - full speed until the max limit is reached
});
// apply to all requests
app.use(limiter);
app.use(helmet()); // Take the defaults to start with
app.use(helmet.csp({
// Specify directives for content sources
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", 'ajax.googleapis.com', 'maxcdn.bootstrapcdn.com'],
styleSrc: ["'self'", "'unsafe-inline'", 'maxcdn.bootstrapcdn.com'],
fontSrc: ["'self'", 'maxcdn.bootstrapcdn.com'],
imgSrc: ['*']
// reportUri: '/report-violation',
}
}));
//app.use(helmet.noCache());
// Adds an X-Response-Time header to responses to measure response times
app.use(responseTime());
// logs all HTTP requests. The "dev" option gives it a specific styling
app.use(logger('dev'));
// Sets up the response object in routes to contain a body property with an object of what is parsed from a JSON body request payload
// There is no need for allowing a huge body, it might be some type of attack, so use the limit option
app.use(bodyParser.json({ limit: '100kb' }));
// This middleware takes any query string key/value pairs and sticks them in the body property
//app.use(bodyParser.urlencoded({ extended: false }));
// Simplifies the serving up of static content such as HTML, images, CSS files, and JavaScript files
app.use(express.static(path.join(__dirname, 'static')));
//
// Fire up the child process that will run in a separate machine core
// and do some background processing. This way, this master process can
// be freed up to keep processing to a minimum on its servicing threads.
var node2 = cp.fork('./worker/app_FORK.js', [], { execArgv: ['--debug=5859'] });
//var node2 = cp.fork('./worker/app_FORK.js');
// node2.on('message', function (m) {
// console.log('PARENT got message:', m);
// });
// node2.send({ hello: 'Forked world' });
//
// MongoDB database connection initialization
//
var db = {};
var MongoClient = require('mongodb').MongoClient;
//Use connect method to connect to the Server
MongoClient.connect(config.MONGODB_CONNECT_URL, function(err, dbConn) {
assert.equal(null, err);
db.dbConnection = dbConn;
db.collection = dbConn.collection('newswatcher');
console.log("Connected to MongoDB server");
});
process.on('SIGINT', function() {
console.log('MongoDB connection close on app termination');
db.dbConnection.close();
process.exit(0);
});
process.on('SIGUSR2', function() {
console.log('MongoDB connection close on app restart');
db.dbConnection.close();
process.kill(process.pid, 'SIGUSR2');
});
app.use(function(req, res, next) {
req.db = db;
req.node2 = node2;
next();
});
// For loading the default HTML page that acts as the SPA Web site
app.get('/', function(req, res) {
res.render('index.html')
});
//
// Rest API routes
app.use('/api/users', users);
app.use('/api/sessions', session);
app.use('/api/sharednews', sharedNews);
//
// Code for running CPU profiling and also memory heap dumps to help find memory leaks
// package.json -> "v8-profiler": "^5.5.0"
// var fs = require('fs');
// var profiler = require('v8-profiler');
// app.post('/testing/startcpuprofile', function(req, res) {
// profiler.startProfiling();
// res.status(201).json({ msg: 'CPU profile started' });
// });
// app.post('/testing/stopcpuprofile', function(req, res) {
// var profileResult = profiler.stopProfiling();
// profileResult.export()
// .pipe(fs.createWriteStream('profile.cpuprofile'))
// .on('finish', function() {
// profileResult.delete();
// });
// res.status(201).json({ msg: 'CPU profile stopped' });
// });
// var snapCount = 0;
// app.post('/testing/takeheapsnapshot', function(req, res) {
// var snapshot = profiler.takeSnapshot();
// snapshot.export()
// .pipe(fs.createWriteStream('snap' + snapCount + '.heapsnapshot'))
// .on('finish', snapshot.delete);
// snapCount++;
// res.status(201).json({ msg: 'Memory HEAP snapshop taken' });
// });
//
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// development error handler that will add in a stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500).json({ message: err.toString(), error: err });
console.log(err);
});
}
// production error handler with no stacktraces exposed to users
app.use(function(err, req, res, next) {
res.status(err.status || 500).json({ message: err.toString(), error: {} });
console.log(err);
});
app.set('port', process.env.PORT || 3000);
//var debug = require('debug')('NewsWatcher');
var server = app.listen(app.get('port'), function() {
//debug('Express server listening on port ' + server.address().port);
console.log('Express server listening on port ' + server.address().port);
});