Permalink
Browse files

Merged 'master' branch into branch 'node-lumberjack-logger'

  • Loading branch information...
2 parents 9c92a90 + e0c1f86 commit 011192c1b997449b90041a4087d5c133a6161b30 @dhruvbird committed Aug 29, 2012
Showing with 190 additions and 103 deletions.
  1. +11 −7 package.json
  2. +0 −28 release.sh
  3. +9 −0 release_checklist.md
  4. +66 −25 src/bosh-request-parser.js
  5. +2 −2 src/bosh.js
  6. +13 −11 src/dutil.js
  7. +27 −16 src/helper.js
  8. +53 −12 src/http-server.js
  9. +1 −2 src/lookup-service.js
  10. +8 −0 whats_changed.md
View
@@ -8,20 +8,20 @@
"description": "An XMPP BOSH server written for node.js in javascript",
"author": "Dhruv Matani",
"dependencies": {
- "node-expat": "=1.4.5",
- "ltx": "= 0.0.4",
+ "node-expat": "= 1.6.1",
+ "ltx": "= 0.1.2",
"node-uuid": "= 1.3.3",
"tav": "= 0.1.0",
- "underscore": "= 1.1.5",
+ "underscore": "= 1.3.3",
"eventpipe": "= 0.0.5",
"dns-srv": "= 0.0.6",
"semver": "= 1.0.8",
- "ws": "= 0.4.12",
"node-lumberjack": "= 0.0.4"
+ "ws": "= 0.4.19",
},
"devDependencies": {
- "jsdom": "= 0.2.0",
- "jslint": "= 0.1.2"
+ "jsdom": "= 0.2.15",
+ "jslint": "= 0.1.9"
},
"repositories": [
{
@@ -66,6 +66,10 @@
{
"name": "Sonny Piers",
"email": "sonny@fastmail.net"
+ },
+ {
+ "name": "Aria Stewart",
+ "email": "aredridel@nbtsc.org"
}
],
"licenses": [
@@ -74,6 +78,6 @@
}
],
"engines": {
- "node": ">=0.4.1"
+ "node": ">=0.6.19"
}
}
View
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-VERSION=`cat package.json | grep "version" | cut -d ' ' -f 2 | sed s/\"//g`
-DIR="node-xmpp-bosh-$VERSION"
-PREVDIR=$PWD
-TARFILE="$DIR.tar.gz"
-
-rm -Rf $DIR
-mkdir $DIR
-
-cp -R images src strophe tests package.json \
-README.TXT INSTALL.TXT EMBEDDING.TXT release.sh \
-run-server.js lintit.sh monitor.js bosh.conf.example.js \
-$DIR
-
-cd $DIR
-
-if [[ $PWD == $PREVDIR ]]; then
- exit 1
-fi
-
-rm tests/sr_users.js
-find . -name "*~" | xargs rm -Rf
-find . -name ".svn" | xargs rm -Rf
-
-cd ..
-
-tar -zvcf $TARFILE $DIR
View
@@ -0,0 +1,9 @@
+# Release Checklist
+
+* Verify if package installs and runs correctly
+* Update ```whats_changed.md``` if necessary
+* Check if version in package.json is okay
+* Apply version tag (e.g. v0.6.1 [=TAG]) to current HEAD
+* Push tag & local copy to origin/master on github
+* Upload to npm using ```npm publish https://github.com/dhruvbird/node-xmpp-bosh/tarball/TAG```
+* Tweet about it, and post on identi.ca
View
@@ -23,34 +23,55 @@
*
*/
-var ltx = require('ltx');
-var util = require('util');
-var dutil = require('./dutil.js');
-var expat = require('node-expat');
+var ltx = require('ltx');
+var util = require('util');
+var dutil = require('./dutil.js');
+var expat = require('node-expat');
+var assert = require('assert').ok;
+var path = require('path');
+
+var filename = "[" + path.basename(path.normalize(__filename)) + "]";
+var log = require('./log.js').getLogger(filename);
function BoshRequestParser() {
this._parser = new expat.Parser('UTF-8');
- this._parser.parse("<bosh>");
-
- this._started = false;
- this.parsedBody = null;
-
- this._parser.on("text", this._handle_text.bind(this));
- this._parser.on("endElement", this._handle_end_element.bind(this));
- this._parser.on("entityDecl", this._handle_entity_decl.bind(this));
- this._parser.on("startElement", this._handle_start_element.bind(this));
+ this.init_state_();
}
dutil.copy(BoshRequestParser.prototype, {
+ /* Initialize the internal state (variables) of the parser */
+ init_state_: function() {
+ this._parser.removeAllListeners();
+ this._parser.parse("<bosh>");
+
+ this.started_ = false;
+ this.parsedBody = null;
+ if (this.hasOwnProperty('stanza')) {
+ delete this.stanza;
+ }
+
+ // Always attach handlers after starting the <bosh> tag.
+ this._parser.on("text", this._handle_text.bind(this));
+ this._parser.on("endElement", this._handle_end_element.bind(this));
+ this._parser.on("entityDecl", this._handle_entity_decl.bind(this));
+ this._parser.on("startElement", this._handle_start_element.bind(this));
+ },
+
+ /* Reset the underlying expat parser and internal state. Do NOT
+ * call this method after calling end() on the parser.
+ */
+ reset: function() {
+ log.debug("Reseting parser state");
+ this._parser.reset();
+ this.init_state_();
+ },
+
_handle_start_element: function(name, attrs) {
- if (!this._started) {
- if (name === "body") {
- this._started = true;
- } else {
- this.end();
- return;
- }
- }
+ if (!this.started_) {
+ // The first node MUST be <DUMMY>.
+ assert(name === 'DUMMY');
+ this.started_ = true;
+ }
var stanza = new ltx.Element(name, attrs);
if (this.stanza) {
@@ -63,14 +84,24 @@ dutil.copy(BoshRequestParser.prototype, {
_handle_end_element: function(name, attrs) {
if (this.stanza) {
if (this.stanza.parent) {
+ // Expat has already verified that the closing tag
+ // matches the corresponding opening tag, so we need
+ // not check that again.
this.stanza = this.stanza.parent;
} else {
this.parsedBody = this.stanza;
delete this.stanza;
}
} else {
- // This happens at times.
- this.end();
+ // The user tried to close the top level <bosh> tag. We
+ // set this.parsedBody to null to indicate that we
+ // encountered a parsing error. If the user sent XML like:
+ // <body/></DUMMY></bosh><DUMMY> then expat will fail to
+ // parse the part after </bosh> and will return 'false' in
+ // the parse() method (as discussed with
+ // @satyamshekhar). We don't do anything else since the
+ // caller will reset() the parser.
+ this.parsedBody = null;
}
},
@@ -82,20 +113,30 @@ dutil.copy(BoshRequestParser.prototype, {
},
_handle_entity_decl: function() {
- this.end();
+ // this.end();
+ // We ignore all entity declarations.
+ this.reset();
},
+ /* parse() may be passed incomplete stanzas, but finally a check
+ * is made to see if parsedBody is non-null. If it is, we reset
+ * the parser.
+ */
parse: function(data) {
+ this.parsedBody = null;
if (this._parser && !this._parser.parse(data)) {
- this.end();
return false;
}
else if (!this._parser) {
+ // end() was called on this parser already.
return false;
}
return true;
},
+ /* Ends parsing and destroys the underlying parser. Do NOT call
+ * any other method on this object after calling end().
+ */
end: function() {
if (this._parser) {
this._parser.stop();
View
@@ -204,8 +204,8 @@ exports.createServer = function (options) {
// event and throw an exception if it is unhandled
if (!bep.emit('error', ex)) {
throw new Error(
- sprintf('ERROR on listener at endpoint: http://%s:%s%s',
- options.host, options.port, options.path)
+ sprintf('ERROR (%s) on listener at endpoint: http://%s:%s%s',
+ String(ex), options.host, options.port, options.path)
);
}
}
View
@@ -23,10 +23,14 @@
*
*/
-var us = require('underscore');
+var us = require('underscore');
+var path = require('path');
+
+var filename = "[" + path.basename(path.normalize(__filename)) + "]";
+var log = require('./log.js').getLogger(filename);
// The maximum number of characters that a single log line can contain
-var MAX_CHARS_IN_LOG_LINE = 4096;
+var TRIM_DEFAULT_LENGTH = 256;
var _log_level = 4;
var _log_levels = {
@@ -96,11 +100,11 @@ function log_it(level) {
astr = arg.toString();
// console.log(astr.length);
- if (astr.length > MAX_CHARS_IN_LOG_LINE) {
+ if (astr.length > TRIM_DEFAULT_LENGTH) {
// We limit the writes because we are running into a
// bug at this point of time.
- more_hint = ' ... ' + (astr.length - MAX_CHARS_IN_LOG_LINE) + ' more characters';
- astr = astr.substr(0, MAX_CHARS_IN_LOG_LINE);
+ more_hint = ' ... ' + (astr.length - TRIM_DEFAULT_LENGTH) + ' more characters';
+ astr = astr.substr(0, TRIM_DEFAULT_LENGTH);
}
process.stdout.write(astr);
@@ -245,7 +249,7 @@ function sprintf(fmt_str) {
var estr = sprintf("The number of arguments in your format string (%s)[%s] " +
"does NOT match the number of arguments passed[%s]",
fmt_str, fs_parts.length-1, args.length);
- log_it("WARN", estr);
+ log.warn("%s", estr);
throw new Error(estr);
}
@@ -283,8 +287,6 @@ function replace_promise(s, victim, replacement) {
});
}
-var TRIM_DEFAULT_LENGTH = 80;
-
function trim_promise(s, len) {
return new ToStringPromise(function() {
len = len || TRIM_DEFAULT_LENGTH;
@@ -335,8 +337,8 @@ function _real_xml_parse(xml, ltx) {
node = ltx.parse(xml);
}
catch (ex) {
- log_it("WARN", "_real_xml_parse::Error parsing XML:", xml, ex.toString());
- log_it("WARN", ex.stack);
+ log.warn("_real_xml_parse::Error (%s) parsing XML: %s", String(ex), xml);
+ log.warn("%s", ex.stack);
}
return node;
}
@@ -561,7 +563,7 @@ exports.sprintfd = sprintfd;
exports.rev_hash = rev_hash;
exports.xml_parse = _xml_parse();
exports.set_log_level = require("./log.js").set_log_level;
-exports.log_it = log_it;
+// exports.log_it = log_it; // DO NOT export to track usage outside this module.
exports.json_parse = json_parse;
exports.jid_parse = jid_parse;
exports.num_cmp = num_cmp;
View
@@ -71,7 +71,16 @@ function add_to_headers(dest, src) {
function JSONPResponseProxy(req, res) {
this.req_ = req;
this.res_ = res;
- this.wrote_ = false;
+ this.has_content_length_header_ = false;
+ this.response_json_ = { reply: '' };
+ this.headers_ = { };
+ this.status_code_ = 200;
+
+ // Provide a getter to access the 'socket' property of this
+ // response object.
+ this.__defineGetter__('socket', function() {
+ return this.res_.socket;
+ });
var _url = url.parse(req.url, true);
this.jsonp_cb_ = _url.query.callback || '';
@@ -89,30 +98,32 @@ JSONPResponseProxy.prototype = {
return this.res_.on.apply(this.res_, arguments);
},
writeHead: function (status_code, headers) {
- var _headers = { };
- dutil.copy(_headers, headers);
- _headers['Content-Type'] = 'application/json; charset=utf-8';
- return this.res_.writeHead(status_code, _headers);
+ dutil.copy(this.headers_, headers);
+ this.status_code_ = status_code;
+ this.headers_['Content-Type'] = 'application/json; charset=utf-8';
},
write: function (data) {
- if (!this.wrote_) {
- this.res_.write(this.jsonp_cb_ + '({"reply":"');
- this.wrote_ = true;
- }
-
data = data || '';
- data = data.replace(/\n/g, '\\n').replace(/"/g, '\\"');
- return this.res_.write(data);
+ this.response_json_.reply += data;
},
end: function (data) {
this.write(data);
- if (this.jsonp_cb_) {
- this.res_.write('"});');
+ var data_to_write = this.jsonp_cb_ + "(" + JSON.stringify(this.response_json_) + ");";
+
+ if (this.has_content_length_header_) {
+ var content_length = Buffer.byteLength(data_to_write, 'utf8');
+ this.headers_['Content-Length'] = content_length;
}
- return this.res_.end();
+ this.res_.writeHead(this.status_code_, this.headers_);
+ this.response_json_ = null;
+ return this.res_.end(data_to_write);
},
setHeader: function(name, value) {
- return this.res_.setHeader(name, value);
+ if (name.toLowerCase() == 'content-length') {
+ this.has_content_length_header_ = true;
+ } else {
+ return this.res_.setHeader(name, value);
+ }
}
};
// End HTTP header helpers
Oops, something went wrong.

0 comments on commit 011192c

Please sign in to comment.