laminas-api-tools / api-tools-content-negotiation

Laminas Module providing content-negotiation features
https://api-tools.getlaminas.org/documentation
BSD 3-Clause "New" or "Revised" License
5 stars 14 forks source link

JSON body with very large numbers causes problems #8

Open weierophinney opened 4 years ago

weierophinney commented 4 years ago

Opening here as it was originally on zf-content-validation - https://github.com/zfcampus/zf-content-validation/issues/57

If an input body into an apigility API contains a field with a very large number, json_encode will emit a notice:

Notice: json_decode(): integer overflow detected in /vagrant_web/vendor/zfcampus/zf-content-negotiation/src/ContentTypeListener.php on line 172

It doesn't matter if the field is defined in the API or not, it will happen on any POST, PUT or PATCH.

{ "foobar": 128934701823471023487128390871 }

Since the decoding happens before any validation occurs, this is understandable. Also, unfortunately, it appears that tacking on the silence operator (@) to hide the notice actually changes the behavior. As the code sits now, the validators and the resource code will receive 9223372036854775807 for the value of those large integer containing fields.

If I send in the large number for a field with a StringLength validator, after the Notice and stack trace, I get a JSON body with the validator indicating that the field expected a string but didn't get that.

If I change line 172 to be

$data = @json_decode($json, true);

Then I don't see the notice and I'm getting the same (expected) validation errors. But the input number is smashed down to PHP_INT_MAX. There's an option on json_decode called JSON_BIGINT_AS_STRING which seems it should be able to use the large number as a string (at least that's how I read it) but it doesn't seem to have any effect whatsoever.

I'm not really happy with the @ solution since @ is evil and all that, but since JSON_BIGINT_AS_STRING doesn't appear to work and there doesn't appear to be any way at all to get the actual input in any format, I'm not sure if anything can be done.

TL;DR - If anything can be done about this that would ideally not spew a notice but could be dealt with in a way that would give back some sort of nice error (that would be JSON at the end) that would be ideal. I don't know if it's possible, though.


Originally posted by @dstockto at https://github.com/zfcampus/zf-content-negotiation/issues/77

weierophinney commented 4 years ago

I wrote a test for the case you are describing, and it seems the listener is returning an ApiProblemResponse in case I pass a large number. This seems like proper behavior, or maybe I misunderstood the issue...

The test can be found here.


Originally posted by @Wilt at https://github.com/zfcampus/zf-content-negotiation/issues/77#issuecomment-240952990

weierophinney commented 4 years ago

@Wilt Shouldn't the first line of the test be:

$data = '{"large_number":128934701823471023487128390871}';

The test does seem to cause an ApiProblem with a 400 status to be thrown which is fine. I don't think it was doing that when I originally opened the issue. This issue can probably be closed in that case.


Originally posted by @dstockto at https://github.com/zfcampus/zf-content-negotiation/issues/77#issuecomment-244582581