You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2019/11/25 21:39:36 UTC
[couchdb] 01/01: WIP proxy the response from the other node
This is an automated email from the ASF dual-hosted git repository.
rnewson pushed a commit to branch 1523-bye-bye-5986-rnewson-4
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 936984f0a479375081b0322719a08cf436f43bed
Author: Robert Newson <rn...@apache.org>
AuthorDate: Mon Nov 25 14:03:15 2019 +0000
WIP proxy the response from the other node
---
src/chttpd/src/chttpd_node.erl | 19 ++++++++++++++++--
src/couch/src/couch_httpd.erl | 44 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/src/chttpd/src/chttpd_node.erl b/src/chttpd/src/chttpd_node.erl
index 9786be5..ea51823 100644
--- a/src/chttpd/src/chttpd_node.erl
+++ b/src/chttpd/src/chttpd_node.erl
@@ -130,17 +130,32 @@ handle_node_req(#httpd{path_parts=[_, Node | PathParts],
{_, Query, Fragment} = mochiweb_util:urlsplit_path(RawUri),
NewPath0 = "/" ++ lists:join("/", [?b2l(P) || P <- PathParts]),
NewRawPath = mochiweb_util:urlunsplit_path({NewPath0, Query, Fragment}),
- MochiReq = mochiweb_request:new(self(),
+ MaxSize = config:get_integer("httpd", "max_http_request_size", 4294967296),
+ NewOpts = [{body, MochiReq0:recv_body(MaxSize)} | MochiReq0:get(opts)],
+ Ref = erlang:make_ref(),
+ MochiReq = mochiweb_request:new({remote, self(), Ref},
+ NewOpts,
MochiReq0:get(method),
NewRawPath,
MochiReq0:get(version),
MochiReq0:get(headers)),
- call_node(Node, couch_httpd, handle_request, [MochiReq]);
+ call_node(Node, couch_httpd, handle_request, [MochiReq]),
+ recv_loop(Ref, MochiReq0:get(socket));
handle_node_req(#httpd{path_parts=[_]}=Req) ->
chttpd:send_error(Req, {bad_request, <<"Incomplete path to _node request">>});
handle_node_req(Req) ->
chttpd:send_error(Req, not_found).
+recv_loop(Ref, Socket) ->
+ receive
+ {Ref, closed} ->
+ ok;
+ {Ref, Data} ->
+ gen_tcp:send(Socket, Data),
+ recv_loop(Ref, Socket)
+ after 5000 ->
+ ok
+ end.
call_node(Node0, Mod, Fun, Args) when is_binary(Node0) ->
Node1 = try
diff --git a/src/couch/src/couch_httpd.erl b/src/couch/src/couch_httpd.erl
index ba35d6f..43c887e 100644
--- a/src/couch/src/couch_httpd.erl
+++ b/src/couch/src/couch_httpd.erl
@@ -221,8 +221,52 @@ make_fun_spec_strs(SpecStr) ->
re:split(SpecStr, "(?<=})\\s*,\\s*(?={)", [{return, list}]).
handle_request(MochiReq) ->
+ handle_request(MochiReq:get(socket), MochiReq).
+
+handle_request({remote, RemotePid, RemoteRef}, MochiReq0) ->
+ Body = proplists:get_value(body, MochiReq0:get(opts)),
+ erlang:put(mochiweb_request_body, Body),
+ LoopbackAddress = loopback_address(),
+ ListenOpts = [binary, {packet, 0}, {active, false}, {ifaddr, LoopbackAddress}],
+ {ok, ListenSocket} = gen_tcp:listen(0, ListenOpts),
+ spawn_link(fun() ->
+ {ok, Socket} = gen_tcp:accept(ListenSocket),
+ recv_loop(RemotePid, RemoteRef, Socket) end),
+ {ok, ListenPort} = inet:port(ListenSocket),
+ {ok, LocalSocket} = gen_tcp:connect(LoopbackAddress, ListenPort, []),
+ MochiReq = set_socket(MochiReq0, LocalSocket),
+ try
+ apply(?MODULE, handle_request, [MochiReq | get_httpd_handlers()])
+ after
+ gen_tcp:close(LocalSocket),
+ gen_tcp:close(ListenSocket)
+ end;
+handle_request(_Socket, MochiReq) ->
apply(?MODULE, handle_request, [MochiReq | get_httpd_handlers()]).
+recv_loop(RemotePid, RemoteRef, Socket) ->
+ case gen_tcp:recv(Socket, 0) of
+ {ok, Data} ->
+ RemotePid ! {RemoteRef, Data},
+ recv_loop(RemotePid, RemoteRef, Socket);
+ {error, closed} ->
+ RemotePid ! {RemoteRef, closed}
+ end.
+
+set_socket(MochiReq, NewSocket) ->
+ mochiweb_request:new(
+ NewSocket,
+ MochiReq:get(method),
+ MochiReq:get(raw_path),
+ MochiReq:get(version),
+ MochiReq:get(headers)).
+
+loopback_address() ->
+ {ok, Interfaces} = inet:getifaddrs(),
+ hd([Addr || {_, Opts} <- Interfaces,
+ {addr, Addr} <- Opts,
+ {flags, Flags} <- Opts, lists:member(loopback, Flags)]).
+
handle_request(MochiReq, DefaultFun, UrlHandlers, DbUrlHandlers,
DesignUrlHandlers) ->
%% reset rewrite count for new request