Skip to content

Commit

Permalink
accept Mojo::JSON::_Bool
Browse files Browse the repository at this point in the history
Mojo does not store their booleans as JSON::PP::Boolean
as everybody else does.
See GH #37
  • Loading branch information
Reini Urban committed Oct 23, 2015
1 parent 0a07be8 commit 23ff878
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 23 deletions.
1 change: 1 addition & 0 deletions MANIFEST
Expand Up @@ -39,6 +39,7 @@ t/25_boolean.t
t/52_object.t
t/53_readonly.t
t/96_interop.t
t/96_mojo.t
t/97_unshare_hek.t
t/98_56only.t
t/99_binary.t
Expand Down
13 changes: 9 additions & 4 deletions README
Expand Up @@ -1521,22 +1521,25 @@ ENCODING/CODESET FLAG NOTES
For updated graphs see
<https://github.com/Sereal/Sereal/wiki/Sereal-Comparison-Graphs>

INTEROP with JSON and JSON::XS
INTEROP with JSON and JSON::XS and other JSON modules
JSON-XS-3.01 broke interoperability with JSON-2.90 with booleans. See
JSON.

Cpanel::JSON::XS needs to know the JSON and JSON::XS versions to be able
work with those objects, especially when encoding a booleans like
"{"is_true":true}". So you need to load these modules before.

true/false overloading is supported.
true/false overloading and boolean representions are supported.

JSON::XS and JSON::PP representations are accepted and older JSON::XS
accepts Cpanel::JSON::XS booleans. All JSON modules JSON, JSON, PP,
JSON::XS , Cpanel::JSON::XS produce JSON::PP::Boolean objects, just Mojo
JSON::XS, Cpanel::JSON::XS produce JSON::PP::Boolean objects, just Mojo
and JSON::YAJL not. Mojo produces Mojo::JSON::_Bool and
JSON::YAJL::Parser just an unblessed IV.

Cpanel::JSON::XS accepts JSON::PP::Boolean and Mojo::JSON::_Bool objects
as booleans.

I cannot think of any reason to still use JSON::XS anymore.

SECURITY CONSIDERATIONS
Expand All @@ -1553,7 +1556,8 @@ SECURITY CONSIDERATIONS
(methods, functions) or external data would be considered the most
dangerous.

Overview of serializers regarding deserializing objects by default:
Security relevant overview of serializers regarding deserializing
objects by default:

Objects Coderefs External Data

Expand All @@ -1564,6 +1568,7 @@ SECURITY CONSIDERATIONS
B::C YES YES YES
B::Bytecode YES YES YES
BSON YES YES NO
JSON::SL YES NO YES
JSON NO (def) NO NO
Data::MessagePack NO NO NO
XML NO NO YES
Expand Down
12 changes: 8 additions & 4 deletions XS.pm
Expand Up @@ -1666,21 +1666,23 @@ comparison table for that case.
For updated graphs see L<https://github.com/Sereal/Sereal/wiki/Sereal-Comparison-Graphs>
=head1 INTEROP with JSON and JSON::XS
=head1 INTEROP with JSON and JSON::XS and other JSON modules
JSON-XS-3.01 broke interoperability with JSON-2.90 with booleans. See L<JSON>.
Cpanel::JSON::XS needs to know the JSON and JSON::XS versions to be able work
with those objects, especially when encoding a booleans like C<{"is_true":true}>.
So you need to load these modules before.
true/false overloading is supported.
true/false overloading and boolean representions are supported.
JSON::XS and JSON::PP representations are accepted and older JSON::XS accepts
Cpanel::JSON::XS booleans. All JSON modules JSON, JSON, PP, JSON::XS , Cpanel::JSON::XS
Cpanel::JSON::XS booleans. All JSON modules JSON, JSON, PP, JSON::XS, Cpanel::JSON::XS
produce JSON::PP::Boolean objects, just Mojo and JSON::YAJL not.
Mojo produces Mojo::JSON::_Bool and JSON::YAJL::Parser just an unblessed IV.
Cpanel::JSON::XS accepts JSON::PP::Boolean and Mojo::JSON::_Bool objects as booleans.
I cannot think of any reason to still use JSON::XS anymore.
=head1 SECURITY CONSIDERATIONS
Expand All @@ -1699,7 +1701,8 @@ Code Execution" for a deserializer which expands
objects. Deserializing even coderefs (methods, functions) or external
data would be considered the most dangerous.
Overview of serializers regarding deserializing objects by default:
Security relevant overview of serializers regarding deserializing
objects by default:
Objects Coderefs External Data
Expand All @@ -1710,6 +1713,7 @@ Overview of serializers regarding deserializing objects by default:
B::C YES YES YES
B::Bytecode YES YES YES
BSON YES YES NO
JSON::SL YES NO YES
JSON NO (def) NO NO
Data::MessagePack NO NO NO
XML NO NO YES
Expand Down
13 changes: 10 additions & 3 deletions XS.xs
Expand Up @@ -145,6 +145,7 @@
typedef struct {
HV *json_stash; /* Cpanel::JSON::XS:: */
HV *json_boolean_stash; /* JSON::PP::Boolean:: */
HV *mojo_boolean_stash; /* Mojo::JSON::_Bool:: if empty will be (HV*)1 */
SV *json_true, *json_false;
SV *sv_json;
} my_cxt_t;
Expand Down Expand Up @@ -198,6 +199,9 @@ init_MY_CXT(pTHX_ my_cxt_t * cxt)
{
cxt->json_stash = gv_stashpvn ("Cpanel::JSON::XS", sizeof("Cpanel::JSON::XS")-1, 1);
cxt->json_boolean_stash = gv_stashpvn ("JSON::PP::Boolean", sizeof("JSON::PP::Boolean")-1, 1);
cxt->mojo_boolean_stash = gv_stashpvn ("Mojo::JSON::_Bool", sizeof("Mojo::JSON::_Bool")-1, 0);
if ( !cxt->mojo_boolean_stash )
cxt->mojo_boolean_stash = (HV*)1; /* invalid ptr to compare against, better than a NULL stash */

cxt->json_true = get_bool (aTHX_ "Cpanel::JSON::XS::true");
cxt->json_false = get_bool (aTHX_ "Cpanel::JSON::XS::false");
Expand Down Expand Up @@ -837,7 +841,9 @@ encode_hv (pTHX_ enc_t *enc, HV *hv)
encode_ch (aTHX_ enc, '}');
}

/* encode objects, arrays and special \0=false and \1=true values. */
/* encode objects, arrays and special \0=false and \1=true values
and other representations of booleans: JSON::PP::Boolean, Mojo::JSON::_Bool
*/
static void
encode_rv (pTHX_ enc_t *enc, SV *rv)
{
Expand All @@ -851,10 +857,11 @@ encode_rv (pTHX_ enc_t *enc, SV *rv)
if (expect_false (SvOBJECT (sv)))
{
dMY_CXT;
HV *bstash = MY_CXT.json_boolean_stash; /* JSON-XS-3.x interop (Types::Serialiser/JSON::PP) */
HV *bstash = MY_CXT.json_boolean_stash; /* JSON-XS-3.x interop (Types::Serialiser/JSON::PP::Boolean) */
HV *mstash = MY_CXT.mojo_boolean_stash; /* Mojo::JSON::_Bool interop */
HV *stash = SvSTASH (sv);

if (stash == bstash)
if (stash == bstash || stash == mstash)
{
if (SvIV (sv))
encode_str (aTHX_ enc, "true", 4, 0);
Expand Down
29 changes: 17 additions & 12 deletions t/96_mojo.t
Expand Up @@ -5,30 +5,35 @@ BEGIN {
plan skip_all => "Mojo::JSON required for testing interop";
exit 0;
} else {
plan tests => 6;
plan tests => 9;
}
}

use Mojo::JSON ();
use Cpanel::JSON::XS ();

my $booltrue = q({"is_true":true});
my $booltrue = q({"is_true":true});
my $boolfalse = q({"is_false":false});
#my $boolpl = { is_false => \0, is_true => \1 };
my $yesno = [ !1, !0 ];
my $js = Mojo::JSON::decode_json( $booltrue );
is( $js->{is_true}, 1 );
is( $js->{is_true}, 1, 'true == 1' );
ok( $js->{is_true}, 'ok true');

my $cjson = Cpanel::JSON::XS->new;
is($cjson->encode( $js ), $booltrue)
is($cjson->encode( $js ), $booltrue, 'can encode Mojo true')
or diag "\$Mojolicious::VERSION=$Mojolicious::VERSION,".
" \$Cpanel::JSON::XS::VERSION=$Cpanel::JSON::XS::VERSION";

$js = Mojo::JSON::decode_json( $boolfalse );
is( $cjson->encode( $js ), $boolfalse );
is( $js->{is_false}, 0 );
is( $cjson->encode( $js ), $boolfalse, 'can encode Mojo false' );
is( $js->{is_false}, 0 ,'false == 0');
ok( !$js->{is_false}, 'ok !false');

# issue18: support Types::Serialiser without allow_blessed (if JSON-XS-3.x is loaded)
$js = $cjson->decode( $booltrue );
is( $cjson->encode( $js ), $booltrue ) or diag(ref $js->{is_true} );
$js = $cjson->decode( $boolfalse );
is( $cjson->encode( $js ), $boolfalse ) or diag(ref $js->{is_false} );
my $mj = Mojo::JSON::encode_json( $yesno );
$js = $cjson->decode( $mj );

is( $js->[0], '', 'can decode Mojo false' );
is( $js->[1], 1, 'can decode Mojo true' );
# Note this is fragile. it depends on the internal representation of booleans.
is_deeply( $js, ['', 1], 'can decode Mojo booleans (fragile)' )
or diag( $mj, $js );

0 comments on commit 23ff878

Please sign in to comment.