# 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';