var Layer = function(stack, callback) { if (!(stack instanceof Layer.Stack)) { var e = new Error('Bad argument: expecting instance of Layer.Stack'); e.type = 'bad_argument'; e.args = arguments; throw e; } callback = callback != undefined ? callback : function(s) {return s} this._callback = function(content) { Layer.inCallback = true; var ret = callback(content); Layer.inCallback = false; return ret; } this._content = ''; this._stack = stack; } Layer.inCallback = false; Layer.prototype.write = function(string) { this._content += string; return this._stack._buffer; } Layer.prototype.clean = function() { if (this.level != 0 && !this.level) { var e = new Error('Buffer clean error: layer not active'); e.type = 'layer_inactive'; e.args = arguments; throw e; } this._content = ''; return this._stack._buffer; } Layer.prototype.flush = function() { if (this.level != 0 && !this.level) { var e = new Error('Buffer flush error: layer not active'); e.type = 'layer_inactive'; e.args = arguments; throw e; } var content = this._callback(this._content); if (this.level > 0) { this._stack._stack[this.level - 1].write(content); } return this._stack._buffer; } Layer.Stack = function(buffer) { if (!(buffer instanceof Buffer)) { var e = new Error('Bad argument: expecting instance of Buffer'); e.type = 'bad_argument'; e.args = arguments; throw e; } this._stack = new Array(); this._buffer = buffer; } Layer.Stack.prototype.push = function(layer) { if (!(layer instanceof Layer)) { var e = new Error('Bad argument: expecting instance of Layer'); e.type = 'bad_argument'; e.args = arguments; throw e; } layer.level = this._stack.length; this._stack.push(layer); return this._buffer; } Layer.Stack.prototype.pop = function() { var layer = this._stack.pop(); layer.clean(); delete layer.level; return this._buffer; } Layer.Stack.prototype.getLast = function() { return this._stack[this._stack.length - 1]; } Layer.Stack.prototype.write = function(string) { if (this._stack.length == 0) { var e = new Error('Buffer write error: buffer stack empty'); e.type = 'no_buffer'; e.args = arguments; throw e; } this.getLast().write(string); return this._buffer; } Layer.Stack.prototype.getLength = function() { return this._stack.length; } var Buffer = function(response) { if (!(response instanceof HTTP.ServerResponse)) { var e = new Error('Bad argument: expecting instance of HTTP.ServerResponse'); e.type = 'bad_argument'; e.args = arguments; throw e; } var self = this; this._response = response; this._stack = new Layer.Stack(this); this._stack.push(new Layer(this._stack, function(layerContent) { self._response.write = HTTP.ServerResponse.prototype.write; self._response.write(layerContent); })); onexit(function() { for (var i = self._stack.getLength(); i >= 0; i--) { self.flush().end(); } }); this._response.write = function(str) { self._stack.write(str); } } Buffer.prototype.start = function(callback) { if (Layer.inCallback) throw new Error('Cannot start output buffer inside buffer callback'); if (this._response._outputStarted) { var e = new Error('Cannot attach buffer: output already started'); e.type = 'output_started'; e.args = arguments; throw e; } this._stack.push(new Layer(this._stack, callback)) return this; } Buffer.prototype.end = function() { if (Layer.inCallback) throw new Error('Cannot end output buffer inside buffer callback'); return this._stack.pop(); } Buffer.prototype.get = function() { if (Layer.inCallback) throw new Error('Cannot get output buffer inside buffer callback'); return this._stack.getLast()._content; } Buffer.prototype.clean = function() { if (Layer.inCallback) throw new Error('Cannot clean output buffer inside buffer callback'); return this._stack.getLast().clean(); } Buffer.prototype.flush = function() { if (Layer.inCallback) throw new Error('Cannot flush output buffer inside buffer callback'); return this._stack.getLast().flush(); } exports.Buffer = Buffer; if (global.response && global.response instanceof HTTP.ServerResponse) { exports.buffer = new Buffer(response); }