From 52804ef907f5c0c4cf9ea45c42714502ba46093f Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Mon, 13 Feb 2012 15:41:14 +0000 Subject: [PATCH] Only validate numbers on JSON decoding Let the encoder validate only the numbers and encode them as the term {json, RawNumberJsonBinary}. COUCHDB-1407 --- src/couchdb/couch_db.hrl | 1 + src/couchdb/couch_httpd.erl | 2 +- src/couchdb/couch_httpd_db.erl | 2 +- src/couchdb/couch_query_servers.erl | 2 +- src/ejson/ejson.erl | 60 ++++++++++++++++++++++------------ 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl index 65eb7f0..6fae38c 100644 --- a/src/couchdb/couch_db.hrl +++ b/src/couchdb/couch_db.hrl @@ -23,6 +23,7 @@ -define(JSON_ENCODE(V), ejson:encode(V)). -define(JSON_DECODE(V), ejson:decode(V)). +-define(JSON_DECODE_RAW_NUMBERS(V), ejson:decode(V, [raw_numbers])). -define(b2l(V), binary_to_list(V)). -define(l2b(V), list_to_binary(V)). diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl index 8b05076..a9dd65e 100644 --- a/src/couchdb/couch_httpd.erl +++ b/src/couchdb/couch_httpd.erl @@ -556,7 +556,7 @@ body(#httpd{req_body=ReqBody}) -> ReqBody. json_body(Httpd) -> - ?JSON_DECODE(body(Httpd)). + ?JSON_DECODE_RAW_NUMBERS(body(Httpd)). json_body_obj(Httpd) -> case json_body(Httpd) of diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index f669643..f732401 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -509,7 +509,7 @@ db_doc_req(#httpd{method='POST'}=Req, Db, DocId) -> Rev = couch_doc:parse_rev(couch_util:get_value("_rev", Form)), {ok, [{ok, Doc}]} = couch_db:open_doc_revs(Db, DocId, [Rev], []); Json -> - Doc = couch_doc_from_req(Req, DocId, ?JSON_DECODE(Json)) + Doc = couch_doc_from_req(Req, DocId, ?JSON_DECODE_RAW_NUMBERS(Json)) end, UpdatedAtts = [ #att{name=validate_attachment_name(Name), diff --git a/src/couchdb/couch_query_servers.erl b/src/couchdb/couch_query_servers.erl index e29f23b..e757edf 100644 --- a/src/couchdb/couch_query_servers.erl +++ b/src/couchdb/couch_query_servers.erl @@ -526,7 +526,7 @@ proc_prompt_raw(#proc{prompt_fun = {Mod, Func}} = Proc, Args) -> apply(Mod, Func, [Proc#proc.pid, Args]). raw_to_ejson({json, Json}) -> - ?JSON_DECODE(Json); + ?JSON_DECODE_RAW_NUMBERS(Json); raw_to_ejson(EJson) -> EJson. diff --git a/src/ejson/ejson.erl b/src/ejson/ejson.erl index 07a71c2..85e155b 100644 --- a/src/ejson/ejson.erl +++ b/src/ejson/ejson.erl @@ -11,7 +11,7 @@ % the License. -module(ejson). --export([encode/1, decode/1]). +-export([encode/1, decode/1, decode/2]). -on_load(init/0). init() -> @@ -34,8 +34,11 @@ init() -> decode(IoList) -> + decode(IoList, []). + +decode(IoList, Options) -> try - nif_decode(IoList) + nif_decode(IoList, Options) catch exit:ejson_nif_not_loaded -> erl_decode(IoList) end. @@ -48,10 +51,11 @@ encode(EJson) -> end. -nif_decode(IoList) -> +nif_decode(IoList, Options) -> case reverse_tokens(IoList) of {ok, ReverseTokens} -> - [[EJson]] = make_ejson(ReverseTokens, [[]]), + RawNumbers = lists:member(raw_numbers, Options), + [[EJson]] = make_ejson(ReverseTokens, [[]], RawNumbers), EJson; Error -> throw({invalid_json, {Error, IoList}}) @@ -85,6 +89,8 @@ mochi_encode_handler(Bad) -> % everything in the list is the final output except for tuples with % {0, Strings} and {1, Floats}, which are to be converted to strings % inside the NIF. +encode_rev({json, RawJson}) -> + RawJson; encode_rev(true) -> <<"true">>; encode_rev(false) -> @@ -132,31 +138,43 @@ as_binary(L) when is_list(L) -> list_to_binary(L). -make_ejson([], Stack) -> +make_ejson([], Stack, _RawNumbers) -> Stack; -make_ejson([0 | RevEvs], [ArrayValues, PrevValues | RestStack]) -> +make_ejson([0 | RevEvs], [ArrayValues, PrevValues | RestStack], RawNumbers) -> % 0 ArrayStart - make_ejson(RevEvs, [[ArrayValues | PrevValues] | RestStack]); -make_ejson([1 | RevEvs], Stack) -> + make_ejson(RevEvs, [[ArrayValues | PrevValues] | RestStack], RawNumbers); +make_ejson([1 | RevEvs], Stack, RawNumbers) -> % 1 ArrayEnd - make_ejson(RevEvs, [[] | Stack]); -make_ejson([2 | RevEvs], [ObjValues, PrevValues | RestStack]) -> + make_ejson(RevEvs, [[] | Stack], RawNumbers); +make_ejson([2 | RevEvs], [ObjValues, PrevValues | RestStack], RawNumbers) -> % 2 ObjectStart - make_ejson(RevEvs, [[{ObjValues} | PrevValues] | RestStack]); -make_ejson([3 | RevEvs], Stack) -> + make_ejson(RevEvs, [[{ObjValues} | PrevValues] | RestStack], RawNumbers); +make_ejson([3 | RevEvs], Stack, RawNumbers) -> % 3 ObjectEnd - make_ejson(RevEvs, [[] | Stack]); -make_ejson([{0, Value} | RevEvs], [Vals | RestStack] = _Stack) -> + make_ejson(RevEvs, [[] | Stack], RawNumbers); +make_ejson([{0, Value} | RevEvs], [Vals | RestStack] = _Stack, RawNumbers) -> % {0, IntegerString} - make_ejson(RevEvs, [[list_to_integer(binary_to_list(Value)) | Vals] | RestStack]); -make_ejson([{1, Value} | RevEvs], [Vals | RestStack] = _Stack) -> + EncValue = case RawNumbers of + true -> + {json, Value}; + false -> + list_to_integer(binary_to_list(Value)) + end, + make_ejson(RevEvs, [[EncValue | Vals] | RestStack], RawNumbers); +make_ejson([{1, Value} | RevEvs], [Vals | RestStack] = _Stack, RawNumbers) -> % {1, FloatString} - make_ejson(RevEvs, [[list_to_float(binary_to_list(Value)) | Vals] | RestStack]); -make_ejson([{3, String} | RevEvs], [[PrevValue|RestObject] | RestStack] = _Stack) -> + EncValue = case RawNumbers of + true -> + {json, Value}; + false -> + list_to_float(binary_to_list(Value)) + end, + make_ejson(RevEvs, [[EncValue | Vals] | RestStack], RawNumbers); +make_ejson([{3, String} | RevEvs], [[PrevValue|RestObject] | RestStack] = _Stack, RawNumbers) -> % {3 , ObjectKey} - make_ejson(RevEvs, [[{String, PrevValue}|RestObject] | RestStack]); -make_ejson([Value | RevEvs], [Vals | RestStack] = _Stack) -> - make_ejson(RevEvs, [[Value | Vals] | RestStack]). + make_ejson(RevEvs, [[{String, PrevValue}|RestObject] | RestStack], RawNumbers); +make_ejson([Value | RevEvs], [Vals | RestStack] = _Stack, RawNumbers) -> + make_ejson(RevEvs, [[Value | Vals] | RestStack], RawNumbers). reverse_tokens(_) -> -- 1.7.4.4