--- Revision None +++ Revision 333063613038 @@ -0,0 +1,162 @@ +diff --git a/src/couchdb/couch_httpd_rewrite.erl b/src/couchdb/couch_httpd_rewrite.erl +index 6324631..ce44fdd 100644 +--- a/src/couchdb/couch_httpd_rewrite.erl ++++ b/src/couchdb/couch_httpd_rewrite.erl +@@ -126,8 +126,7 @@ handle_rewrite_req(#httpd{ + % we are in a design handler + DesignId = <<"_design/", DesignName/binary>>, + Prefix = <<"/", DbName/binary, "/", DesignId/binary>>, +- QueryList = couch_httpd:qs(Req), +- QueryList1 = [{to_binding(K), V} || {K, V} <- QueryList], ++ QueryList = lists:map(fun decode_query_value/1, couch_httpd:qs(Req)), + + #doc{body={Props}} = DDoc, + +@@ -145,7 +144,7 @@ handle_rewrite_req(#httpd{ + + %% get raw path by matching url to a rule. + RawPath = case try_bind_path(DispatchList, couch_util:to_binary(Method), PathParts, +- QueryList1) of ++ QueryList) of + no_dispatch_path -> + throw(not_found); + {NewPathParts, Bindings} -> +@@ -153,13 +152,15 @@ handle_rewrite_req(#httpd{ + + % build new path, reencode query args, eventually convert + % them to json +- Path = lists:append( +- string:join(Parts, [?SEPARATOR]), +- case Bindings of +- [] -> []; +- _ -> [$?, encode_query(Bindings)] +- end), +- ++ Bindings1 = maybe_encode_bindings(Bindings), ++ ?LOG_INFO("bindings1 ~p~n", [Bindings1]), ++ Path = binary_to_list( ++ iolist_to_binary([ ++ string:join(Parts, [?SEPARATOR]), ++ [["?", mochiweb_util:urlencode(Bindings1)] ++ || Bindings1 =/= [] ] ++ ])), ++ + % if path is relative detect it and rewrite path + case mochiweb_util:safe_relative_path(Path) of + undefined -> +@@ -253,44 +254,29 @@ make_query_list([{Key, Value}|Rest], Bindings, Acc) when is_list(Value) -> + make_query_list([{Key, Value}|Rest], Bindings, Acc) -> + make_query_list(Rest, Bindings, [{to_binding(Key), Value}|Acc]). + +-replace_var(Key, Value, Bindings) -> +- case Value of +- <<":", Var/binary>> -> +- get_var(Var, Bindings, Value); +- <<"*">> -> +- get_var(Value, Bindings, Value); +- _ when is_list(Value) -> +- Value1 = lists:foldr(fun(V, Acc) -> +- V1 = case V of +- <<":", VName/binary>> -> +- case get_var(VName, Bindings, V) of +- V2 when is_list(V2) -> +- iolist_to_binary(V2); +- V2 -> V2 +- end; +- <<"*">> -> +- get_var(V, Bindings, V); +- _ -> +- V +- end, +- [V1|Acc] +- end, [], Value), +- to_json(Value1); +- _ when is_binary(Value) -> +- Value; +- _ -> +- case Key of +- <<"key">> -> to_json(Value); +- <<"startkey">> -> to_json(Value); +- <<"start_key">> -> to_json(Value); +- <<"endkey">> -> to_json(Value); +- <<"end_key">> -> to_json(Value); +- _ -> +- lists:flatten(?JSON_ENCODE(Value)) +- end ++replace_var(Key, <<":", Var/binary>> = Value, Bindings) -> ++ get_var(Var, Bindings, Value); ++replace_var(_Key, Value, Bindings) when is_binary(Value) -> ++ Value; ++replace_var(_Key, Value, Bindings) when is_list(Value) -> ++ lists:foldl(fun ++ (<<":", Var/binary>>=Value1, Acc) -> ++ [get_var(Var, Bindings, Value1)|Acc]; ++ (Value1, Acc) -> ++ [Value1|Acc] ++ end, [], Value); ++replace_var(Key, Value, _Bindings) -> ++ Value. ++ ++maybe_json(Key, Value) -> ++ case lists:member(Key, [<<"key">>, <<"startkey">>, <<"start_key">>, ++ <<"endkey">>, <<"end_key">>]) of ++ true -> ++ ?JSON_ENCODE(Value); ++ false -> ++ Value + end. + +- + get_var(VarName, Props, Default) -> + VarName1 = to_binding(VarName), + couch_util:get_value(VarName1, Props, Default). +@@ -309,7 +295,7 @@ make_new_path([?MATCH_ALL|_Rest], _Bindings, Remaining, Acc) -> + make_new_path([{bind, P}|Rest], Bindings, Remaining, Acc) -> + P2 = case couch_util:get_value({bind, P}, Bindings) of + undefined -> << "undefined">>; +- P1 -> P1 ++ P1 -> to_json(P1) + end, + make_new_path(Rest, Bindings, Remaining, [P2|Acc]); + make_new_path([P|Rest], Bindings, Remaining, Acc) -> +@@ -437,21 +423,25 @@ path_to_list([P|R], Acc, DotDotCount) -> + end, + path_to_list(R, [P1|Acc], DotDotCount). + +-encode_query(Props) -> +- Props1 = lists:foldl(fun ({{bind, K}, V}, Acc) -> +- case K of +- <<"*">> -> Acc; +- _ -> +- V1 = case is_list(V) orelse is_binary(V) of +- true -> V; +- false -> +- % probably it's a number +- quote_plus(V) +- end, +- [{K, V1} | Acc] +- end +- end, [], Props), +- lists:flatten(mochiweb_util:urlencode(Props1)). ++maybe_encode_bindings([]) -> ++ []; ++maybe_encode_bindings(Props) -> ++ lists:foldl(fun ++ ({{bind, <<"*">>}, V}, Acc) -> ++ Acc; ++ ({{bind, K}, V}, Acc) -> ++ V1 = iolist_to_binary(maybe_json(K, V)), ++ [{K, V1}|Acc] ++ end, [], Props). ++ ++decode_query_value({K,V}) -> ++ case lists:member(K, ["key", "startkey", "start_key", ++ "endkey", "end_key"]) of ++ true -> ++ {to_binding(K), ?JSON_DECODE(V)}; ++ false -> ++ {to_binding(K), ?l2b(V)} ++ end. + + to_binding({bind, V}) -> + {bind, V};