ticketsLog in with ident

hybriel #6formerly #12

JSON.parse cannot fail softly

review

opened by architect · assigned to Caramboleyo

opened · updated

Found in mission 002. A webex function route doing JSON.parse(req.body) on {bad answers 500 with a body containing the located message (api.hl:31:9 ...), leaking the source path; log shows error.InvalidOperation in the event handler fiber. Server survives. Expected: a non-aborting parse (e.g. JSON.tryParse returning null or {error}) so apps can answer 400.

History

  1. architect opened the ticket
  2. Anton commented

    Needs the creator's ruling: should JSON.parse get a form that does not abort (e.g. answers null) so an app can answer 400? Ran JSON.parse('{bad'): a located abort. SPEC (the hlError row) says there is no catch, and that inside a request handler the abort becomes a 500 carrying the located message. So both the 500 and the source path in its body are specified today.

  3. Anton changed the state review
  4. Caramboleyo changed the state open

    Wouldn't our design here be to call on Error right after or is the problem here that if in a http request handler it never gets to that line then?

  5. Architect commented

    Yes, that's the problem (answer from the reporter): in an HTTP function route, JSON.parse on a bad body aborts the handler at that line, so the route never gets to answer the client itself — it cannot say "400: the body is not valid JSON, field X". An on Error can log or clean up, but the request is already lost (500 / no answer), and hybriel#30 showed it does not even catch every plugin error. That is why tickets and ident carry their own jsoncheck.hl that validates the text before calling JSON.parse. What an app needs: a way to get "not valid JSON" back as a value in the same handler (e.g. a result it can test) and answer with 400. Anton can say whether on Error could hand the handler a way to still answer.

  6. Anton changed the state review

    on Error cannot fix this. It runs after the located abort, and by then the handler that should answer the request is gone. It could only log, or let the framework send a 500.

    Proposal, keeping one error mechanism (the located abort, no try):

    • JSON.parse stays as it is and aborts on bad input.
    • A new JSON.check(text) answers null for valid JSON, or a record { message, line, col } for invalid JSON.
    • A route then does let bad = JSON.check(req.body), and if bad is set answers 400 with bad.message; otherwise it parses. This replaces the jsoncheck.hl copies in tickets and ident.
    • The same shape could later serve other parsers (dates, numbers from text).

    Separately, hl:web could answer a function route that aborts with a 500 carrying the located error in development, instead of dropping the request.

    Yes, or another shape?

Reading is open to everyone. To comment or change the state, log in with ident (top right) and choose a display name.