Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use JSON.generate instead of .dump in request middleware #266

Merged
merged 2 commits into from
Apr 14, 2021

Conversation

Be-ngt-oH
Copy link
Contributor

The standard library's JSON gem provides two methods for encoding objects as JSON strings JSON.dump and JSON.generate.

To quote the docs, JSON.load is "is part of the implementation of the load/dump interface of Marshal and YAML.". It uses JSON.generate but calls it with a different set of options.

Analogous there is JSON.load and JSON.parse where JSON.load must not be used with untrusted user input. Typically, dump gets paired with load and generate with parse

Since we want to encode a hash as a JSON string, it makes sense to use JSON.generate rather than dump. This ensures that safe defaults will be used. The differences (default options) are as follows:

JSON.dump JSON.generate
max_nesting false 100
allow_nan true false

The max_nesting option set will ensure that no infinite loop can happen if there's circular references in the data which might be a breaking change if users are creating deeply nested JSON objects. A workaround is to not pash a hash to Faraday but instead encode it, e.g. with an increased max_nesting value, beforehand.

The allow_nan option causes JSON generation to fail if NaN, Infinity or -Infinity is encountered, e.g. JSON.generate({a: 0.0/0}) raises NaN not allowed in JSON (JSON::GeneratorError) which seems to be a sane default.


Background story how we came to notice this:

We recently ran into an odd issue with a Rails app using the Oj gem1. As of Oj version 3.11.3 there is a difference in behaviour between JSON.generate and JSON.dump. This is the output from a console in a fresh Rails app:

JSON.dump(Time.now)
=> "\"2021-04-13 16:25:23 +0100\""
JSON.generate(Time.now)
=> "\"2021-04-13T16:25:27.154+01:00\""

Because of another gem that was using Faraday Middleware internally this caused timestamps in the wrong format when generating the JSON for an external API.

The standard library's JSON gem provides two methods for encoding
objects as JSON strings JSON.dump and JSON.generate.

To quote the docs, JSON.load is "is part of the implementation of the
load/dump interface of Marshal and YAML.". It _uses_ JSON.generate but
calls it with a different set of options.

Analogous there is JSON.load and JSON.parse where JSON.load _must not be
used_ with untrusted user input. Typically, `dump` gets paired with
`load` and `generate` with `parse`

Since we want to encode a hash as a JSON string, it makes sense to use
JSON.generate rather than dump. This ensures that safe defaults will be
used. The differences (default options) are as follows:

|             | JSON.dump | JSON.generate |
|-------------|-----------|---------------|
| max_nesting | false     | 100           |
| allow_nan   | true      | false         |

The max_nesting option set will ensure that no infinite loop can happen
if there's circular references in the data which _might_ be a breaking
change if users are creating deeply nested JSON objects. A workaround is
to not pash a hash to Faraday but instead encode it, e.g. with an
increased max_nesting value, beforehand.

The allow_nan option causes JSON generation to fail if NaN, Infinity or
-Infinity is encountered, e.g. `JSON.generate({a: 0.0/0})` raises `NaN
not allowed in JSON (JSON::GeneratorError)` which seems to be a sane
default.
@olleolleolle olleolleolle requested a review from iMacTia April 13, 2021 17:22
@olleolleolle
Copy link
Member

@Be-ngt-oH 👋 Hello! I made some linting fixes, and also, made the CI quicker, so that we can see you changes go green.

Copy link
Member

@iMacTia iMacTia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for raising this @Be-ngt-oH, it makes sense to me.
Adding a couple of useful links for further reading:

@iMacTia iMacTia merged commit 6e10251 into lostisland:main Apr 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants