bourne icon indicating copy to clipboard operation
bourne copied to clipboard

Ignore BOM char

Open paulovieira opened this issue 3 years ago • 0 comments

Support plan

  • is this issue currently blocking your project? (yes/no): yes
  • is this issue affecting a production system? (yes/no): yes

Context

  • node version: v16.14.0
  • module version: 3.0.0
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...): wreck (with the json option)

What problem are you trying to solve?

In some weird cases the json response will have a byte order mark (BOM) character at the beginning. I experienced this when using @hapi/wreck to fetch data from a wacky API of a portuguese public service (see the example below).

Since bourne is meant to be a secure replacement for JSON.parse, I think it would make sense to detect and correct this well-known faulty case. In fact the JSON RFC suggests precisely that: https://datatracker.ietf.org/doc/html/rfc8259#section-8.1

Implementations MUST NOT add a byte order mark (U+FEFF) to the beginning of a networked-transmitted JSON text. In the interests of interoperability, implementations that parse JSON texts MAY ignore the presence of a byte order mark rather than treating it as an error.

The secure-json-parse module (which is the equivalent module in the fastify ecosystem) also does that: https://github.com/fastify/secure-json-parse/pull/5

Below is a simple example that reproduces the problem. The response has a BOM char.

I'm happy to submit a PR if this is a desired feature for bourne.

const Wreck = require('@hapi/wreck');
const Bourne = require('@hapi/bourne');

const exampleThatWillFail = async function () {

    let { payload } = await Wreck.get(getUrl(), { json: true });
    console.log(payload)
};

const exampleThatWillSucceed = async function () {

    let { payload } = await Wreck.get(getUrl(), { json: false });

    // manually call Bourne.parse

    let s = payload.toString();
    if (s.charCodeAt(0) === 0xFEFF) {
        s = s.slice(1)
    }

    payload = Bourne.parse(s);
    console.log(payload)
};

try {
    exampleThatWillFail();
    // exampleThatWillSucceed();
}
catch (ex) {
    console.error(ex);
}

function getUrl() {

    return 'https://observatorioindicadores.dgterritorio.gov.pt/websig/bi/ngGeoAPI/public/index.php/metrics/load?par=observatorio&mod=metrics&type=0&table=t_new_observatorio_dat&identifier=0&query=and%20category_geo%20=%205%20and%20category_time%20=%201&classification=0&lang=pt&numclasses=5&precision=2&columns=category_time&rows=category_geo&ruddmode=&ruddparent=&ruddmember=&colors=%23FFF7EC%2C%23FEE8C8%2C%23FDD49E%2C%23FDBB84%2C%23FC8D59%2C%23EF6548%2C%23D7301F%2C%23B30000%2C%237F0000&param=894';
}

paulovieira avatar Jun 28 '22 23:06 paulovieira