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