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