Code coverage report for lib/parsers/javascript.js

Statements: 100% (101 / 101)      Branches: 100% (41 / 41)      Functions: 100% (8 / 8)      Lines: 100% (101 / 101)      Ignored: none     

All files » lib/parsers/ » javascript.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    13   13 965 965 965 965 965 965 965 965     13 43 43   13   13 10929             10929   2795 2785   2785   2785 1932 853   738   115 8134 4994     4990 111   4879 4879   4879 23 23 23     4856   4856 3140   532 532   528 7   521 521   521 4147 2   4145 4122   496   2608       13 2713 50 50 50   2663 16 16 16 16 16 16 2647 2623   24   2663 2663 2663     13   6784 6784 6784       43 43 43       13 2663 2663   2663 4133 97   4036   4121 4121   2651   2 2       13 5526     5518 5518     13 8321     8321 23375   23375 18     8303     13 13  
'use strict';
 
var util = require('util');
 
function JavascriptReplyParser() {
    this.name = exports.name;
    this._buffer = new Buffer(0);
    this._offset = 0;
    this._big_offset = 0;
    this._chunks_size = 0;
    this._buffers = [];
    this._type = 0;
    this._protocol_error = false;
}
 
function IncompleteReadBuffer(message) {
    this.name = 'IncompleteReadBuffer';
    this.message = message;
}
util.inherits(IncompleteReadBuffer, Error);
 
JavascriptReplyParser.prototype._parseResult = function (type) {
    var start = 0,
        end = 0,
        offset = 0,
        packetHeader = 0,
        res,
        reply;
 
    if (type === 43 || type === 58 || type === 45) { // + or : or -
        // Up to the delimiter
        end = this._packetEndOffset();
        start = this._offset;
        // Include the delimiter
        this._offset = end + 2;
 
        if (type === 43) {
            return this._buffer.slice(start, end);
        } else if (type === 58) {
            // Return the coerced numeric value
            return +this._buffer.toString('ascii', start, end);
        }
        return new Error(this._buffer.toString('utf-8', start, end));
    } else if (type === 36) { // $
        packetHeader = this.parseHeader();
 
        // Packets with a size of -1 are considered null
        if (packetHeader === -1) {
            return null;
        }
        end = this._offset + packetHeader;
        start = this._offset;
 
        if (end + 2 > this._buffer.length) {
            this._chunks_size = this._buffer.length - this._offset - 2;
            this._big_offset = packetHeader;
            throw new IncompleteReadBuffer('Wait for more data.');
        }
        // Set the offset to after the delimiter
        this._offset = end + 2;
 
        return this._buffer.slice(start, end);
    } else if (type === 42) { // *
        // Set a rewind point, as the packet is larger than the buffer in memory
        offset = this._offset;
        packetHeader = this.parseHeader();
 
        if (packetHeader === -1) {
            return null;
        }
        reply = [];
        offset = this._offset - 1;
 
        for (var i = 0; i < packetHeader; i++) {
            if (this._offset >= this._buffer.length) {
                throw new IncompleteReadBuffer('Wait for more data.');
            }
            res = this._parseResult(this._buffer[this._offset++]);
            reply.push(res);
        }
        return reply;
    } else {
        return void 0;
    }
};
 
JavascriptReplyParser.prototype.execute = function (buffer) {
    if (this._chunks_size !== 0 && this._big_offset > this._chunks_size + buffer.length) {
        this._buffers.push(buffer);
        this._chunks_size += buffer.length;
        return;
    }
    if (this._buffers.length !== 0) {
        this._buffers.unshift(this._offset === 0 ? this._buffer : this._buffer.slice(this._offset));
        this._buffers.push(buffer);
        this._buffer = Buffer.concat(this._buffers);
        this._buffers = [];
        this._big_offset = 0;
        this._chunks_size = 0;
    } else if (this._offset >= this._buffer.length) {
        this._buffer = buffer;
    } else {
        this._buffer = Buffer.concat([this._buffer.slice(this._offset), buffer]);
    }
    this._offset = 0;
    this._protocol_error = true;
    this.run();
};
 
JavascriptReplyParser.prototype.try_parsing = function () {
    // Set a rewind point. If a failure occurs, wait for the next execute()/append() and try again
    var offset = this._offset - 1;
    try {
        return this._parseResult(this._type);
    } catch (err) {
        // Catch the error (not enough data), rewind if it's an array,
        // and wait for the next packet to appear
        this._offset = offset;
        this._protocol_error = false;
        return void 0;
    }
};
 
JavascriptReplyParser.prototype.run = function (buffer) {
    this._type = this._buffer[this._offset++];
    var reply = this.try_parsing();
 
    while (reply !== undefined) {
        if (this._type === 45) { // Errors -
            this.send_error(reply);
        } else {
            this.send_reply(reply); // Strings + // Integers : // Bulk strings $ // Arrays *
        }
        this._type = this._buffer[this._offset++];
        reply = this.try_parsing();
    }
    if (this._type !== undefined && this._protocol_error === true) {
        // Reset the buffer so the parser can handle following commands properly
        this._buffer = new Buffer(0);
        this.send_error(new Error('Protocol error, got "' + String.fromCharCode(this._type) + '" as reply type byte'));
    }
};
 
JavascriptReplyParser.prototype.parseHeader = function () {
    var end   = this._packetEndOffset(),
        value = this._buffer.toString('ascii', this._offset, end) | 0;
 
    this._offset = end + 2;
    return value;
};
 
JavascriptReplyParser.prototype._packetEndOffset = function () {
    var offset = this._offset,
        len = this._buffer.length - 1;
 
    while (this._buffer[offset] !== 0x0d && this._buffer[offset + 1] !== 0x0a) {
        offset++;
 
        if (offset >= len) {
            throw new IncompleteReadBuffer('Did not see LF after NL reading multi bulk count (' + offset + ' => ' + this._buffer.length + ', ' + this._offset + ')');
        }
    }
    return offset;
};
 
exports.Parser = JavascriptReplyParser;
exports.name = 'javascript';