Hello community, here is the log from the commit of package perl-JSON-XS for openSUSE:Factory checked in at 2018-12-12 17:27:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-JSON-XS (Old) and /work/SRC/openSUSE:Factory/.perl-JSON-XS.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-JSON-XS" Wed Dec 12 17:27:12 2018 rev:21 rq:655789 version:4.0 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-JSON-XS/perl-JSON-XS.changes 2017-09-04 12:36:37.676933521 +0200 +++ /work/SRC/openSUSE:Factory/.perl-JSON-XS.new.28833/perl-JSON-XS.changes 2018-12-12 17:27:15.414970329 +0100 @@ -1,0 +2,6 @@ +Thu Dec 6 15:47:56 UTC 2018 - Stephan Kulow <co...@suse.com> + +- updated to 4.0 + see /usr/share/doc/packages/perl-JSON-XS/Changes + +------------------------------------------------------------------- Old: ---- JSON-XS-3.04.tar.gz New: ---- JSON-XS-4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-JSON-XS.spec ++++++ --- /var/tmp/diff_new_pack.0LjaqV/_old 2018-12-12 17:27:16.050969521 +0100 +++ /var/tmp/diff_new_pack.0LjaqV/_new 2018-12-12 17:27:16.050969521 +0100 @@ -1,7 +1,7 @@ # # spec file for package perl-JSON-XS # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,19 +12,18 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: perl-JSON-XS -Version: 3.04 +Version: 4.0 Release: 0 -#Upstream: CHECK(GPL-1.0+ or Artistic-1.0) %define cpan_name JSON-XS Summary: JSON serialising/deserialising, done correctly and fast -License: Artistic-1.0 or GPL-1.0+ +License: Artistic-1.0 OR GPL-1.0-or-later Group: Development/Libraries/Perl -Url: http://search.cpan.org/dist/JSON-XS/ +Url: https://metacpan.org/release/%{cpan_name} Source0: https://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/%{cpan_name}-%{version}.tar.gz Source1: cpanspec.yml BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -42,20 +41,6 @@ primary goal is to be _correct_ and its secondary goal is to be _fast_. To reach the latter goal it was written in C. -Beginning with version 2.0 of the JSON module, when both JSON and JSON::XS -are installed, then JSON will fall back on JSON::XS (this can be -overridden) with no overhead due to emulation (by inheriting constructor -and methods). If JSON::XS is not available, it will fall back to the -compatible JSON::PP module as backend, so using JSON instead of JSON::XS -gives you a portable JSON API that can be fast when you need it and doesn't -require a C compiler when that is a problem. - -As this is the n-th-something JSON module on CPAN, what was the reason to -write yet another JSON module? While it seems there are many JSON modules, -none of them correctly handle all corner cases, and in most cases their -maintainers are unresponsive, gone missing, or not listening to bug reports -for other reasons. - See MAPPING, below, on how JSON::XS maps perl values to JSON values and vice versa. @@ -64,11 +49,11 @@ find . -type f ! -name \*.pl -print0 | xargs -0 chmod 644 %build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="%{optflags}" -%{__make} %{?_smp_mflags} +perl Makefile.PL INSTALLDIRS=vendor OPTIMIZE="%{optflags}" +make %{?_smp_mflags} %check -%{__make} test +make test %install %perl_make_install ++++++ JSON-XS-3.04.tar.gz -> JSON-XS-4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/Changes new/JSON-XS-4.0/Changes --- old/JSON-XS-3.04/Changes 2017-08-17 04:31:27.000000000 +0200 +++ new/JSON-XS-4.0/Changes 2018-11-19 11:26:51.000000000 +0100 @@ -1,13 +1,27 @@ Revision history for Perl extension JSON::XS -TODO: maybe detetc and croak on more invalid inputs (e.g. +-inf/nan) +TODO: maybe detect and croak on more invalid inputs (e.g. +-inf/nan) TODO: maybe avoid the reblessing and better support readonly objects. -TODO: http://stevehanov.ca/blog/index.php?id=104 compression TODO: how to cope with tagged values and standard json decoders TODO: investigate magic (Eric Brine) -TODO: rfc7464 -TODO: Victor Efimov -TODO: move json_xs to types::serialiser +TODO: [PATCH] Types::Serialiser: Inline true(), false() and error() functions + +4.0 Fri Nov 16 00:06:54 CET 2018 + - 4.0 pre-release, do not use other than for testing. + - SECURITY IMPLICATION: this release enables allow_nonref by default + for compatibnility with RFC 7159 and newer. See "old" vs. "new" + JSON under SECURITY CONSIDERATIONS. + - reworked the "old" vs. "new" JSON section. + - add ->boolean_values to provide the values to which booleans + decode (requested by Aristotle Pagaltzis). + - decode would wrongly accept ASCII NUL characters instead of + reporting them as trailing garbage. + - work around what smells like a perl bug w.r.t. exceptions + thrown in callbacks. + - incremental parser now more or less respects allow_nonref. + - json_xs json-pretty now enables canonical mode. + - add documentation section about I-JSON. + - minor documentation fixes/updates. 3.04 Thu Aug 17 04:30:47 CEST 2017 - change exponential realloc algorithm on encoding and string decoding to be diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/META.json new/JSON-XS-4.0/META.json --- old/JSON-XS-3.04/META.json 2017-08-17 05:47:47.000000000 +0200 +++ new/JSON-XS-4.0/META.json 2018-11-19 11:27:09.000000000 +0100 @@ -4,7 +4,7 @@ "unknown" ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010", + "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "unknown" ], @@ -39,6 +39,6 @@ } }, "release_status" : "stable", - "version" : 3.04, + "version" : "4.0", "x_serialization_backend" : "JSON::PP version 2.27300" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/META.yml new/JSON-XS-4.0/META.yml --- old/JSON-XS-3.04/META.yml 2017-08-17 05:47:47.000000000 +0200 +++ new/JSON-XS-4.0/META.yml 2018-11-19 11:27:09.000000000 +0100 @@ -8,7 +8,7 @@ Canary::Stability: '0' ExtUtils::MakeMaker: '6.52' dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010' +generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -21,5 +21,5 @@ requires: Types::Serialiser: '0' common::sense: '0' -version: 3.04 +version: '4.0' x_serialization_backend: 'CPAN::Meta::YAML version 0.012' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/README new/JSON-XS-4.0/README --- old/JSON-XS-3.04/README 2017-08-17 05:47:47.000000000 +0200 +++ new/JSON-XS-4.0/README 2018-11-19 11:27:10.000000000 +0100 @@ -32,20 +32,6 @@ primary goal is to be *correct* and its secondary goal is to be *fast*. To reach the latter goal it was written in C. - Beginning with version 2.0 of the JSON module, when both JSON and - JSON::XS are installed, then JSON will fall back on JSON::XS (this can - be overridden) with no overhead due to emulation (by inheriting - constructor and methods). If JSON::XS is not available, it will fall - back to the compatible JSON::PP module as backend, so using JSON instead - of JSON::XS gives you a portable JSON API that can be fast when you need - it and doesn't require a C compiler when that is a problem. - - As this is the n-th-something JSON module on CPAN, what was the reason - to write yet another JSON module? While it seems there are many JSON - modules, none of them correctly handle all corner cases, and in most - cases their maintainers are unresponsive, gone missing, or not listening - to bug reports for other reasons. - See MAPPING, below, on how JSON::XS maps perl values to JSON values and vice versa. @@ -105,8 +91,8 @@ Except being faster. $perl_scalar = decode_json $json_text - The opposite of "encode_json": expects an UTF-8 (binary) string and - tries to parse that as an UTF-8 encoded JSON text, returning the + The opposite of "encode_json": expects a UTF-8 (binary) string and + tries to parse that as a UTF-8 encoded JSON text, returning the resulting reference. Croaks on error. This function call is functionally identical to: @@ -160,8 +146,9 @@ $json = new JSON::XS Creates a new JSON::XS object that can be used to de/encode JSON - strings. All boolean flags described below are by default - *disabled*. + strings. All boolean flags described below are by default *disabled* + (with the exception of "allow_nonref", which defaults to *enabled* + since version 4.0). The mutators for flags all return the JSON object again and thus calls can be chained: @@ -227,7 +214,7 @@ $enabled = $json->get_utf8 If $enable is true (or missing), then the "encode" method will encode the JSON result into UTF-8, as required by many protocols, - while the "decode" method expects to be handled an UTF-8-encoded + while the "decode" method expects to be handed a UTF-8-encoded string. Please note that UTF-8-encoded strings do not contain any characters outside the range 0..255, they are thus useful for bytewise/binary I/O. In future versions, enabling this option might @@ -316,7 +303,7 @@ $enabled = $json->get_relaxed If $enable is true (or missing), then "decode" will accept some extensions to normal JSON syntax (see below). "encode" will not be - affected in anyway. *Be aware that this option makes you accept + affected in any way. *Be aware that this option makes you accept invalid JSON texts as if they were valid!*. I suggest only to use this option to parse application-specific files written by humans (configuration files, resource files etc.) @@ -387,6 +374,10 @@ $json = $json->allow_nonref ([$enable]) $enabled = $json->get_allow_nonref + Unlike other boolean options, this opotion is enabled by default + beginning with version 4.0. See "SECURITY CONSIDERATIONS" for the + gory details. + If $enable is true (or missing), then the "encode" method can convert a non-reference into its corresponding string, number or null JSON value, which is an extension to RFC4627. Likewise, @@ -397,11 +388,11 @@ object or array. Likewise, "decode" will croak if given something that is not a JSON object or array. - Example, encode a Perl scalar as JSON value with enabled - "allow_nonref", resulting in an invalid JSON text: + Example, encode a Perl scalar as JSON value without enabled + "allow_nonref", resulting in an error: - JSON::XS->new->allow_nonref->encode ("Hello, World!") - => "Hello, World!" + JSON::XS->new->allow_nonref (0)->encode ("Hello, World!") + => hash- or arrayref expected... $json = $json->allow_unknown ([$enable]) $enabled = $json->get_allow_unknown @@ -457,7 +448,7 @@ This setting has no effect on "decode". $json = $json->allow_tags ([$enable]) - $enabled = $json->allow_tags + $enabled = $json->get_allow_tags See "OBJECT SERIALISATION" for details. If $enable is true (or missing), then "encode", upon encountering a @@ -473,15 +464,32 @@ this type of conversion, and tagged JSON values will cause a parse error in "decode", as if tags were not part of the grammar. + $json->boolean_values ([$false, $true]) + ($false, $true) = $json->get_boolean_values + By default, JSON booleans will be decoded as overloaded + $Types::Serialiser::false and $Types::Serialiser::true objects. + + With this method you can specify your own boolean values for + decoding - on decode, JSON "false" will be decoded as a copy of + $false, and JSON "true" will be decoded as $true ("copy" here is the + same thing as assigning a value to another variable, i.e. "$copy = + $false"). + + Calling this method without any arguments will reset the booleans to + their default values. + + "get_boolean_values" will return both $false and $true values, or + the empty list when they are set to the default. + $json = $json->filter_json_object ([$coderef->($hashref)]) When $coderef is specified, it will be called from "decode" each time it decodes a JSON object. The only argument is a reference to - the newly-created hash. If the code references returns a single - scalar (which need not be a reference), this value (i.e. a copy of - that scalar to avoid aliasing) is inserted into the deserialised - data structure. If it returns an empty list (NOTE: *not* "undef", - which is a valid scalar), the original deserialised hash will be - inserted. This setting can slow down decoding considerably. + the newly-created hash. If the code reference returns a single + scalar (which need not be a reference), this value (or rather a copy + of it) is inserted into the deserialised data structure. If it + returns an empty list (NOTE: *not* "undef", which is a valid + scalar), the original deserialised hash will be inserted. This + setting can slow down decoding considerably. When $coderef is omitted or undefined, any existing callback will be removed and "decode" will not change the deserialised hash in any @@ -726,16 +734,19 @@ parser after each successful decode. LIMITATIONS - All options that affect decoding are supported, except "allow_nonref". - The reason for this is that it cannot be made to work sensibly: JSON - objects and arrays are self-delimited, i.e. you can concatenate them - back to back and still decode them perfectly. This does not hold true - for JSON numbers, however. - - For example, is the string 1 a single JSON number, or is it simply the - start of 12? Or is 12 a single JSON number, or the concatenation of 1 - and 2? In neither case you can tell, and this is why JSON::XS takes the - conservative route and disallows this case. + The incremental parser is a non-exact parser: it works by gathering as + much text as possible that *could* be a valid JSON text, followed by + trying to decode it. + + That means it sometimes needs to read more data than strictly necessary + to diagnose an invalid JSON text. For example, after parsing the + following fragment, the parser *could* stop with an error, as this + fragment *cannot* be the beginning of a valid JSON text: + + [, + + In reality, hopwever, the parser might continue to read data until a + length limit is exceeded or it finds a closing bracket. EXAMPLES Some examples will make all this clearer. First, a simple example that @@ -1178,8 +1189,8 @@ does not allow that. The "utf8" flag therefore switches between two modes: disabled means - you will get a Unicode string in Perl, enabled means you get an - UTF-8 encoded octet/binary string in Perl. + you will get a Unicode string in Perl, enabled means you get a UTF-8 + encoded octet/binary string in Perl. "latin1" or "ascii" flags enabled With "latin1" (or "ascii") enabled, "encode" will escape characters @@ -1445,44 +1456,94 @@ deal with it, as major browser developers care only for features, not about getting security right). -"OLD" VS. "NEW" JSON (RFC 4627 VS. RFC 7159) - TL;DR: Due to security concerns, JSON::XS will not allow scalar data in - JSON texts by default - you need to create your own JSON::XS object and - enable "allow_nonref": - - my $json = JSON::XS->new->allow_nonref; - - $text = $json->encode ($data); - $data = $json->decode ($text); - - The long version: JSON being an important and supposedly stable format, - the IETF standardised it as RFC 4627 in 2006. Unfortunately, the - inventor of JSON, Dougles Crockford, unilaterally changed the definition - of JSON in javascript. Rather than create a fork, the IETF decided to - standardise the new syntax (apparently, so Iw as told, without finding - it very amusing). - - The biggest difference between thed original JSON and the new JSON is - that the new JSON supports scalars (anything other than arrays and - objects) at the toplevel of a JSON text. While this is strictly - backwards compatible to older versions, it breaks a number of protocols - that relied on sending JSON back-to-back, and is a minor security - concern. - - For example, imagine you have two banks communicating, and on one side, - trhe JSON coder gets upgraded. Two messages, such as 10 and 1000 might - then be confused to mean 101000, something that couldn't happen in the - original JSON, because niether of these messages would be valid JSON. - - If one side accepts these messages, then an upgrade in the coder on - either side could result in this becoming exploitable. - - This module has always allowed these messages as an optional extension, - by default disabled. The security concerns are the reason why the - default is still disabled, but future versions might/will likely upgrade - to the newer RFC as default format, so you are advised to check your - implementation and/or override the default with "->allow_nonref (0)" to - ensure that future versions are safe. + "OLD" VS. "NEW" JSON (RFC4627 VS. RFC7159) + JSON originally required JSON texts to represent an array or object - + scalar values were explicitly not allowed. This has changed, and + versions of JSON::XS beginning with 4.0 reflect this by allowing scalar + values by default. + + One reason why one might not want this is that this removes a + fundamental property of JSON texts, namely that they are self-delimited + and self-contained, or in other words, you could take any number of + "old" JSON texts and paste them together, and the result would be + unambiguously parseable: + + [1,3]{"k":5}[][null] # four JSON texts, without doubt + + By allowing scalars, this property is lost: in the following example, is + this one JSON text (the number 12) or two JSON texts (the numbers 1 and + 2): + + 12 # could be 12, or 1 and 2 + + Another lost property of "old" JSON is that no lookahead is required to + know the end of a JSON text, i.e. the JSON text definitely ended at the + last "]" or "}" character, there was no need to read extra characters. + + For example, a viable network protocol with "old" JSON was to simply + exchange JSON texts without delimiter. For "new" JSON, you have to use a + suitable delimiter (such as a newline) after every JSON text or ensure + you never encode/decode scalar values. + + Most protocols do work by only transferring arrays or objects, and the + easiest way to avoid problems with the "new" JSON definition is to + explicitly disallow scalar values in your encoder and decoder: + + $json_coder = JSON::XS->new->allow_nonref (0) + + This is a somewhat unhappy situation, and the blame can fully be put on + JSON's inmventor, Douglas Crockford, who unilaterally changed the format + in 2006 without consulting the IETF, forcing the IETF to either fork the + format or go with it (as I was told, the IETF wasn't amused). + +RELATIONSHIP WITH I-JSON + JSON is a somewhat sloppily-defined format - it carries around obvious + Javascript baggage, such as not really defining number range, probably + because Javascript only has one type of numbers: IEEE 64 bit floats + ("binary64"). + + For this reaosn, RFC7493 defines "Internet JSON", which is a restricted + subset of JSON that is supposedly more interoperable on the internet. + + While "JSON::XS" does not offer specific support for I-JSON, it of + course accepts valid I-JSON and by default implements some of the + limitations of I-JSON, such as parsing numbers as perl numbers, which + are usually a superset of binary64 numbers. + + To generate I-JSON, follow these rules: + + * always generate UTF-8 + + I-JSON must be encoded in UTF-8, the default for "encode_json". + + * numbers should be within IEEE 754 binary64 range + + Basically all existing perl installations use binary64 to represent + floating point numbers, so all you need to do is to avoid large + integers. + + * objects must not have duplicate keys + + This is trivially done, as "JSON::XS" does not allow duplicate keys. + + * do not generate scalar JSON texts, use "->allow_nonref (0)" + + I-JSON strongly requests you to only encode arrays and objects into + JSON. + + * times should be strings in ISO 8601 format + + There are a myriad of modules on CPAN dealing with ISO 8601 - search + for "ISO8601" on CPAN and use one. + + * encode binary data as base64 + + While it's tempting to just dump binary data as a string (and let + "JSON::XS" do the escaping), for I-JSON, it's *recommended* to + encode binary data as base64. + + There are some other considerations - read RFC7493 for the details if + interested. INTEROPERABILITY WITH OTHER MODULES "JSON::XS" uses the Types::Serialiser module to provide boolean @@ -1549,26 +1610,10 @@ Again, this has some limitations - the magic string must not be encoded with character escapes, and the constructor arguments must be non-empty. -RFC7159 - Since this module was written, Google has written a new JSON RFC, RFC - 7159 (and RFC7158). Unfortunately, this RFC breaks compatibility with - both the original JSON specification on www.json.org and RFC4627. - - As far as I can see, you can get partial compatibility when parsing by - using "->allow_nonref". However, consider the security implications of - doing so. - - I haven't decided yet when to break compatibility with RFC4627 by - default (and potentially leave applications insecure) and change the - default to follow RFC7159, but application authors are well advised to - call "->allow_nonref(0)" even if this is the current default, if they - cannot handle non-reference values, in preparation for the day when the - default will change. - (I-)THREADS This module is *not* guaranteed to be ithread (or MULTIPLICITY-) safe and there are no plans to change this. Note that perl's builtin - so-called theeads/ithreads are officially deprecated and should not be + so-called threads/ithreads are officially deprecated and should not be used. THE PERILS OF SETLOCALE @@ -1587,6 +1632,30 @@ actually needs it (avoiding stringification of numbers), and restore it afterwards. +SOME HISTORY + At the time this module was created there already were a number of JSON + modules available on CPAN, so what was the reason to write yet another + JSON module? While it seems there are many JSON modules, none of them + correctly handled all corner cases, and in most cases their maintainers + are unresponsive, gone missing, or not listening to bug reports for + other reasons. + + Beginning with version 2.0 of the JSON module, when both JSON and + JSON::XS are installed, then JSON will fall back on JSON::XS (this can + be overridden) with no overhead due to emulation (by inheriting + constructor and methods). If JSON::XS is not available, it will fall + back to the compatible JSON::PP module as backend, so using JSON instead + of JSON::XS gives you a portable JSON API that can be fast when you need + it and doesn't require a C compiler when that is a problem. + + Somewhere around version 3, this module was forked into + "Cpanel::JSON::XS", because its maintainer had serious trouble + understanding JSON and insisted on a fork with many bugs "fixed" that + weren't actually bugs, while spreading FUD about this module without + actually giving any details on his accusations. You be the judge, but in + my personal opinion, if you want quality, you will stay away from + dangerous forks like that. + BUGS While the goal of this module is to be correct, that unfortunately does not mean it's bug-free, only that I think its design is bug-free. If you diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/XS.pm new/JSON-XS-4.0/XS.pm --- old/JSON-XS-3.04/XS.pm 2017-08-17 04:31:35.000000000 +0200 +++ new/JSON-XS-4.0/XS.pm 2018-11-19 11:26:55.000000000 +0100 @@ -37,26 +37,12 @@ primary goal is to be I<correct> and its secondary goal is to be I<fast>. To reach the latter goal it was written in C. -Beginning with version 2.0 of the JSON module, when both JSON and -JSON::XS are installed, then JSON will fall back on JSON::XS (this can be -overridden) with no overhead due to emulation (by inheriting constructor -and methods). If JSON::XS is not available, it will fall back to the -compatible JSON::PP module as backend, so using JSON instead of JSON::XS -gives you a portable JSON API that can be fast when you need it and -doesn't require a C compiler when that is a problem. - -As this is the n-th-something JSON module on CPAN, what was the reason -to write yet another JSON module? While it seems there are many JSON -modules, none of them correctly handle all corner cases, and in most cases -their maintainers are unresponsive, gone missing, or not listening to bug -reports for other reasons. - See MAPPING, below, on how JSON::XS maps perl values to JSON values and vice versa. =head2 FEATURES -=over 4 +=over =item * correct Unicode handling @@ -103,7 +89,7 @@ use common::sense; -our $VERSION = 3.04; +our $VERSION = '4.0'; our @ISA = qw(Exporter); our @EXPORT = qw(encode_json decode_json); @@ -118,7 +104,7 @@ The following convenience methods are provided by this module. They are exported by default: -=over 4 +=over =item $json_text = encode_json $perl_scalar @@ -133,8 +119,8 @@ =item $perl_scalar = decode_json $json_text -The opposite of C<encode_json>: expects an UTF-8 (binary) string and tries -to parse that as an UTF-8 encoded JSON text, returning the resulting +The opposite of C<encode_json>: expects a UTF-8 (binary) string and tries +to parse that as a UTF-8 encoded JSON text, returning the resulting reference. Croaks on error. This function call is functionally identical to: @@ -151,7 +137,7 @@ Since this often leads to confusion, here are a few very clear words on how Unicode works in Perl, modulo bugs. -=over 4 +=over =item 1. Perl strings can store characters with ordinal values > 255. @@ -199,12 +185,14 @@ The object oriented interface lets you configure your own encoding or decoding style, within the limits of supported formats. -=over 4 +=over =item $json = new JSON::XS Creates a new JSON::XS object that can be used to de/encode JSON -strings. All boolean flags described below are by default I<disabled>. +strings. All boolean flags described below are by default I<disabled> +(with the exception of C<allow_nonref>, which defaults to I<enabled> since +version C<4.0>). The mutators for flags all return the JSON object again and thus calls can be chained: @@ -272,7 +260,7 @@ If C<$enable> is true (or missing), then the C<encode> method will encode the JSON result into UTF-8, as required by many protocols, while the -C<decode> method expects to be handled an UTF-8-encoded string. Please +C<decode> method expects to be handed a UTF-8-encoded string. Please note that UTF-8-encoded strings do not contain any characters outside the range C<0..255>, they are thus useful for bytewise/binary I/O. In future versions, enabling this option might enable autodetection of the UTF-16 @@ -367,7 +355,7 @@ If C<$enable> is true (or missing), then C<decode> will accept some extensions to normal JSON syntax (see below). C<encode> will not be -affected in anyway. I<Be aware that this option makes you accept invalid +affected in any way. I<Be aware that this option makes you accept invalid JSON texts as if they were valid!>. I suggest only to use this option to parse application-specific files written by humans (configuration files, resource files etc.) @@ -377,7 +365,7 @@ Currently accepted extensions are: -=over 4 +=over =item * list items can have an end-comma @@ -443,6 +431,9 @@ =item $enabled = $json->get_allow_nonref +Unlike other boolean options, this opotion is enabled by default beginning +with version C<4.0>. See L<SECURITY CONSIDERATIONS> for the gory details. + If C<$enable> is true (or missing), then the C<encode> method can convert a non-reference into its corresponding string, number or null JSON value, which is an extension to RFC4627. Likewise, C<decode> will accept those JSON @@ -453,11 +444,11 @@ or array. Likewise, C<decode> will croak if given something that is not a JSON object or array. -Example, encode a Perl scalar as JSON value with enabled C<allow_nonref>, -resulting in an invalid JSON text: +Example, encode a Perl scalar as JSON value without enabled C<allow_nonref>, +resulting in an error: - JSON::XS->new->allow_nonref->encode ("Hello, World!") - => "Hello, World!" + JSON::XS->new->allow_nonref (0)->encode ("Hello, World!") + => hash- or arrayref expected... =item $json = $json->allow_unknown ([$enable]) @@ -517,7 +508,7 @@ =item $json = $json->allow_tags ([$enable]) -=item $enabled = $json->allow_tags +=item $enabled = $json->get_allow_tags See L<OBJECT SERIALISATION> for details. @@ -533,16 +524,34 @@ this type of conversion, and tagged JSON values will cause a parse error in C<decode>, as if tags were not part of the grammar. +=item $json->boolean_values ([$false, $true]) + +=item ($false, $true) = $json->get_boolean_values + +By default, JSON booleans will be decoded as overloaded +C<$Types::Serialiser::false> and C<$Types::Serialiser::true> objects. + +With this method you can specify your own boolean values for decoding - +on decode, JSON C<false> will be decoded as a copy of C<$false>, and JSON +C<true> will be decoded as C<$true> ("copy" here is the same thing as +assigning a value to another variable, i.e. C<$copy = $false>). + +Calling this method without any arguments will reset the booleans +to their default values. + +C<get_boolean_values> will return both C<$false> and C<$true> values, or +the empty list when they are set to the default. + =item $json = $json->filter_json_object ([$coderef->($hashref)]) When C<$coderef> is specified, it will be called from C<decode> each -time it decodes a JSON object. The only argument is a reference to the -newly-created hash. If the code references returns a single scalar (which -need not be a reference), this value (i.e. a copy of that scalar to avoid -aliasing) is inserted into the deserialised data structure. If it returns -an empty list (NOTE: I<not> C<undef>, which is a valid scalar), the -original deserialised hash will be inserted. This setting can slow down -decoding considerably. +time it decodes a JSON object. The only argument is a reference to +the newly-created hash. If the code reference returns a single scalar +(which need not be a reference), this value (or rather a copy of it) is +inserted into the deserialised data structure. If it returns an empty +list (NOTE: I<not> C<undef>, which is a valid scalar), the original +deserialised hash will be inserted. This setting can slow down decoding +considerably. When C<$coderef> is omitted or undefined, any existing callback will be removed and C<decode> will not change the deserialised hash in any @@ -726,7 +735,7 @@ The following methods implement this incremental parser. -=over 4 +=over =item [void, scalar or list context] = $json->incr_parse ([$string]) @@ -803,16 +812,19 @@ =head2 LIMITATIONS -All options that affect decoding are supported, except -C<allow_nonref>. The reason for this is that it cannot be made to work -sensibly: JSON objects and arrays are self-delimited, i.e. you can -concatenate them back to back and still decode them perfectly. This does -not hold true for JSON numbers, however. - -For example, is the string C<1> a single JSON number, or is it simply the -start of C<12>? Or is C<12> a single JSON number, or the concatenation -of C<1> and C<2>? In neither case you can tell, and this is why JSON::XS -takes the conservative route and disallows this case. +The incremental parser is a non-exact parser: it works by gathering as +much text as possible that I<could> be a valid JSON text, followed by +trying to decode it. + +That means it sometimes needs to read more data than strictly necessary to +diagnose an invalid JSON text. For example, after parsing the following +fragment, the parser I<could> stop with an error, as this fragment +I<cannot> be the beginning of a valid JSON text: + + [, + +In reality, hopwever, the parser might continue to read data until a +length limit is exceeded or it finds a closing bracket. =head2 EXAMPLES @@ -966,7 +978,7 @@ =head2 JSON -> PERL -=over 4 +=over =item object @@ -1044,7 +1056,7 @@ truly typeless language, so we can only guess which JSON type is meant by a Perl value. -=over 4 +=over =item hash references @@ -1143,7 +1155,7 @@ C<allow_blessed>, C<convert_blessed> and C<allow_tags> settings, which are used in this order: -=over 4 +=over =item 1. C<allow_tags> is enabled and the object has a C<FREEZE> method. @@ -1264,7 +1276,7 @@ and ISO-8859-1 (= latin 1) and ASCII are both codesets I<and> encodings at the same time, which can be confusing. -=over 4 +=over =item C<utf8> flag disabled @@ -1291,7 +1303,7 @@ that. The C<utf8> flag therefore switches between two modes: disabled means you -will get a Unicode string in Perl, enabled means you get an UTF-8 encoded +will get a Unicode string in Perl, enabled means you get a UTF-8 encoded octet/binary string in Perl. =item C<latin1> or C<ascii> flags enabled @@ -1433,7 +1445,7 @@ high that you will run into severe interoperability problems when you least expect it. -=over 4 +=over =item (*) @@ -1569,45 +1581,99 @@ security right). -=head1 "OLD" VS. "NEW" JSON (RFC 4627 VS. RFC 7159) +=head2 "OLD" VS. "NEW" JSON (RFC4627 VS. RFC7159) + +JSON originally required JSON texts to represent an array or object - +scalar values were explicitly not allowed. This has changed, and versions +of JSON::XS beginning with C<4.0> reflect this by allowing scalar values +by default. + +One reason why one might not want this is that this removes a fundamental +property of JSON texts, namely that they are self-delimited and +self-contained, or in other words, you could take any number of "old" +JSON texts and paste them together, and the result would be unambiguously +parseable: + + [1,3]{"k":5}[][null] # four JSON texts, without doubt + +By allowing scalars, this property is lost: in the following example, is +this one JSON text (the number 12) or two JSON texts (the numbers 1 and +2): + + 12 # could be 12, or 1 and 2 + +Another lost property of "old" JSON is that no lookahead is required to +know the end of a JSON text, i.e. the JSON text definitely ended at the +last C<]> or C<}> character, there was no need to read extra characters. + +For example, a viable network protocol with "old" JSON was to simply +exchange JSON texts without delimiter. For "new" JSON, you have to use a +suitable delimiter (such as a newline) after every JSON text or ensure you +never encode/decode scalar values. + +Most protocols do work by only transferring arrays or objects, and the +easiest way to avoid problems with the "new" JSON definition is to +explicitly disallow scalar values in your encoder and decoder: + + $json_coder = JSON::XS->new->allow_nonref (0) + +This is a somewhat unhappy situation, and the blame can fully be put on +JSON's inmventor, Douglas Crockford, who unilaterally changed the format +in 2006 without consulting the IETF, forcing the IETF to either fork the +format or go with it (as I was told, the IETF wasn't amused). + + +=head1 RELATIONSHIP WITH I-JSON + +JSON is a somewhat sloppily-defined format - it carries around obvious +Javascript baggage, such as not really defining number range, probably +because Javascript only has one type of numbers: IEEE 64 bit floats +("binary64"). + +For this reaosn, RFC7493 defines "Internet JSON", which is a restricted +subset of JSON that is supposedly more interoperable on the internet. -TL;DR: Due to security concerns, JSON::XS will not allow scalar data in -JSON texts by default - you need to create your own JSON::XS object and -enable C<allow_nonref>: - - - my $json = JSON::XS->new->allow_nonref; - - $text = $json->encode ($data); - $data = $json->decode ($text); - -The long version: JSON being an important and supposedly stable format, -the IETF standardised it as RFC 4627 in 2006. Unfortunately, the inventor -of JSON, Dougles Crockford, unilaterally changed the definition of JSON in -javascript. Rather than create a fork, the IETF decided to standardise the -new syntax (apparently, so Iw as told, without finding it very amusing). - -The biggest difference between thed original JSON and the new JSON is that -the new JSON supports scalars (anything other than arrays and objects) at -the toplevel of a JSON text. While this is strictly backwards compatible -to older versions, it breaks a number of protocols that relied on sending -JSON back-to-back, and is a minor security concern. - -For example, imagine you have two banks communicating, and on one side, -trhe JSON coder gets upgraded. Two messages, such as C<10> and C<1000> -might then be confused to mean C<101000>, something that couldn't happen -in the original JSON, because niether of these messages would be valid -JSON. - -If one side accepts these messages, then an upgrade in the coder on either -side could result in this becoming exploitable. - -This module has always allowed these messages as an optional extension, by -default disabled. The security concerns are the reason why the default is -still disabled, but future versions might/will likely upgrade to the newer -RFC as default format, so you are advised to check your implementation -and/or override the default with C<< ->allow_nonref (0) >> to ensure that -future versions are safe. +While C<JSON::XS> does not offer specific support for I-JSON, it of course +accepts valid I-JSON and by default implements some of the limitations +of I-JSON, such as parsing numbers as perl numbers, which are usually a +superset of binary64 numbers. + +To generate I-JSON, follow these rules: + +=over + +=item * always generate UTF-8 + +I-JSON must be encoded in UTF-8, the default for C<encode_json>. + +=item * numbers should be within IEEE 754 binary64 range + +Basically all existing perl installations use binary64 to represent +floating point numbers, so all you need to do is to avoid large integers. + +=item * objects must not have duplicate keys + +This is trivially done, as C<JSON::XS> does not allow duplicate keys. + +=item * do not generate scalar JSON texts, use C<< ->allow_nonref (0) >> + +I-JSON strongly requests you to only encode arrays and objects into JSON. + +=item * times should be strings in ISO 8601 format + +There are a myriad of modules on CPAN dealing with ISO 8601 - search for +C<ISO8601> on CPAN and use one. + +=item * encode binary data as base64 + +While it's tempting to just dump binary data as a string (and let +C<JSON::XS> do the escaping), for I-JSON, it's I<recommended> to encode +binary data as base64. + +=back + +There are some other considerations - read RFC7493 for the details if +interested. =head1 INTEROPERABILITY WITH OTHER MODULES @@ -1680,29 +1746,11 @@ with character escapes, and the constructor arguments must be non-empty. -=head1 RFC7159 - -Since this module was written, Google has written a new JSON RFC, RFC 7159 -(and RFC7158). Unfortunately, this RFC breaks compatibility with both the -original JSON specification on www.json.org and RFC4627. - -As far as I can see, you can get partial compatibility when parsing by -using C<< ->allow_nonref >>. However, consider the security implications -of doing so. - -I haven't decided yet when to break compatibility with RFC4627 by default -(and potentially leave applications insecure) and change the default to -follow RFC7159, but application authors are well advised to call C<< -->allow_nonref(0) >> even if this is the current default, if they cannot -handle non-reference values, in preparation for the day when the default -will change. - - =head1 (I-)THREADS This module is I<not> guaranteed to be ithread (or MULTIPLICITY-) safe and there are no plans to change this. Note that perl's builtin so-called -theeads/ithreads are officially deprecated and should not be used. +threads/ithreads are officially deprecated and should not be used. =head1 THE PERILS OF SETLOCALE @@ -1723,6 +1771,32 @@ afterwards. +=head1 SOME HISTORY + +At the time this module was created there already were a number of JSON +modules available on CPAN, so what was the reason to write yet another +JSON module? While it seems there are many JSON modules, none of them +correctly handled all corner cases, and in most cases their maintainers +are unresponsive, gone missing, or not listening to bug reports for other +reasons. + +Beginning with version 2.0 of the JSON module, when both JSON and +JSON::XS are installed, then JSON will fall back on JSON::XS (this can be +overridden) with no overhead due to emulation (by inheriting constructor +and methods). If JSON::XS is not available, it will fall back to the +compatible JSON::PP module as backend, so using JSON instead of JSON::XS +gives you a portable JSON API that can be fast when you need it and +doesn't require a C compiler when that is a problem. + +Somewhere around version 3, this module was forked into +C<Cpanel::JSON::XS>, because its maintainer had serious trouble +understanding JSON and insisted on a fork with many bugs "fixed" that +weren't actually bugs, while spreading FUD about this module without +actually giving any details on his accusations. You be the judge, but +in my personal opinion, if you want quality, you will stay away from +dangerous forks like that. + + =head1 BUGS While the goal of this module is to be correct, that unfortunately does diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/XS.xs new/JSON-XS-4.0/XS.xs --- old/JSON-XS-3.04/XS.xs 2017-08-17 03:54:33.000000000 +0200 +++ new/JSON-XS-4.0/XS.xs 2018-11-15 23:20:25.000000000 +0100 @@ -52,7 +52,7 @@ #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER -#define INIT_SIZE 32 // initial scalar size to be allocated +#define INIT_SIZE 64 // initial scalar size to be allocated #define INDENT_STEP 3 // spaces per indentation level #define SHORT_STRING_LEN 16384 // special-case strings of up to this size @@ -80,23 +80,26 @@ #define ERR_NESTING_EXCEEDED "json text or perl structure exceeds maximum nesting level (max_depth set too low?)" #ifdef USE_ITHREADS -# define JSON_SLOW 1 -# define JSON_STASH (json_stash ? json_stash : gv_stashpv ("JSON::XS", 1)) -# define BOOL_STASH (bool_stash ? bool_stash : gv_stashpv ("Types::Serialiser::Boolean", 1)) +# define JSON_STASH (expect_true (json_stash) ? json_stash : gv_stashpv ("JSON::XS", 1)) +# define BOOL_STASH (expect_true (bool_stash) ? bool_stash : gv_stashpv ("Types::Serialiser::Boolean", 1)) +# define GET_BOOL(value) (expect_true (bool_ ## value) ? bool_ ## value : get_bool ("Types::Serialiser::" # value)) #else -# define JSON_SLOW 0 # define JSON_STASH json_stash # define BOOL_STASH bool_stash +# define GET_BOOL(value) bool_ ## value #endif // the amount of HEs to allocate on the stack, when sorting keys #define STACK_HES 64 static HV *json_stash, *bool_stash; // JSON::XS::, Types::Serialiser::Boolean:: -static SV *bool_true, *bool_false, *sv_json; +static SV *bool_false, *bool_true; +static SV *sv_json; enum { INCR_M_WS = 0, // initial whitespace skipping, must be 0 + INCR_M_TFN, // inside true/false/null + INCR_M_NUM, // inside number INCR_M_STR, // inside string INCR_M_BS, // inside backslash INCR_M_C0, // inside comment in initial whitespace sequence @@ -119,13 +122,16 @@ STRLEN incr_pos; // the current offset into the text int incr_nest; // {[]}-nesting level unsigned char incr_mode; + + SV *v_false, *v_true; } JSON; INLINE void json_init (JSON *json) { - Zero (json, 1, JSON); - json->max_depth = 512; + static const JSON init = { F_ALLOW_NONREF, 512 }; + + *json = init; } ///////////////////////////////////////////////////////////////////////////// @@ -182,7 +188,7 @@ return SvGROW (sv, len1); } -// decode an utf-8 character and return it, or (UV)-1 in +// decode a utf-8 character and return it, or (UV)-1 in // case of an error. // we special-case "safe" characters from U+80 .. U+7FF, // but use the very good perl function to parse anything else. @@ -778,10 +784,8 @@ if (stash == bool_stash) { - if (SvIV (sv)) - encode_str (enc, "true", 4, 0); - else - encode_str (enc, "false", 5, 0); + if (SvIV (sv)) encode_str (enc, "true" , 4, 0); + else encode_str (enc, "false", 5, 0); } else if ((enc->json.flags & F_ALLOW_TAGS) && (method = gv_fetchmethod_autoload (stash, "FREEZE", 0))) { @@ -789,7 +793,6 @@ dSP; ENTER; SAVETMPS; - SAVESTACK_POS (); PUSHMARK (SP); EXTEND (SP, 2); // we re-bless the reference to get overload and other niceties right @@ -811,12 +814,18 @@ encode_ch (enc, ')'); encode_ch (enc, '['); - while (count) + if (count) { - encode_sv (enc, SP[1 - count--]); + int i; - if (count) - encode_ch (enc, ','); + for (i = 0; i < count - 1; ++i) + { + encode_sv (enc, SP[i + 1 - count]); + encode_ch (enc, ','); + } + + encode_sv (enc, TOPs); + SP -= count; } encode_ch (enc, ']'); @@ -1517,7 +1526,6 @@ int count; ENTER; SAVETMPS; - SAVESTACK_POS (); PUSHMARK (SP); XPUSHs (HeVAL (he)); sv_2mortal (sv); @@ -1530,6 +1538,8 @@ FREETMPS; LEAVE; return sv; } + else if (count) + croak ("filter_json_single_key_object callbacks must not return more than one scalar"); SvREFCNT_inc (sv); FREETMPS; LEAVE; @@ -1542,7 +1552,6 @@ int count; ENTER; SAVETMPS; - SAVESTACK_POS (); PUSHMARK (SP); XPUSHs (sv_2mortal (sv)); @@ -1554,6 +1563,8 @@ FREETMPS; LEAVE; return sv; } + else if (count) + croak ("filter_json_object callbacks must not return more than one scalar"); SvREFCNT_inc (sv); FREETMPS; LEAVE; @@ -1668,31 +1679,33 @@ case '5': case '6': case '7': case '8': case '9': return decode_num (dec); - case 't': - if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4)) + case 'f': + if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5)) { - dec->cur += 4; -#if JSON_SLOW - bool_true = get_bool ("Types::Serialiser::true"); -#endif - return newSVsv (bool_true); + dec->cur += 5; + + if (expect_false (!dec->json.v_false)) + dec->json.v_false = GET_BOOL (false); + + return newSVsv (dec->json.v_false); } else - ERR ("'true' expected"); + ERR ("'false' expected"); break; - case 'f': - if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5)) + case 't': + if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4)) { - dec->cur += 5; -#if JSON_SLOW - bool_false = get_bool ("Types::Serialiser::false"); -#endif - return newSVsv (bool_false); + dec->cur += 4; + + if (expect_false (!dec->json.v_true)) + dec->json.v_true = GET_BOOL (true); + + return newSVsv (dec->json.v_true); } else - ERR ("'false' expected"); + ERR ("'true' expected"); break; @@ -1786,7 +1799,7 @@ // check for trailing garbage decode_ws (&dec); - if (*dec.cur) + if (dec.cur != dec.end) { dec.err = "garbage after JSON object"; SvREFCNT_dec (sv); @@ -1834,9 +1847,17 @@ for (;;) { - //printf ("loop pod %d *p<%c><%s>, mode %d nest %d\n", p - SvPVX (self->incr_text), *p, p, self->incr_mode, self->incr_nest);//D switch (self->incr_mode) { + // reached end of a scalar, see if we are inside a nested structure or not + end_of_scalar: + self->incr_mode = INCR_M_JSON; + + if (self->incr_nest) // end of a scalar inside array, object or tag + goto incr_m_json; + else // end of scalar outside structure, json text ends here + goto interrupt; + // only used for initial whitespace skipping case INCR_M_WS: for (;;) @@ -1888,6 +1909,40 @@ break; + // inside true/false/null + case INCR_M_TFN: + incr_m_tfn: + for (;;) + switch (*p++) + { + case 'r': case 'u': case 'e': // tRUE, falsE, nUll + case 'a': case 'l': case 's': // fALSe, nuLL + // allowed + break; + + default: + --p; + goto end_of_scalar; + } + + // inside a number + case INCR_M_NUM: + incr_m_num: + for (;;) + switch (*p++) + { + case 'e': case 'E': case '.': case '+': + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // allowed + break; + + default: + --p; + goto end_of_scalar; + } + // inside a string case INCR_M_STR: incr_m_str: @@ -1896,12 +1951,7 @@ if (*p == '"') { ++p; - self->incr_mode = INCR_M_JSON; - - if (!self->incr_nest) - goto interrupt; - - goto incr_m_json; + goto end_of_scalar; } else if (*p == '\\') { @@ -1941,6 +1991,21 @@ } break; + // the following three blocks handle scalars. this makes the parser + // more strict than required inside arrays or objects, and could + // be moved to a special case on the toplevel (except strings) + case 't': + case 'f': + case 'n': + self->incr_mode = INCR_M_TFN; + goto incr_m_tfn; + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + self->incr_mode = INCR_M_NUM; + goto incr_m_num; + case '"': self->incr_mode = INCR_M_STR; goto incr_m_str; @@ -1997,8 +2062,8 @@ json_stash = gv_stashpv ("JSON::XS" , 1); bool_stash = gv_stashpv ("Types::Serialiser::Boolean", 1); - bool_true = get_bool ("Types::Serialiser::true"); bool_false = get_bool ("Types::Serialiser::false"); + bool_true = get_bool ("Types::Serialiser::true"); sv_json = newSVpv ("JSON", 0); SvREADONLY_on (sv_json); @@ -2010,8 +2075,13 @@ void CLONE (...) CODE: + // as long as these writes are atomic, the race should not matter + // as existing threads either already use 0, or use the old value, + // which is sitll correct for the initial thread. json_stash = 0; bool_stash = 0; + bool_false = 0; + bool_true = 0; void new (char *klass) PPCODE: @@ -2025,6 +2095,21 @@ ))); } +void boolean_values (JSON *self, SV *v_false = 0, SV *v_true = 0) + PPCODE: + self->v_false = newSVsv (v_false); + self->v_true = newSVsv (v_true); + XPUSHs (ST (0)); + +void get_boolean_values (JSON *self) + PPCODE: + if (self->v_false && self->v_true) + { + EXTEND (SP, 2); + PUSHs (self->v_false); + PUSHs (self->v_true); + } + void ascii (JSON *self, int enable = 1) ALIAS: ascii = F_ASCII @@ -2270,6 +2355,8 @@ void DESTROY (JSON *self) CODE: + SvREFCNT_dec (self->v_false); + SvREFCNT_dec (self->v_true); SvREFCNT_dec (self->cb_sk_object); SvREFCNT_dec (self->cb_object); SvREFCNT_dec (self->incr_text); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/bin/json_xs new/JSON-XS-4.0/bin/json_xs --- old/JSON-XS-3.04/bin/json_xs 2017-07-07 04:31:43.000000000 +0200 +++ new/JSON-XS-4.0/bin/json_xs 2018-11-15 21:48:29.000000000 +0100 @@ -193,7 +193,7 @@ "string" => sub { $_ }, "json" => sub { encode_json $_ }, "json-utf-8" => sub { encode_json $_ }, - "json-pretty" => sub { JSON::XS->new->utf8->pretty->encode ($_) }, + "json-pretty" => sub { JSON::XS->new->utf8->pretty->canonical->encode ($_) }, "json-utf-16le" => sub { encode "utf-16le", JSON::XS->new->encode ($_) }, "json-utf-16be" => sub { encode "utf-16be", JSON::XS->new->encode ($_) }, "json-utf-32le" => sub { encode "utf-32le", JSON::XS->new->encode ($_) }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/t/02_error.t new/JSON-XS-4.0/t/02_error.t --- old/JSON-XS-3.04/t/02_error.t 2008-11-20 04:59:53.000000000 +0100 +++ new/JSON-XS-4.0/t/02_error.t 2018-11-15 21:22:22.000000000 +0100 @@ -1,4 +1,4 @@ -BEGIN { $| = 1; print "1..31\n"; } +BEGIN { $| = 1; print "1..35\n"; } use utf8; use JSON::XS; @@ -20,7 +20,7 @@ eval { JSON::XS->new->allow_nonref->decode ('"\ud800"') }; ok $@ =~ /missing low /; eval { JSON::XS->new->allow_nonref (1)->decode ('"\ud800\u1234"') }; ok $@ =~ /surrogate pair /; -eval { JSON::XS->new->decode ('null') }; ok $@ =~ /allow_nonref/; +eval { JSON::XS->new->allow_nonref (0)->decode ('null') }; ok $@ =~ /allow_nonref/; eval { JSON::XS->new->allow_nonref (1)->decode ('+0') }; ok $@ =~ /malformed/; eval { JSON::XS->new->allow_nonref->decode ('.2') }; ok $@ =~ /malformed/; eval { JSON::XS->new->allow_nonref (1)->decode ('bare') }; ok $@ =~ /malformed/; @@ -44,4 +44,8 @@ eval { decode_json ("\"\xa0") }; ok $@ =~ /malformed.*character/; eval { decode_json ("\"\xa0\"") }; ok $@ =~ /malformed.*character/; +eval { decode_json ("1\x01") }; ok $@ =~ /garbage after/; +eval { decode_json ("1\x00") }; ok $@ =~ /garbage after/; +eval { decode_json ("\"\"\x00") }; ok $@ =~ /garbage after/; +eval { decode_json ("[]\x00") }; ok $@ =~ /garbage after/; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/t/18_json_checker.t new/JSON-XS-4.0/t/18_json_checker.t --- old/JSON-XS-3.04/t/18_json_checker.t 2007-10-10 19:38:47.000000000 +0200 +++ new/JSON-XS-4.0/t/18_json_checker.t 2018-11-15 21:19:06.000000000 +0100 @@ -6,7 +6,7 @@ use strict; no warnings; use Test::More; -BEGIN { plan tests => 39 }; +BEGIN { plan tests => 38 }; use JSON::XS; @@ -31,8 +31,6 @@ } __DATA__ -"A JSON payload should be an object or array, not a string." -# fail1.json {"Extra value after close": true} "misplaced quoted value" # fail10.json {"Illegal expression": 1 + 2} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-XS-3.04/t/19_incr.t new/JSON-XS-4.0/t/19_incr.t --- old/JSON-XS-3.04/t/19_incr.t 2013-05-23 11:20:06.000000000 +0200 +++ new/JSON-XS-4.0/t/19_incr.t 2018-11-15 23:00:55.000000000 +0100 @@ -3,7 +3,7 @@ use strict; no warnings; use Test::More; -BEGIN { plan tests => 697 }; +BEGIN { plan tests => 745 }; use JSON::XS; @@ -21,16 +21,23 @@ $coder->incr_parse ($b); my $data = $coder->incr_parse; - ok ($data); - ok ($coder->encode ($data) eq $coder->encode ($coder->decode ($text)), "data"); + #ok (defined $data, "split<$a><$b>"); + ok (defined $data, "split"); + my $e1 = $coder->encode ($data); + my $e2 = $coder->encode ($coder->decode ($text)); + #ok ($e1 eq $e2, "data<$a><$b><$e1><$e2>"); + #ok ($coder->incr_text =~ /^\s*$/, "tailws<$a><$b>"); + ok ($e1 eq $e2, "data"); ok ($coder->incr_text =~ /^\s*$/, "tailws"); } } -splitter +JSON::XS->new , ' ["x\\"","\\u1000\\\\n\\nx",1,{"\\\\" :5 , "": "x"}]'; -splitter +JSON::XS->new , '[ "x\\"","\\u1000\\\\n\\nx" , 1,{"\\\\ " :5 , "": " x"} ] '; -splitter +JSON::XS->new->allow_nonref, '"test"'; -splitter +JSON::XS->new->allow_nonref, ' "5" '; +splitter +JSON::XS->new->allow_nonref (0), ' ["x\\"","\\u1000\\\\n\\nx",1,{"\\\\" :5 , "": "x"}]'; +splitter +JSON::XS->new->allow_nonref (0), '[ "x\\"","\\u1000\\\\n\\nx" , 1,{"\\\\ " :5 , "": " x"} ] '; +splitter +JSON::XS->new , '"test"'; +splitter +JSON::XS->new , ' "5" '; +splitter +JSON::XS->new , '-1e5'; +splitter +JSON::XS->new , ' 0.00E+00 '; { my $text = '[5],{"":1} , [ 1,2, 3], {"3":null}';