diff options
author | John Christopher Anderson <jchris@apache.org> | 2008-12-16 20:42:05 +0000 |
---|---|---|
committer | John Christopher Anderson <jchris@apache.org> | 2008-12-16 20:42:05 +0000 |
commit | e64377c89cb535d4d649f637d3b434356ff984b5 (patch) | |
tree | 323673b652c3eda53985ca8e9ed5d2c243249988 /src/couchdb/couch_httpd_external.erl | |
parent | 54ddcb1768b915e90d315e1f5ceba4f322b8e28b (diff) |
the external process handler
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@727136 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb/couch_httpd_external.erl')
-rw-r--r-- | src/couchdb/couch_httpd_external.erl | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/src/couchdb/couch_httpd_external.erl b/src/couchdb/couch_httpd_external.erl new file mode 100644 index 00000000..7ed3d51a --- /dev/null +++ b/src/couchdb/couch_httpd_external.erl @@ -0,0 +1,107 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(couch_httpd_external). + +-export([handle_external_req/2]). + +-import(couch_httpd,[send_error/4]). + +-include("couch_db.hrl"). + +-record(extern_resp_args, { + code = 200, + data = <<>>, + ctype = "application/json", + headers = [] +}). + +handle_external_req(#httpd{mochi_req=Req, + method=Verb, + path_parts=[_DbName, _External, UrlName | Path] + }=HttpReq, Db) -> + ReqBody = Req:recv_body(), + ParsedForm = case Req:get_primary_header_value("content-type") of + "application/x-www-form-urlencoded" ++ _ -> + mochiweb_util:parse_qs(ReqBody); + _ -> + [] + end, + Response = couch_external_manager:execute(binary_to_list(UrlName), + Db, Verb, Path, Req:parse_qs(), ReqBody, ParsedForm, + Req:parse_cookie()), + + case Response of + {unknown_external_server, Msg} -> + send_error(HttpReq, 404, <<"external_server_error">>, Msg); + _ -> + send_external_response(Req, Response) + end; +handle_external_req(#httpd{path_parts=[_, _]}=Req, _Db) -> + send_error(Req, 404, <<"external_server_error">>, <<"No server name specified.">>); +handle_external_req(Req, _) -> + send_error(Req, 404, <<"external_server_error">>, <<"Broken assumption">>). + +send_external_response(Req, Response) -> + #extern_resp_args{ + code = Code, + data = Data, + ctype = CType, + headers = Headers + } = parse_external_response(Response), + ?LOG_DEBUG("External Response ~p",[Response]), + Resp = Req:respond({Code, + default_or_content_type(CType, Headers), chunked}), + Resp:write_chunk(Data), + Resp:write_chunk(""), + {ok, Resp}. + +parse_external_response({Response}) -> + lists:foldl(fun({Key,Value}, Args) -> + case {Key, Value} of + {"", _} -> + Args; + {<<"code">>, Value} -> + Args#extern_resp_args{code=Value}; + {<<"json">>, Value} -> + Args#extern_resp_args{ + data=?JSON_ENCODE(Value), + ctype="application/json"}; + {<<"body">>, Value} -> + Args#extern_resp_args{data=Value, ctype="text/html"}; + {<<"headers">>, {Headers}} -> + NewHeaders = lists:map(fun({Header, HVal}) -> + {binary_to_list(Header), binary_to_list(HVal)} + end, Headers), + Args#extern_resp_args{headers=NewHeaders}; + _ -> % unknown key + Msg = lists:flatten(io_lib:format("Invalid data from external server: ~s = ~p", [Key, Value])), + throw({external_response_error, Msg}) + end + end, #extern_resp_args{}, Response). + +default_or_content_type(DefaultContentType, Headers) -> + {ContentType, OtherHeaders} = lists:partition( + fun({HeaderName, _}) -> + HeaderName == "Content-Type" + end, Headers), + + % XXX: What happens if we were passed multiple content types? We add another? + case ContentType of + [{"Content-Type", SetContentType}] -> + TrueContentType = SetContentType; + _Else -> + TrueContentType = DefaultContentType + end, + + HeadersWithContentType = lists:append(OtherHeaders, [{"Content-Type", TrueContentType}]), + HeadersWithContentType. |