Generated on 2009-08-09 21:22:56 with etap 0.3.4.
| Name | Total lines | Lines of code | Total coverage | Code coverage | ||||
| couch_httpd_external | ?? | ?? | ?? |
|
....1 % Licensed under the Apache License, Version 2.0 (the "License"); you may not ....2 % use this file except in compliance with the License. You may obtain a copy of ....3 % the License at ....4 % ....5 % http://www.apache.org/licenses/LICENSE-2.0 ....6 % ....7 % Unless required by applicable law or agreed to in writing, software ....8 % distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ....9 % WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ...10 % License for the specific language governing permissions and limitations under ...11 % the License. ...12 ...13 -module(couch_httpd_external). ...14 ...15 -export([handle_external_req/2, handle_external_req/3]). ...16 -export([send_external_response/2, json_req_obj/2]). ...17 -export([default_or_content_type/2, parse_external_response/1]). ...18 ...19 -import(couch_httpd,[send_error/4]). ...20 ...21 -include("couch_db.hrl"). ...22 ...23 % handle_external_req/2 ...24 % for the old type of config usage: ...25 % _external = {couch_httpd_external, handle_external_req} ...26 % with urls like ...27 % /db/_external/action/design/name ...28 handle_external_req(#httpd{ ...29 path_parts=[_DbName, _External, UrlName | _Path] ...30 }=HttpReq, Db) -> ...31 process_external_req(HttpReq, Db, UrlName); ...32 handle_external_req(#httpd{path_parts=[_, _]}=Req, _Db) -> ...33 send_error(Req, 404, <<"external_server_error">>, <<"No server name specified.">>); ...34 handle_external_req(Req, _) -> ...35 send_error(Req, 404, <<"external_server_error">>, <<"Broken assumption">>). ...36 ...37 % handle_external_req/3 ...38 % for this type of config usage: ...39 % _action = {couch_httpd_external, handle_external_req, <<"action">>} ...40 % with urls like ...41 % /db/_action/design/name ...42 handle_external_req(HttpReq, Db, Name) -> ...43 process_external_req(HttpReq, Db, Name). ...44 ...45 process_external_req(HttpReq, Db, Name) -> ...46 ...47 Response = couch_external_manager:execute(binary_to_list(Name), ...48 json_req_obj(HttpReq, Db)), ...49 ...50 case Response of ...51 {unknown_external_server, Msg} -> ...52 send_error(HttpReq, 404, <<"external_server_error">>, Msg); ...53 _ -> ...54 send_external_response(HttpReq, Response) ...55 end. ...56 ...57 json_req_obj(#httpd{mochi_req=Req, ...58 method=Verb, ...59 path_parts=Path, ...60 req_body=ReqBody, ...61 user_ctx=#user_ctx{name=UserName, roles=UserRoles} ...62 }, Db) -> ...63 Body = case ReqBody of ...64 undefined -> Req:recv_body(); ...65 Else -> Else ...66 end, ...67 ParsedForm = case Req:get_primary_header_value("content-type") of ...68 "application/x-www-form-urlencoded" ++ _ -> ...69 mochiweb_util:parse_qs(Body); ...70 _ -> ...71 [] ...72 end, ...73 UserCtx = {[{<<"name">>, UserName}, {<<"roles">>, UserRoles}]}, ...74 Headers = Req:get(headers), ...75 Hlist = mochiweb_headers:to_list(Headers), ...76 {ok, Info} = couch_db:get_db_info(Db), ...77 % add headers... ...78 {[{<<"info">>, {Info}}, ...79 {<<"verb">>, Verb}, ...80 {<<"path">>, Path}, ...81 {<<"query">>, to_json_terms(Req:parse_qs())}, ...82 {<<"headers">>, to_json_terms(Hlist)}, ...83 {<<"body">>, Body}, ...84 {<<"form">>, to_json_terms(ParsedForm)}, ...85 {<<"cookie">>, to_json_terms(Req:parse_cookie())}, ...86 {<<"userCtx">>, UserCtx}]}. ...87 ...88 to_json_terms(Data) -> ...89 to_json_terms(Data, []). ...90 to_json_terms([], Acc) -> ...91 {lists:reverse(Acc)}; ...92 to_json_terms([{Key, Value} | Rest], Acc) when is_atom(Key) -> ...93 to_json_terms(Rest, [{list_to_binary(atom_to_list(Key)), list_to_binary(Value)} | Acc]); ...94 to_json_terms([{Key, Value} | Rest], Acc) -> ...95 to_json_terms(Rest, [{list_to_binary(Key), list_to_binary(Value)} | Acc]). ...96 ...97 ...98 send_external_response(#httpd{mochi_req=MochiReq}, Response) -> ...99 #extern_resp_args{ ..100 code = Code, ..101 data = Data, ..102 ctype = CType, ..103 headers = Headers ..104 } = parse_external_response(Response), ..105 Resp = MochiReq:respond({Code, ..106 default_or_content_type(CType, Headers ++ couch_httpd:server_header()), Data}), ..107 {ok, Resp}. ..108 ..109 parse_external_response({Response}) -> ..110 lists:foldl(fun({Key,Value}, Args) -> ..111 case {Key, Value} of ..112 {"", _} -> ..113 Args; ..114 {<<"code">>, Value} -> ..115 Args#extern_resp_args{code=Value}; ..116 {<<"stop">>, true} -> ..117 Args#extern_resp_args{stop=true}; ..118 {<<"json">>, Value} -> ..119 Args#extern_resp_args{ ..120 data=?JSON_ENCODE(Value), ..121 ctype="application/json"}; ..122 {<<"body">>, Value} -> ..123 Args#extern_resp_args{data=Value, ctype="text/html; charset=utf-8"}; ..124 {<<"base64">>, Value} -> ..125 Args#extern_resp_args{ ..126 data=couch_util:decodeBase64(Value), ..127 ctype="application/binary" ..128 }; ..129 {<<"headers">>, {Headers}} -> ..130 NewHeaders = lists:map(fun({Header, HVal}) -> ..131 {binary_to_list(Header), binary_to_list(HVal)} ..132 end, Headers), ..133 Args#extern_resp_args{headers=NewHeaders}; ..134 _ -> % unknown key ..135 Msg = lists:flatten(io_lib:format("Invalid data from external server: ~p", [{Key, Value}])), ..136 throw({external_response_error, Msg}) ..137 end ..138 end, #extern_resp_args{}, Response). ..139 ..140 default_or_content_type(DefaultContentType, Headers) -> ..141 {ContentType, OtherHeaders} = lists:partition( ..142 fun({HeaderName, _}) -> ..143 HeaderName == "Content-Type" ..144 end, Headers), ..145 ..146 % XXX: What happens if we were passed multiple content types? We add another? ..147 case ContentType of ..148 [{"Content-Type", SetContentType}] -> ..149 TrueContentType = SetContentType; ..150 _Else -> ..151 TrueContentType = DefaultContentType ..152 end, ..153 ..154 HeadersWithContentType = lists:append(OtherHeaders, [{"Content-Type", TrueContentType}]), ..155 HeadersWithContentType.
Generated using etap 0.3.4.