UNPKG

@ntrip/caster

Version:
123 lines (122 loc) 5.47 kB
"use strict"; /* * This file is part of the @ntrip/caster distribution (https://github.com/node-ntrip/caster). * Copyright (c) 2020 Nebojsa Cvetkovic. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NtripHTTPParser = void 0; const http_parser_ts_1 = require("http-parser-ts"); class NtripHTTPParser extends http_parser_ts_1.HTTPParser { constructor() { super(...arguments); this.injectedLines = []; } injectLine(line) { this.injectedLines.push(line); } consumeLine() { var _a; return (_a = this.injectedLines.pop()) !== null && _a !== void 0 ? _a : super.consumeLine(); } REQUEST_LINE() { var _a, _b, _c; const line = this.consumeLine(); if (!line) return; const match = NtripHTTPParser.REQUEST_EXP.exec(line); if (match === null) throw parseError('HPE_INVALID_CONSTANT'); let method = match.groups['method']; let protocol = (_a = match.groups['protocol']) !== null && _a !== void 0 ? _a : 'HTTP'; // Process SOURCE request secret if (method.startsWith('SOURCE ')) { method = 'SOURCE'; this.info.headers.push('Ntrip-Source-Secret', match.groups['secret']); } this.info.method = NtripHTTPParser.methods.indexOf(method); if (this.info.method === -1) throw new Error('invalid request method'); this.info.url = match.groups['url']; this.info.headers.push('@protocol', protocol); this.socket.protocol = protocol; this.info.versionMajor = +((_b = match.groups['versionMajor']) !== null && _b !== void 0 ? _b : 1); this.info.versionMinor = +((_c = match.groups['versionMinor']) !== null && _c !== void 0 ? _c : 1); // TODO: Discover why keep-alive can't be forced with 1.0 if (protocol === 'RTSP') { this.info.versionMajor = 1; this.info.versionMinor = 1; } this.bodyBytes = 0; this.state = 'HEADER'; } RESPONSE_LINE() { var _a, _b, _c, _d; const line = this.consumeLine(); if (!line) return; const match = (_a = NtripHTTPParser.RESPONSE_EXP.exec(line)) !== null && _a !== void 0 ? _a : NtripHTTPParser.ERROR_EXP.exec(line); if (match === null) throw parseError('HPE_INVALID_CONSTANT'); let protocol = (_b = match.groups['protocol']) !== null && _b !== void 0 ? _b : 'HTTP'; // Inject newline for casters that don't send second \r\n if (['ICY', 'SOURCETABLE', 'ERROR'].includes(protocol)) this.injectLine(''); let statusCode = +match.groups['code']; let statusMessage = match.groups['message']; // Error message doesn't have status code if (isNaN(statusCode)) { let statusMessageLower = statusMessage.toLowerCase(); if (statusMessageLower === 'bad password') { statusCode = 401; } else if (statusMessageLower === 'already connected') { statusCode = 409; } else if (statusMessageLower === 'mount point taken or invalid') { statusCode = 404; } else { statusCode = 400; } } this.info.statusCode = statusCode; this.info.statusMessage = statusMessage; this.info.headers.push('@protocol', protocol); this.socket.protocol = protocol; this.info.versionMajor = +((_c = match.groups['versionMajor']) !== null && _c !== void 0 ? _c : 1); this.info.versionMinor = +((_d = match.groups['versionMinor']) !== null && _d !== void 0 ? _d : 1); // TODO: Discover why keep-alive can't be forced with 1.0 if (protocol === 'RTSP') { this.info.versionMajor = 1; this.info.versionMinor = 1; } // Implied zero length if ((statusCode / 100 | 0) === 1 || statusCode === 204 || statusCode === 304) { this.bodyBytes = 0; } this.state = 'HEADER'; } } exports.NtripHTTPParser = NtripHTTPParser; NtripHTTPParser.REQUEST_EXP = /^(?<method>[A-Z-_]+|SOURCE (?<secret>[^ ]+)) (?<url>[^ ]+)(?: (?<protocol>HTTP|RTSP|RTP)\/(?<versionMajor>\d)\.(?<versionMinor>\d))?$/; NtripHTTPParser.RESPONSE_EXP = /^(?<protocol>ICY|SOURCETABLE|HTTP|RTSP)(?:\/(?<versionMajor>\d)\.(?<versionMinor>\d))? (?<code>\d{3}) ?(?<message>.*)$/; NtripHTTPParser.ERROR_EXP = /^(?<protocol>ERROR)(?: - (?<message>.*))?$/; NtripHTTPParser.methods = http_parser_ts_1.HTTPParser.methods.concat(['SOURCE', 'SETUP', 'RECORD', 'PLAY', 'TEARDOWN', 'GET_PARAMETER']).sort(); function parseError(code) { let err = new Error('Parse Error'); err.code = code; return err; }