From 59cd930b6cec038d36d55d014bd96d33de44814b Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Sun, 4 Aug 2019 12:40:02 -0700 Subject: [PATCH] Support more charsets using iconv-lite --- build/build.ts | 1 + lib/cwmp.ts | 44 +++++++++++++++++++++++++++++++++++++++----- npm-shrinkwrap.json | 36 +++++++++++++++++++++++++++++++++--- package.json | 1 + 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/build/build.ts b/build/build.ts index 025aff1..e507495 100644 --- a/build/build.ts +++ b/build/build.ts @@ -64,6 +64,7 @@ const externals = [ "child_process", "dgram", "url", + "iconv-lite", "koa", "koa-router", "koa-compress", diff --git a/lib/cwmp.ts b/lib/cwmp.ts index 75b024d..3daf1ab 100644 --- a/lib/cwmp.ts +++ b/lib/cwmp.ts @@ -50,6 +50,7 @@ import { IncomingMessage, ServerResponse } from "http"; import { Readable } from "stream"; import { promisify } from "util"; import { TLSSocket } from "tls"; +import { decode, encodingExists } from "iconv-lite"; import { dependencies as DEPENDENCIES } from "../package.json"; import { parseXmlDeclaration } from "./xml-parser"; import * as debug from "./debug"; @@ -1106,6 +1107,15 @@ export function listener( }); } +function decodeString(buffer: Buffer, charset: string): string { + try { + return buffer.toString(charset); + } catch (err) { + if (encodingExists(charset)) return decode(buffer, charset); + } + return null; +} + async function listenerAsync( httpRequest: IncomingMessage, httpResponse: ServerResponse @@ -1233,10 +1243,36 @@ async function listenerAsync( if (!charset) { const parse = parseXmlDeclaration(body); const e = parse ? parse.find(s => s.localName === "encoding") : null; - charset = e ? e.value : "utf8"; + charset = e ? e.value.toLowerCase() : "utf8"; } - const bodyStr = body.toString(charset); + const bodyStr = decodeString(body, charset); + + if (bodyStr == null) { + const msg = `Unknown encoding '${charset}'`; + logger.accessError({ + message: "XML parse error", + parseError: msg, + sessionContext: sessionContext || { + httpRequest: httpRequest, + httpResponse: httpResponse + } + }); + httpResponse.setHeader("Content-Length", Buffer.byteLength(msg)); + httpResponse.writeHead(400, { Connection: "close" }); + if (sessionContext) { + if (sessionContext.debug) + debug.outgoingHttpResponse(httpResponse, sessionContext.deviceId, msg); + } else { + const cacheSnapshot = await localCache.getCurrentSnapshot(); + const d = !!localCache.getConfig(cacheSnapshot, "cwmp.debug", { + remoteAddress: httpResponse.connection.remoteAddress + }); + if (d) debug.outgoingHttpResponse(httpResponse, null, msg); + } + httpResponse.end(msg); + return; + } async function parsedRpc(_sessionContext, rpc, parseWarnings): Promise { for (const w of parseWarnings) { @@ -1283,9 +1319,7 @@ async function listenerAsync( const d = !!localCache.getConfig(cacheSnapshot, "cwmp.debug", { remoteAddress: httpResponse.connection.remoteAddress }); - if (d) { - debug.outgoingHttpResponse(httpResponse, null, error.message); - } + if (d) debug.outgoingHttpResponse(httpResponse, null, error.message); } httpResponse.end(error.message); return; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index ff447b3..fc25732 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -3670,6 +3670,17 @@ "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } } }, "extglob": { @@ -4355,9 +4366,9 @@ "dev": true }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", + "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==", "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -5937,6 +5948,15 @@ "requires": { "ms": "^2.1.1" } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } } } }, @@ -7664,6 +7684,16 @@ "http-errors": "1.7.3", "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } } }, "rc": { diff --git a/package.json b/package.json index c1d787b..e0f9816 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "tools": "tools" }, "dependencies": { + "iconv-lite": "^0.5.0", "jsonwebtoken": "^8.5.1", "koa": "^2.7.0", "koa-bodyparser": "^4.2.1",