1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 12:52:42 +01:00

Make the Aphlict server more resilient.

Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.

Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.

Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.

**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:

    $ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'

[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>

SyntaxError: Unexpected end of input
>>> Server exited!
```

**After**
(No output... the bad JSON is caught and a 400 is returned)

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: epriestley, Korvin

Maniphest Tasks: T4324, T5284

Differential Revision: https://secure.phabricator.com/D9480
This commit is contained in:
Joshua Spence 2014-06-11 10:16:31 -07:00 committed by epriestley
parent bb06e36986
commit ab4324148a
10 changed files with 65 additions and 62 deletions

View file

@ -476,7 +476,7 @@ return array(
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '6e8cefa4',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
'rsrc/swf/aphlict.swf' => 'b7c2d7aa',
'rsrc/swf/aphlict.swf' => 'f45c3edc',
),
'symbols' =>
array(

View file

@ -176,10 +176,8 @@ final class PhabricatorFeedStoryPublisher {
private function sendNotification($chrono_key) {
$data = array(
'data' => array(
'key' => (string)$chrono_key,
'type' => 'notification',
),
'key' => (string)$chrono_key,
'type' => 'notification',
'subscribers' => $this->subscribedPHIDs,
);

View file

@ -2,7 +2,7 @@
final class PhabricatorNotificationClient {
const EXPECT_VERSION = 5;
const EXPECT_VERSION = 6;
public static function getServerStatus() {
$uri = PhabricatorEnv::getEnvConfig('notification.server-uri');

View file

@ -25,10 +25,10 @@ if (config.logfile) {
function parse_command_line_arguments(argv) {
var config = {
port : 22280,
admin : 22281,
host : '127.0.0.1',
user : null,
port: 22280,
admin: 22281,
host: '127.0.0.1',
user: null,
log: '/var/log/aphlict.log'
};
@ -36,10 +36,10 @@ function parse_command_line_arguments(argv) {
var arg = argv[ii];
var matches = arg.match(/^--([^=]+)=(.*)$/);
if (!matches) {
throw new Error("Unknown argument '"+arg+"'!");
throw new Error("Unknown argument '" + arg + "'!");
}
if (!(matches[1] in config)) {
throw new Error("Unknown argument '"+matches[1]+"'!");
throw new Error("Unknown argument '" + matches[1] + "'!");
}
config[matches[1]] = matches[2];
}
@ -52,19 +52,19 @@ function parse_command_line_arguments(argv) {
if (process.getuid() !== 0) {
console.log(
"ERROR: "+
"This server must be run as root because it needs to bind to privileged "+
"port 843 to start a Flash policy server. It will downgrade to run as a "+
"less-privileged user after binding if you pass a user in the command "+
"ERROR: " +
"This server must be run as root because it needs to bind to privileged " +
"port 843 to start a Flash policy server. It will downgrade to run as a " +
"less-privileged user after binding if you pass a user in the command " +
"line arguments with '--user=alincoln'.");
process.exit(1);
}
var net = require('net');
var http = require('http');
var http = require('http');
var url = require('url');
process.on('uncaughtException', function (err) {
process.on('uncaughtException', function(err) {
debug.log("\n<<< UNCAUGHT EXCEPTION! >>>\n\n" + err);
process.exit(1);
});
@ -95,7 +95,7 @@ var send_server = net.createServer(function(socket) {
debug.log('<%s> Ended Connection', listener.getDescription());
});
socket.on('error', function (e) {
socket.on('error', function(e) {
debug.log('<%s> Error: %s', listener.getDescription(), e);
});
@ -107,23 +107,29 @@ var messages_in = 0;
var start_time = new Date().getTime();
var receive_server = http.createServer(function(request, response) {
response.writeHead(200, {'Content-Type' : 'text/plain'});
// Publishing a notification.
if (request.method == 'POST') {
var body = '';
request.on('data', function (data) {
request.on('data', function(data) {
body += data;
});
request.on('end', function () {
++messages_in;
request.on('end', function() {
try {
var msg = JSON.parse(body);
var msg = JSON.parse(body);
debug.log('notification: ' + JSON.stringify(msg));
broadcast(msg.data);
response.end();
debug.log('notification: ' + JSON.stringify(msg));
++messages_in;
broadcast(msg);
response.writeHead(200, {'Content-Type': 'text/plain'});
} catch (err) {
response.statusCode = 400;
response.write('400 Bad Request');
} finally {
response.end();
}
});
} else if (request.url == '/status/') {
request.on('data', function(data) {
@ -139,9 +145,10 @@ var receive_server = http.createServer(function(request, response) {
'messages.in': messages_in,
'messages.out': messages_out,
'log': config.log,
'version': 5
'version': 6
};
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write(JSON.stringify(status));
response.end();
});

View file

@ -17,12 +17,12 @@ JX.install('AphlictFlashPolicyServer', {
_accessPort: null,
_debug: null,
setDebugLog : function(log) {
setDebugLog: function(log) {
this._debug = log;
return this;
},
setAccessPort : function(port) {
setAccessPort: function(port) {
this._accessPort = port;
return this;
},

View file

@ -1,28 +1,28 @@
var JX = require('javelin').JX;
JX.install('AphlictListener', {
construct : function(id, socket) {
construct: function(id, socket) {
this._id = id;
this._socket = socket;
},
members : {
_id : null,
_socket : null,
members: {
_id: null,
_socket: null,
getID : function() {
getID: function() {
return this._id;
},
getSocket : function() {
getSocket: function() {
return this._socket;
},
getDescription : function() {
getDescription: function() {
return 'Listener/' + this.getID();
},
writeMessage : function(message) {
writeMessage: function(message) {
var serial = JSON.stringify(message);
var length = Buffer.byteLength(serial, 'utf8');

View file

@ -2,20 +2,18 @@ var JX = require('javelin').JX;
JX.require('AphlictListener', __dirname);
JX.install('AphlictListenerList', {
construct : function() {
construct: function() {
this._listeners = {};
},
members : {
_listeners : null,
_nextID : 0,
_activeListenerCount : 0,
_totalListenerCount : 0,
members: {
_listeners: null,
_nextID: 0,
_activeListenerCount: 0,
_totalListenerCount: 0,
addListener : function(socket) {
var listener = new JX.AphlictListener(
this._generateNextID(),
socket);
addListener: function(socket) {
var listener = new JX.AphlictListener(this._generateNextID(), socket);
this._listeners[listener.getID()] = listener;
this._activeListenerCount++;
@ -24,7 +22,7 @@ JX.install('AphlictListenerList', {
return listener;
},
removeListener : function(listener) {
removeListener: function(listener) {
var id = listener.getID();
if (id in this._listeners) {
delete this._listeners[id];
@ -32,19 +30,19 @@ JX.install('AphlictListenerList', {
}
},
getListeners : function() {
getListeners: function() {
return this._listeners;
},
getActiveListenerCount : function() {
getActiveListenerCount: function() {
return this._activeListenerCount;
},
getTotalListenerCount : function() {
getTotalListenerCount: function() {
return this._totalListenerCount;
},
_generateNextID : function() {
_generateNextID: function() {
do {
this._nextID = ((this._nextID + 1) % 1000000000000);
} while (this._nextID in this._listeners);

View file

@ -4,16 +4,16 @@ var fs = require('fs');
var util = require('util');
JX.install('AphlictLog', {
construct : function() {
construct: function() {
this._writeToLogs = [];
this._writeToConsoles = [];
},
members : {
_writeToConsoles : null,
_writeToLogs : null,
members: {
_writeToConsoles: null,
_writeToLogs: null,
addLogfile : function(path) {
addLogfile: function(path) {
var options = {
flags: 'a',
encoding: 'utf8',
@ -27,12 +27,12 @@ JX.install('AphlictLog', {
return this;
},
addConsole : function(console) {
addConsole: function(console) {
this._writeToConsoles.push(console);
return this;
},
log : function(pattern) {
log: function(pattern) {
var str = util.format.apply(null, arguments);
var date = new Date().toLocaleString();
str = '[' + date + '] ' + str;

View file

@ -6,7 +6,7 @@ JX.require('core/install');
// NOTE: This is faking out a piece of code in JX.install which waits for
// Stratcom before running static initializers.
JX.Stratcom = {ready : true};
JX.Stratcom = {ready: true};
JX.require('core/Event');
JX.require('core/Stratcom');

Binary file not shown.