UNPKG

nntp-fast

Version:

A lightweight nntp client for node made with attention to speed and ease of use. Works with promises and streams.

202 lines (201 loc) 8.53 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var events_1 = require("events"); var DelimiterSearchState; (function (DelimiterSearchState) { DelimiterSearchState[DelimiterSearchState["START"] = 0] = "START"; DelimiterSearchState[DelimiterSearchState["CR"] = 1] = "CR"; DelimiterSearchState[DelimiterSearchState["CR_LF"] = 2] = "CR_LF"; DelimiterSearchState[DelimiterSearchState["CR_LF_DOT"] = 3] = "CR_LF_DOT"; DelimiterSearchState[DelimiterSearchState["CR_LF_DOT_CR"] = 4] = "CR_LF_DOT_CR"; })(DelimiterSearchState || (DelimiterSearchState = {})); var Delimiter; (function (Delimiter) { Delimiter[Delimiter["CRLF"] = 0] = "CRLF"; Delimiter[Delimiter["MLDB"] = 1] = "MLDB"; // multiline datablock \r\n.\r\n })(Delimiter || (Delimiter = {})); var CR = "\r".charCodeAt(0); var LF = "\n".charCodeAt(0); var DOT = ".".charCodeAt(0); /** * Searches for needle in stream while also dot-unstuffing. */ var DotUnstuffingStreamSearch = /** @class */ (function (_super) { __extends(DotUnstuffingStreamSearch, _super); /** * * @param needle Must me `Buffer.from("\r\n.\r\n")` */ function DotUnstuffingStreamSearch(needle) { var _this = _super.call(this) || this; if (needle.toString() != "\r\n.\r\n") { "unsupported CRLF needle in DotUnstuffingStreamSearch"; } _this._needle = Delimiter.MLDB; _this.maxMatches = Infinity; _this.reset(); return _this; } /** * Resets internal state */ DotUnstuffingStreamSearch.prototype.reset = function () { this._bufpos = 0; this._searchState = DelimiterSearchState.START; this.matches = 0; }; /** * Processes `chunk`. * @param chunk * @param pos * * @fires info * * @returns The last processed index in chunk + 1. */ DotUnstuffingStreamSearch.prototype.push = function (chunk, pos) { var r = 0; if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, 'binary'); var chlen = chunk.length; this._bufpos = pos || 0; while (r != chlen && this.matches < this.maxMatches) { r = this._feed(chunk); } return r; }; /** * @private * @param data */ DotUnstuffingStreamSearch.prototype._feed = function (data) { var startData = this._bufpos; var lastData = this._bufpos - 1; while (this._bufpos < data.length) { var symbol = data[this._bufpos]; switch (this._searchState) { case DelimiterSearchState.START: if (symbol == CR) { this._searchState = DelimiterSearchState.CR; } else { lastData = this._bufpos; } break; case DelimiterSearchState.CR: if (symbol == LF) { if (this._needle == Delimiter.CRLF) { // Found CRLF console.log("unsupported CRLF needl in DotUnstuffingStreamSearch"); this._searchState = DelimiterSearchState.START; } else { this._searchState = DelimiterSearchState.CR_LF; } } else { console.log("Malformed Data: Standalone CR character not allowed"); // Allow anyway if (startData <= lastData) { this.emit("info", false, data, startData, lastData + 1); } this.emit("info", false, Buffer.from("\r"), 0, 1); if (symbol == CR) { this._searchState = DelimiterSearchState.CR; } else { startData = this._bufpos; lastData = this._bufpos; this._searchState = DelimiterSearchState.START; } } break; case DelimiterSearchState.CR_LF: if (symbol == DOT) { this._searchState = DelimiterSearchState.CR_LF_DOT; } else { if (symbol == CR) { this._searchState = DelimiterSearchState.CR; } else { //false alarm if (startData <= lastData) { this.emit("info", false, data, startData, lastData + 1); } this.emit("info", false, Buffer.from("\r\n"), 0, 2); startData = this._bufpos; lastData = this._bufpos; this._searchState = DelimiterSearchState.START; } } break; case DelimiterSearchState.CR_LF_DOT: if (symbol == CR) { this._searchState = DelimiterSearchState.CR_LF_DOT_CR; } else { this._searchState = DelimiterSearchState.START; // dot stuffing must be undone https://tools.ietf.org/html/rfc3977#section-3.1.1 if (startData <= lastData) { this.emit("info", false, data, startData, lastData + 1); } this.emit("info", false, Buffer.from("\r\n"), 0, 2); return this._bufpos; } break; case DelimiterSearchState.CR_LF_DOT_CR: if (symbol == LF) { // Found MLDB delimiter this.matches++; this._searchState = DelimiterSearchState.START; this.emit("info", true, data, startData, lastData + 1); startData = this._bufpos + 1; lastData = this._bufpos; this._bufpos++; return this._bufpos; } else { console.log("Malformed Data: Standalone CR character not allowed (after dot)"); // Allow anyway //false alarm if (startData <= lastData) { this.emit("info", false, data, startData, lastData + 1); } this.emit("info", false, Buffer.from("\r"), 0, 1); if (symbol == CR) { this._searchState = DelimiterSearchState.CR; } else { this._searchState = DelimiterSearchState.START; startData = this._bufpos; lastData = this._bufpos; } } break; default: break; } this._bufpos++; } if (startData <= lastData) { this.emit("info", false, data, startData, lastData + 1); } return this._bufpos; }; return DotUnstuffingStreamSearch; }(events_1.EventEmitter)); exports.default = DotUnstuffingStreamSearch;