--- Revision None +++ Revision 663932343733 @@ -0,0 +1,180 @@ +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