summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@gmail.com>2021-04-13 23:27:10 -0400
committerNick Vatamaniuc <nickva@users.noreply.github.com>2021-04-16 17:44:43 -0400
commite05a6bfc03e100e998de89cd99c8c9e0000d7acf (patch)
tree7b7b7e6812dd35685153b2b4169067e48e698645
parentba6819b0086b2b80a62d8a094df889616d3744dc (diff)
downloadcouchdb-e05a6bfc03e100e998de89cd99c8c9e0000d7acf.tar.gz
Close backend port and clean up url handlers
Backend (5986) port is closed. Requests to `/_node/_local/_config` and a few other `_*` endpoints continues to work. Backend db access now returns error code 410 (not_supported). Previously, it was accessing couch_server and couch_files to create 3.x style local dbs. Url handlers are updated to return `not_supported` for features which are not coming back, and `not_implemented` for features which haven't been implemented yet. `parse_copy_destination_header/1` is the only function from `couch_httpd_db` that's still needed, so it was moved to `chttpd_util` module. `couch_httpd_db` handled `/_uuid` requests and that handler was moved to `chttpd_misc` module. "Welcome" endpoint (/) was updated to not call `clouseau_rpc:connected/0`. Request handling in `couch_httpd` was removed, so most of the file is now a bunch of utility functions mostly.
-rw-r--r--src/chttpd/src/chttpd.erl7
-rw-r--r--src/chttpd/src/chttpd_db.erl146
-rw-r--r--src/chttpd/src/chttpd_httpd_handlers.erl25
-rw-r--r--src/chttpd/src/chttpd_misc.erl37
-rw-r--r--src/chttpd/src/chttpd_node.erl46
-rw-r--r--src/chttpd/src/chttpd_show.erl150
-rw-r--r--src/chttpd/src/chttpd_util.erl41
-rw-r--r--src/couch/src/couch.app.src34
-rw-r--r--src/couch/src/couch_httpd.erl347
-rw-r--r--src/couch/src/couch_secondary_sup.erl10
-rw-r--r--src/couch/test/eunit/chttpd_endpoints_tests.erl18
-rw-r--r--src/couch_replicator/src/couch_replicator_ids.erl2
12 files changed, 112 insertions, 751 deletions
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index b1243755c..8567adaeb 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -123,6 +123,12 @@ start_link(Name, Options) ->
end,
ok = couch_httpd:validate_bind_address(IP),
+ % Ensure uuid is set so that concurrent replications
+ % get the same value. This used to in the backend (:5986) httpd
+ % start_link and was moved here for now. Ideally this should be set
+ % in FDB or coordinated across all the nodes
+ couch_server:get_uuid(),
+
set_auth_handlers(),
Options1 = Options ++ [
@@ -153,7 +159,6 @@ stop() ->
mochiweb_http:stop(?MODULE).
handle_request(MochiReq0) ->
- erlang:put(?REWRITE_COUNT, 0),
MochiReq = couch_httpd_vhost:dispatch_host(MochiReq0),
handle_request_int(MochiReq).
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index ac3d3b159..8b9905927 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -23,8 +23,7 @@
db_req/2, couch_doc_open/4,handle_changes_req/2,
update_doc_result_to_json/1, update_doc_result_to_json/2,
handle_design_info_req/3, handle_view_cleanup_req/2,
- update_doc/4, http_code_from_status/1,
- handle_partition_req/2]).
+ update_doc/4, http_code_from_status/1]).
-import(chttpd,
[send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,
@@ -275,80 +274,6 @@ handle_view_cleanup_req(Req, Db) ->
ok = fabric2_index:cleanup(Db),
send_json(Req, 202, {[{ok, true}]}).
-
-handle_partition_req(#httpd{path_parts=[_,_]}=_Req, _Db) ->
- throw({bad_request, invalid_partition_req});
-
-handle_partition_req(#httpd{method='GET', path_parts=[_,_,PartId]}=Req, Db) ->
- couch_partition:validate_partition(PartId),
- case couch_db:is_partitioned(Db) of
- true ->
- {ok, PartitionInfo} = fabric:get_partition_info(Db, PartId),
- send_json(Req, {PartitionInfo});
- false ->
- throw({bad_request, <<"database is not partitioned">>})
- end;
-
-handle_partition_req(#httpd{method='POST',
- path_parts=[_, <<"_partition">>, <<"_", _/binary>>]}, _Db) ->
- Msg = <<"Partition must not start with an underscore">>,
- throw({illegal_partition, Msg});
-
-handle_partition_req(#httpd{path_parts = [_, _, _]}=Req, _Db) ->
- send_method_not_allowed(Req, "GET");
-
-handle_partition_req(#httpd{path_parts=[DbName, _, PartId | Rest]}=Req, Db) ->
- case couch_db:is_partitioned(Db) of
- true ->
- couch_partition:validate_partition(PartId),
- QS = chttpd:qs(Req),
- PartIdStr = ?b2l(PartId),
- QSPartIdStr = couch_util:get_value("partition", QS, PartIdStr),
- if QSPartIdStr == PartIdStr -> ok; true ->
- Msg = <<"Conflicting value for `partition` in query string">>,
- throw({bad_request, Msg})
- end,
- NewQS = lists:ukeysort(1, [{"partition", PartIdStr} | QS]),
- NewReq = Req#httpd{
- path_parts = [DbName | Rest],
- qs = NewQS
- },
- update_partition_stats(Rest),
- case Rest of
- [OP | _] when OP == <<"_all_docs">> orelse ?IS_MANGO(OP) ->
- case chttpd_handlers:db_handler(OP, fun db_req/2) of
- Handler when is_function(Handler, 2) ->
- Handler(NewReq, Db);
- _ ->
- chttpd:send_error(Req, not_found)
- end;
- [<<"_design">>, _Name, <<"_", _/binary>> | _] ->
- handle_design_req(NewReq, Db);
- _ ->
- chttpd:send_error(Req, not_found)
- end;
- false ->
- throw({bad_request, <<"database is not partitioned">>})
- end;
-
-handle_partition_req(Req, _Db) ->
- chttpd:send_error(Req, not_found).
-
-update_partition_stats(PathParts) ->
- case PathParts of
- [<<"_design">> | _] ->
- couch_stats:increment_counter([couchdb, httpd, partition_view_requests]);
- [<<"_all_docs">> | _] ->
- couch_stats:increment_counter([couchdb, httpd, partition_all_docs_requests]);
- [<<"_find">> | _] ->
- couch_stats:increment_counter([couchdb, httpd, partition_find_requests]);
- [<<"_explain">> | _] ->
- couch_stats:increment_counter([couchdb, httpd, partition_explain_requests]);
- _ ->
- ok % ignore path that do not match
- end.
-
-
handle_design_req(#httpd{
path_parts=[_DbName, _Design, Name, <<"_",_/binary>> = Action | _Rest]
}=Req, Db) ->
@@ -635,41 +560,6 @@ db_req(#httpd{method='POST', path_parts=[_, <<"_bulk_get">>],
db_req(#httpd{path_parts=[_, <<"_bulk_get">>]}=Req, _Db) ->
send_method_not_allowed(Req, "POST");
-
-db_req(#httpd{method='POST',path_parts=[_,<<"_purge">>]}=Req, Db) ->
- couch_stats:increment_counter([couchdb, httpd, purge_requests]),
- chttpd:validate_ctype(Req, "application/json"),
- {IdsRevs} = chttpd:json_body_obj(Req),
- IdsRevs2 = [{Id, couch_doc:parse_revs(Revs)} || {Id, Revs} <- IdsRevs],
- MaxIds = config:get_integer("purge", "max_document_id_number", 100),
- case length(IdsRevs2) =< MaxIds of
- false -> throw({bad_request, "Exceeded maximum number of documents."});
- true -> ok
- end,
- RevsLen = lists:foldl(fun({_Id, Revs}, Acc) ->
- length(Revs) + Acc
- end, 0, IdsRevs2),
- MaxRevs = config:get_integer("purge", "max_revisions_number", 1000),
- case RevsLen =< MaxRevs of
- false -> throw({bad_request, "Exceeded maximum number of revisions."});
- true -> ok
- end,
- couch_stats:increment_counter([couchdb, document_purges, total], length(IdsRevs2)),
- Results2 = case fabric:purge_docs(Db, IdsRevs2, []) of
- {ok, Results} ->
- chttpd_stats:incr_writes(length(Results)),
- Results;
- {accepted, Results} ->
- chttpd_stats:incr_writes(length(Results)),
- Results
- end,
- {Code, Json} = purge_results_to_json(IdsRevs2, Results2),
- send_json(Req, Code, {[{<<"purge_seq">>, null}, {<<"purged">>, {Json}}]});
-
-db_req(#httpd{path_parts=[_,<<"_purge">>]}=Req, _Db) ->
- send_method_not_allowed(Req, "POST");
-
-
db_req(#httpd{method='GET',path_parts=[_,OP]}=Req, Db) when ?IS_ALL_DOCS(OP) ->
case chttpd:qs_json_value(Req, "keys", nil) of
Keys when is_list(Keys) ->
@@ -778,22 +668,6 @@ db_req(#httpd{method='GET',path_parts=[_,<<"_revs_limit">>]}=Req, Db) ->
db_req(#httpd{path_parts=[_,<<"_revs_limit">>]}=Req, _Db) ->
send_method_not_allowed(Req, "PUT,GET");
-db_req(#httpd{method='PUT',path_parts=[_,<<"_purged_infos_limit">>]}=Req, Db) ->
- case chttpd:json_body(Req) of
- Limit when is_integer(Limit), Limit > 0 ->
- case fabric:set_purge_infos_limit(Db, Limit, []) of
- ok ->
- send_json(Req, {[{<<"ok">>, true}]});
- Error ->
- throw(Error)
- end;
- _->
- throw({bad_request, "`purge_infos_limit` must be positive integer"})
- end;
-
-db_req(#httpd{method='GET',path_parts=[_,<<"_purged_infos_limit">>]}=Req, Db) ->
- send_json(Req, fabric:get_purge_infos_limit(Db));
-
% Special case to enable using an unencoded slash in the URL of design docs,
% as slashes in document IDs must otherwise be URL encoded.
db_req(#httpd{method='GET', mochi_req=MochiReq, path_parts=[_DbName, <<"_design/", _/binary>> | _]}=Req, _Db) ->
@@ -1444,24 +1318,6 @@ update_doc_result_to_json(DocId, Error) ->
{_Code, ErrorStr, Reason} = chttpd:error_info(Error),
{[{id, DocId}, {error, ErrorStr}, {reason, Reason}]}.
-purge_results_to_json([], []) ->
- {201, []};
-purge_results_to_json([{DocId, _Revs} | RIn], [{ok, PRevs} | ROut]) ->
- {Code, Results} = purge_results_to_json(RIn, ROut),
- couch_stats:increment_counter([couchdb, document_purges, success]),
- {Code, [{DocId, couch_doc:revs_to_strs(PRevs)} | Results]};
-purge_results_to_json([{DocId, _Revs} | RIn], [{accepted, PRevs} | ROut]) ->
- {Code, Results} = purge_results_to_json(RIn, ROut),
- couch_stats:increment_counter([couchdb, document_purges, success]),
- NewResults = [{DocId, couch_doc:revs_to_strs(PRevs)} | Results],
- {erlang:max(Code, 202), NewResults};
-purge_results_to_json([{DocId, _Revs} | RIn], [Error | ROut]) ->
- {Code, Results} = purge_results_to_json(RIn, ROut),
- {NewCode, ErrorStr, Reason} = chttpd:error_info(Error),
- couch_stats:increment_counter([couchdb, document_purges, failure]),
- NewResults = [{DocId, {[{error, ErrorStr}, {reason, Reason}]}} | Results],
- {erlang:max(NewCode, Code), NewResults}.
-
send_updated_doc(Req, Db, DocId, Json) ->
send_updated_doc(Req, Db, DocId, Json, []).
diff --git a/src/chttpd/src/chttpd_httpd_handlers.erl b/src/chttpd/src/chttpd_httpd_handlers.erl
index d50115917..e5374b1b6 100644
--- a/src/chttpd/src/chttpd_httpd_handlers.erl
+++ b/src/chttpd/src/chttpd_httpd_handlers.erl
@@ -15,9 +15,11 @@
-export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
-export([
- not_supported/2,
not_supported/3,
- not_implemented/2
+ not_supported/2,
+ not_supported/1,
+ not_implemented/2,
+ not_implemented/1
]).
@@ -38,16 +40,22 @@ url_handler(<<"_replicate">>) -> fun chttpd_misc:handle_replicate_req/1;
url_handler(<<"_uuids">>) -> fun chttpd_misc:handle_uuids_req/1;
url_handler(<<"_session">>) -> fun chttpd_auth:handle_session_req/1;
url_handler(<<"_up">>) -> fun chttpd_misc:handle_up_req/1;
+url_handler(<<"_membership">>) -> fun ?MODULE:not_supported/1;
+url_handler(<<"_reshard">>) -> fun ?MODULE:not_supported/1;
+url_handler(<<"_db_updates">>) -> fun ?MODULE:not_implemented/1;
+url_handler(<<"_cluster_setup">>) -> fun ?MODULE:not_implemented/1;
url_handler(_) -> no_match.
db_handler(<<"_view_cleanup">>) -> fun chttpd_db:handle_view_cleanup_req/2;
db_handler(<<"_compact">>) -> fun chttpd_db:handle_compact_req/2;
db_handler(<<"_design">>) -> fun chttpd_db:handle_design_req/2;
-db_handler(<<"_partition">>) -> fun chttpd_db:handle_partition_req/2;
+db_handler(<<"_partition">>) -> fun ?MODULE:not_implemented/2;
db_handler(<<"_temp_view">>) -> fun ?MODULE:not_supported/2;
db_handler(<<"_changes">>) -> fun chttpd_db:handle_changes_req/2;
db_handler(<<"_purge">>) -> fun ?MODULE:not_implemented/2;
db_handler(<<"_purged_infos_limit">>) -> fun ?MODULE:not_implemented/2;
+db_handler(<<"_shards">>) -> fun ?MODULE:not_supported/2;
+db_handler(<<"_sync_shards">>) -> fun ?MODULE:not_supported/2;
db_handler(_) -> no_match.
design_handler(<<"_view">>) -> fun chttpd_view:handle_view_req/3;
@@ -186,7 +194,6 @@ handler_info(Method, [<<"_", _/binary>> = Part| Rest], Req) ->
% on for known system databases.
DbName = case Part of
<<"_dbs">> -> '_dbs';
- <<"_global_changes">> -> '_global_changes';
<<"_metadata">> -> '_metadata';
<<"_nodes">> -> '_nodes';
<<"_replicator">> -> '_replicator';
@@ -497,7 +504,7 @@ handler_info(_, _, _) ->
get_copy_destination(Req) ->
try
- {DocIdStr, _} = couch_httpd_db:parse_copy_destination_header(Req),
+ {DocIdStr, _} = chttpd_util:parse_copy_destination_header(Req),
list_to_binary(mochiweb_util:unquote(DocIdStr))
catch _:_ ->
unknown
@@ -509,10 +516,18 @@ not_supported(#httpd{} = Req, Db, _DDoc) ->
not_supported(#httpd{} = Req, _Db) ->
+ not_supported(Req).
+
+
+not_supported(#httpd{} = Req) ->
Msg = <<"resource is not supported in CouchDB >= 4.x">>,
chttpd:send_error(Req, 410, gone, Msg).
not_implemented(#httpd{} = Req, _Db) ->
+ not_implemented(Req).
+
+
+not_implemented(#httpd{} = Req) ->
Msg = <<"resource is not implemented">>,
chttpd:send_error(Req, 501, not_implemented, Msg).
diff --git a/src/chttpd/src/chttpd_misc.erl b/src/chttpd/src/chttpd_misc.erl
index 5cfd0f7cb..5d9706abf 100644
--- a/src/chttpd/src/chttpd_misc.erl
+++ b/src/chttpd/src/chttpd_misc.erl
@@ -33,7 +33,7 @@
-include_lib("couch_mrview/include/couch_mrview.hrl").
-import(chttpd,
- [send_json/2,send_json/3,send_method_not_allowed/2,
+ [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,
send_chunk/2,start_chunked_response/3]).
-define(MAX_DB_NUM_FOR_DBS_INFO, 100).
@@ -61,12 +61,7 @@ handle_welcome_req(Req, _) ->
send_method_not_allowed(Req, "GET,HEAD").
get_features() ->
- case clouseau_rpc:connected() of
- true ->
- [search | config:features()];
- false ->
- config:features()
- end.
+ config:features().
handle_favicon_req(Req) ->
handle_favicon_req(Req, get_docroot()).
@@ -334,9 +329,33 @@ handle_reload_query_servers_req(#httpd{method='POST'}=Req) ->
handle_reload_query_servers_req(Req) ->
send_method_not_allowed(Req, "POST").
+handle_uuids_req(#httpd{method='GET'}=Req) ->
+ Max = list_to_integer(config:get("uuids","max_count","1000")),
+ Count = try list_to_integer(couch_httpd:qs_value(Req, "count", "1")) of
+ N when N > Max ->
+ throw({bad_request, <<"count parameter too large">>});
+ N when N < 0 ->
+ throw({bad_request, <<"count must be a positive integer">>});
+ N -> N
+ catch
+ error:badarg ->
+ throw({bad_request, <<"count must be a positive integer">>})
+ end,
+ UUIDs = [couch_uuids:new() || _ <- lists:seq(1, Count)],
+ Etag = couch_httpd:make_etag(UUIDs),
+ couch_httpd:etag_respond(Req, Etag, fun() ->
+ CacheBustingHeaders = [
+ {"Date", couch_util:rfc1123_date()},
+ {"Cache-Control", "no-cache"},
+ % Past date, ON PURPOSE!
+ {"Expires", "Mon, 01 Jan 1990 00:00:00 GMT"},
+ {"Pragma", "no-cache"},
+ {"ETag", Etag}
+ ],
+ send_json(Req, 200, CacheBustingHeaders, {[{<<"uuids">>, UUIDs}]})
+ end);
handle_uuids_req(Req) ->
- couch_httpd_misc_handlers:handle_uuids_req(Req).
-
+ send_method_not_allowed(Req, "GET").
handle_up_req(#httpd{method='GET'} = Req) ->
case config:get("couchdb", "maintenance_mode") of
diff --git a/src/chttpd/src/chttpd_node.erl b/src/chttpd/src/chttpd_node.erl
index b6c4fac6c..e36380aeb 100644
--- a/src/chttpd/src/chttpd_node.erl
+++ b/src/chttpd/src/chttpd_node.erl
@@ -138,54 +138,14 @@ handle_node_req(#httpd{method='POST', path_parts=[_, Node, <<"_restart">>]}=Req)
send_json(Req, 200, {[{ok, true}]});
handle_node_req(#httpd{path_parts=[_, _Node, <<"_restart">>]}=Req) ->
send_method_not_allowed(Req, "POST");
-handle_node_req(#httpd{path_parts=[_, Node | PathParts],
- mochi_req=MochiReq0}) ->
- % strip /_node/{node} from Req0 before descending further
- RawUri = MochiReq0:get(raw_path),
- {_, Query, Fragment} = mochiweb_util:urlsplit_path(RawUri),
- NewPath0 = "/" ++ lists:join("/", [couch_util:url_encode(P) || P <- PathParts]),
- NewRawPath = mochiweb_util:urlunsplit_path({NewPath0, Query, Fragment}),
- 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]),
- recv_loop(Ref, MochiReq0);
+handle_node_req(#httpd{path_parts=[_, _Node | _PathParts]}=Req) ->
+ % Local (backend) dbs are not support any more
+ chttpd_httpd_handlers:not_supported(Req);
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, ReqResp) ->
- receive
- {Ref, Code, Headers, _Args, start_response} ->
- recv_loop(Ref, ReqResp:start({Code, Headers}));
- {Ref, Code, Headers, Len, start_response_length} ->
- recv_loop(Ref, ReqResp:start_response_length({Code, Headers, Len}));
- {Ref, Code, Headers, chunked, respond} ->
- Resp = ReqResp:respond({Code, Headers, chunked}),
- recv_loop(Ref, Resp);
- {Ref, Code, Headers, Args, respond} ->
- Resp = ReqResp:respond({Code, Headers, Args}),
- {ok, Resp};
- {Ref, send, Data} ->
- ReqResp:send(Data),
- {ok, ReqResp};
- {Ref, chunk, <<>>} ->
- ReqResp:write_chunk(<<>>),
- {ok, ReqResp};
- {Ref, chunk, Data} ->
- ReqResp:write_chunk(Data),
- recv_loop(Ref, ReqResp);
- _Else ->
- recv_loop(Ref, ReqResp)
- end.
-
call_node(Node0, Mod, Fun, Args) when is_binary(Node0) ->
Node1 = try
list_to_existing_atom(?b2l(Node0))
diff --git a/src/chttpd/src/chttpd_show.erl b/src/chttpd/src/chttpd_show.erl
index 8a15bdcbe..295d753a0 100644
--- a/src/chttpd/src/chttpd_show.erl
+++ b/src/chttpd/src/chttpd_show.erl
@@ -12,15 +12,11 @@
-module(chttpd_show).
--export([handle_doc_show_req/3, handle_doc_update_req/3, handle_view_list_req/3]).
+-export([handle_doc_update_req/3]).
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-% /db/_design/foo/_show/bar/docid
-% show converts a json doc to a response of any content-type.
-% it looks up the doc an then passes it to the query server.
-% then it sends the response from the query server to the http client.
maybe_open_doc(Db, DocId, Options) ->
case fabric:open_doc(Db, DocId, Options) of
@@ -31,70 +27,6 @@ maybe_open_doc(Db, DocId, Options) ->
nil
end.
-handle_doc_show_req(#httpd{
- path_parts=[_, _, _, _, ShowName, DocId]
- }=Req, Db, DDoc) ->
-
- % open the doc
- Options = [conflicts, {user_ctx, Req#httpd.user_ctx}],
- Doc = maybe_open_doc(Db, DocId, Options),
-
- % we don't handle revs here b/c they are an internal api
- % returns 404 if there is no doc with DocId
- handle_doc_show(Req, Db, DDoc, ShowName, Doc, DocId);
-
-handle_doc_show_req(#httpd{
- path_parts=[_, _, _, _, ShowName, DocId|Rest]
- }=Req, Db, DDoc) ->
-
- DocParts = [DocId|Rest],
- DocId1 = ?l2b(string:join([?b2l(P)|| P <- DocParts], "/")),
-
- % open the doc
- Options = [conflicts, {user_ctx, Req#httpd.user_ctx}],
- Doc = maybe_open_doc(Db, DocId1, Options),
-
- % we don't handle revs here b/c they are an internal api
- % pass 404 docs to the show function
- handle_doc_show(Req, Db, DDoc, ShowName, Doc, DocId1);
-
-handle_doc_show_req(#httpd{
- path_parts=[_, _, _, _, ShowName]
- }=Req, Db, DDoc) ->
- % with no docid the doc is nil
- handle_doc_show(Req, Db, DDoc, ShowName, nil);
-
-handle_doc_show_req(Req, _Db, _DDoc) ->
- chttpd:send_error(Req, 404, <<"show_error">>, <<"Invalid path.">>).
-
-handle_doc_show(Req, Db, DDoc, ShowName, Doc) ->
- handle_doc_show(Req, Db, DDoc, ShowName, Doc, null).
-
-handle_doc_show(Req, Db, DDoc, ShowName, Doc, DocId) ->
- %% Will throw an exception if the _show handler is missing
- couch_util:get_nested_json_value(DDoc#doc.body, [<<"shows">>, ShowName]),
- % get responder for ddoc/showname
- CurrentEtag = show_etag(Req, Doc, DDoc, []),
- chttpd:etag_respond(Req, CurrentEtag, fun() ->
- JsonReq = chttpd_external:json_req_obj(Req, Db, DocId),
- JsonDoc = couch_query_servers:json_doc(Doc),
- [<<"resp">>, ExternalResp] =
- couch_query_servers:ddoc_prompt(DDoc, [<<"shows">>, ShowName],
- [JsonDoc, JsonReq]),
- JsonResp = apply_etag(ExternalResp, CurrentEtag),
- chttpd_external:send_external_response(Req, JsonResp)
- end).
-
-
-show_etag(#httpd{user_ctx=UserCtx}=Req, Doc, DDoc, More) ->
- Accept = chttpd:header_value(Req, "Accept"),
- DocPart = case Doc of
- nil -> nil;
- Doc -> chttpd:doc_etag(Doc)
- end,
- couch_httpd:make_etag({couch_httpd:doc_etag(DDoc), DocPart, Accept,
- UserCtx#user_ctx.roles, More}).
-
% /db/_design/foo/update/bar/docid
% updates a doc based on a request
% handle_doc_update_req(#httpd{method = 'GET'}=Req, _Db, _DDoc) ->
@@ -154,86 +86,6 @@ send_doc_update_response(Req, Db, DDoc, UpdateName, Doc, DocId) ->
% todo set location field
chttpd_external:send_external_response(Req, JsonResp).
-
-% view-list request with view and list from same design doc.
-handle_view_list_req(#httpd{method=Method,
- path_parts=[_, _, DesignName, _, ListName, ViewName]}=Req, Db, DDoc)
- when Method =:= 'GET' orelse Method =:= 'OPTIONS' ->
- Keys = chttpd:qs_json_value(Req, "keys", undefined),
- handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, Keys);
-
-% view-list request with view and list from different design docs.
-handle_view_list_req(#httpd{method=Method,
- path_parts=[_, _, _, _, ListName, DesignName, ViewName]}=Req, Db, DDoc)
- when Method =:= 'GET' orelse Method =:= 'OPTIONS' ->
- Keys = chttpd:qs_json_value(Req, "keys", undefined),
- handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, Keys);
-
-handle_view_list_req(#httpd{method=Method}=Req, _Db, _DDoc)
- when Method =:= 'GET' orelse Method =:= 'OPTIONS' ->
- chttpd:send_error(Req, 404, <<"list_error">>, <<"Invalid path.">>);
-
-handle_view_list_req(#httpd{method='POST',
- path_parts=[_, _, DesignName, _, ListName, ViewName]}=Req, Db, DDoc) ->
- chttpd:validate_ctype(Req, "application/json"),
- ReqBody = chttpd:body(Req),
- {Props2} = ?JSON_DECODE(ReqBody),
- Keys = proplists:get_value(<<"keys">>, Props2, undefined),
- handle_view_list(Req#httpd{req_body=ReqBody}, Db, DDoc, ListName,
- {DesignName, ViewName}, Keys);
-
-handle_view_list_req(#httpd{method='POST',
- path_parts=[_, _, _, _, ListName, DesignName, ViewName]}=Req, Db, DDoc) ->
- chttpd:validate_ctype(Req, "application/json"),
- ReqBody = chttpd:body(Req),
- {Props2} = ?JSON_DECODE(ReqBody),
- Keys = proplists:get_value(<<"keys">>, Props2, undefined),
- handle_view_list(Req#httpd{req_body=ReqBody}, Db, DDoc, ListName,
- {DesignName, ViewName}, Keys);
-
-handle_view_list_req(#httpd{method='POST'}=Req, _Db, _DDoc) ->
- chttpd:send_error(Req, 404, <<"list_error">>, <<"Invalid path.">>);
-
-handle_view_list_req(Req, _Db, _DDoc) ->
- chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
-
-handle_view_list(Req, Db, DDoc, LName, {ViewDesignName, ViewName}, Keys) ->
- %% Will throw an exception if the _list handler is missing
- couch_util:get_nested_json_value(DDoc#doc.body, [<<"lists">>, LName]),
- DbName = couch_db:name(Db),
- {ok, VDoc} = ddoc_cache:open(DbName, <<"_design/", ViewDesignName/binary>>),
- CB = fun list_cb/2,
- QueryArgs = couch_mrview_http:parse_body_and_query(Req, Keys),
- Options = [{user_ctx, Req#httpd.user_ctx}],
- couch_query_servers:with_ddoc_proc(DDoc, fun(QServer) ->
- Acc = #lacc{
- lname = LName,
- req = Req,
- qserver = QServer,
- db = Db
- },
- case ViewName of
- <<"_all_docs">> ->
- fabric:all_docs(Db, Options, CB, Acc, QueryArgs);
- _ ->
- fabric:query_view(Db, Options, VDoc, ViewName,
- CB, Acc, QueryArgs)
- end
- end).
-
-
-list_cb({row, Row} = Msg, Acc) ->
- case lists:keymember(doc, 1, Row) of
- true -> chttpd_stats:incr_reads();
- false -> ok
- end,
- chttpd_stats:incr_rows(),
- couch_mrview_show:list_cb(Msg, Acc);
-
-list_cb(Msg, Acc) ->
- couch_mrview_show:list_cb(Msg, Acc).
-
-
% Maybe this is in the proplists API
% todo move to couch_util
json_apply_field(H, {L}) ->
diff --git a/src/chttpd/src/chttpd_util.erl b/src/chttpd/src/chttpd_util.erl
new file mode 100644
index 000000000..fcaa09de0
--- /dev/null
+++ b/src/chttpd/src/chttpd_util.erl
@@ -0,0 +1,41 @@
+% 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(chttpd_util).
+
+
+-export([
+ parse_copy_destination_header/1
+]).
+
+
+parse_copy_destination_header(Req) ->
+ case couch_httpd:header_value(Req, "Destination") of
+ undefined ->
+ throw({bad_request, "Destination header is mandatory for COPY."});
+ Destination ->
+ case re:run(Destination, "^https?://", [{capture, none}]) of
+ match ->
+ throw({bad_request, "Destination URL must be relative."});
+ nomatch ->
+ % see if ?rev=revid got appended to the Destination header
+ case re:run(Destination, "\\?", [{capture, none}]) of
+ nomatch ->
+ {list_to_binary(Destination), {0, []}};
+ match ->
+ [DocId, RevQs] = re:split(Destination, "\\?", [{return, list}]),
+ [_RevQueryKey, Rev] = re:split(RevQs, "=", [{return, list}]),
+ {Pos, RevId} = couch_doc:parse_rev(Rev),
+ {list_to_binary(DocId), {Pos, [RevId]}}
+ end
+ end
+ end.
diff --git a/src/couch/src/couch.app.src b/src/couch/src/couch.app.src
index e411b5eab..af277c161 100644
--- a/src/couch/src/couch.app.src
+++ b/src/couch/src/couch.app.src
@@ -42,39 +42,5 @@
couch_stats,
hyper,
couch_prometheus
- ]},
- {env, [
- { httpd_global_handlers, [
- {"/", "{couch_httpd_misc_handlers, handle_welcome_req, <<\"Welcome\">>}"},
- {"favicon.ico", "{couch_httpd_misc_handlers, handle_favicon_req, \"{{prefix}}/share/www\"}"},
- {"_utils", "{couch_httpd_misc_handlers, handle_utils_dir_req, \"{{prefix}}/share/www\"}"},
- {"_all_dbs", "{couch_httpd_misc_handlers, handle_all_dbs_req}"},
- {"_active_tasks", "{couch_httpd_misc_handlers, handle_task_status_req}"},
- {"_config", "{couch_httpd_misc_handlers, handle_config_req}"},
- {"_replicate", "{couch_replicator_httpd, handle_req}"},
- {"_uuids", "{couch_httpd_misc_handlers, handle_uuids_req}"},
- {"_stats", "{couch_stats_httpd, handle_stats_req}"},
- {"_session", "{couch_httpd_auth, handle_session_req}"},
- {"_plugins", "{couch_plugins_httpd, handle_req}"}
- ]},
- { httpd_db_handlers, [
- {"_all_docs", "{couch_mrview_http, handle_all_docs_req}"},
- {"_local_docs", "{couch_mrview_http, handle_local_docs_req}"},
- {"_design_docs", "{couch_mrview_http, handle_design_docs_req}"},
- {"_changes", "{couch_httpd_db, handle_db_changes_req}"},
- {"_compact", "{couch_httpd_db, handle_compact_req}"},
- {"_design", "{couch_httpd_db, handle_design_req}"},
- {"_temp_view", "{couch_mrview_http, handle_temp_view_req}"},
- {"_view_cleanup", "{couch_mrview_http, handle_cleanup_req}"}
- ]},
- { httpd_design_handlers, [
- {"_compact", "{couch_mrview_http, handle_compact_req}"},
- {"_info", "{couch_mrview_http, handle_info_req}"},
- {"_list", "{couch_mrview_show, handle_view_list_req}"},
- {"_rewrite", "{couch_httpd_rewrite, handle_rewrite_req}"},
- {"_show", "{couch_mrview_show, handle_doc_show_req}"},
- {"_update", "{couch_mrview_show, handle_doc_update_req}"},
- {"_view", "{couch_mrview_http, handle_view_req}"}
- ]}
]}
]}.
diff --git a/src/couch/src/couch_httpd.erl b/src/couch/src/couch_httpd.erl
index d89c74957..fd83c258a 100644
--- a/src/couch/src/couch_httpd.erl
+++ b/src/couch/src/couch_httpd.erl
@@ -16,8 +16,6 @@
-include_lib("couch/include/couch_db.hrl").
--export([start_link/0, start_link/1, stop/0, handle_request/5]).
-
-export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,qs_json_value/3]).
-export([path/1,absolute_uri/2,body_length/1]).
-export([verify_is_server_admin/1,unquote/1,quote/1,recv/2,recv_chunked/4,error_info/1]).
@@ -32,164 +30,17 @@
-export([send_response/4,send_response_no_cors/4,send_method_not_allowed/2,
send_error/2,send_error/4, send_redirect/2,send_chunked_error/2]).
-export([send_json/2,send_json/3,send_json/4,last_chunk/1,parse_multipart_request/3]).
--export([accepted_encodings/1,handle_request_int/5,validate_referer/1,validate_ctype/2]).
+-export([accepted_encodings/1,validate_referer/1,validate_ctype/2]).
-export([http_1_0_keep_alive/2]).
-export([validate_host/1]).
-export([validate_bind_address/1]).
-export([check_max_request_length/1]).
--export([handle_request/1]).
--export([set_auth_handlers/0]).
-export([maybe_decompress/2]).
-define(HANDLER_NAME_IN_MODULE_POS, 6).
-define(MAX_DRAIN_BYTES, 1048576).
-define(MAX_DRAIN_TIME_MSEC, 1000).
-start_link() ->
- start_link(http).
-start_link(http) ->
- Port = config:get("httpd", "port", "5984"),
- start_link(?MODULE, [{port, Port}]);
-start_link(https) ->
- Port = config:get("ssl", "port", "6984"),
- {ok, Ciphers} = couch_util:parse_term(config:get("ssl", "ciphers", undefined)),
- {ok, Versions} = couch_util:parse_term(config:get("ssl", "tls_versions", undefined)),
- {ok, SecureRenegotiate} = couch_util:parse_term(config:get("ssl", "secure_renegotiate", undefined)),
- ServerOpts0 =
- [{cacertfile, config:get("ssl", "cacert_file", undefined)},
- {keyfile, config:get("ssl", "key_file", undefined)},
- {certfile, config:get("ssl", "cert_file", undefined)},
- {password, config:get("ssl", "password", undefined)},
- {secure_renegotiate, SecureRenegotiate},
- {versions, Versions},
- {ciphers, Ciphers}],
-
- case (couch_util:get_value(keyfile, ServerOpts0) == undefined orelse
- couch_util:get_value(certfile, ServerOpts0) == undefined) of
- true ->
- couch_log:error("SSL enabled but PEM certificates are missing", []),
- throw({error, missing_certs});
- false ->
- ok
- end,
-
- ServerOpts = [Opt || {_, V}=Opt <- ServerOpts0, V /= undefined],
-
- ClientOpts = case config:get("ssl", "verify_ssl_certificates", "false") of
- "false" ->
- [];
- "true" ->
- FailIfNoPeerCert = case config:get("ssl", "fail_if_no_peer_cert", "false") of
- "false" -> false;
- "true" -> true
- end,
- [{depth, list_to_integer(config:get("ssl",
- "ssl_certificate_max_depth", "1"))},
- {fail_if_no_peer_cert, FailIfNoPeerCert},
- {verify, verify_peer}] ++
- case config:get("ssl", "verify_fun", undefined) of
- undefined -> [];
- SpecStr ->
- [{verify_fun, make_arity_3_fun(SpecStr)}]
- end
- end,
- SslOpts = ServerOpts ++ ClientOpts,
-
- Options =
- [{port, Port},
- {ssl, true},
- {ssl_opts, SslOpts}],
- start_link(https, Options).
-start_link(Name, Options) ->
- BindAddress = case config:get("httpd", "bind_address", "any") of
- "any" -> any;
- Else -> Else
- end,
- ok = validate_bind_address(BindAddress),
-
- {ok, ServerOptions} = couch_util:parse_term(
- config:get("httpd", "server_options", "[]")),
- {ok, SocketOptions} = couch_util:parse_term(
- config:get("httpd", "socket_options", "[]")),
-
- set_auth_handlers(),
- Handlers = get_httpd_handlers(),
-
- % ensure uuid is set so that concurrent replications
- % get the same value.
- couch_server:get_uuid(),
-
- Loop = fun(Req)->
- case SocketOptions of
- [] ->
- ok;
- _ ->
- ok = mochiweb_socket:setopts(Req:get(socket), SocketOptions)
- end,
- apply(?MODULE, handle_request, [Req | Handlers])
- end,
-
- % set mochiweb options
- FinalOptions = lists:append([Options, ServerOptions, [
- {loop, Loop},
- {name, Name},
- {ip, BindAddress}]]),
-
- % launch mochiweb
- case mochiweb_http:start(FinalOptions) of
- {ok, MochiPid} ->
- {ok, MochiPid};
- {error, Reason} ->
- couch_log:error("Failure to start Mochiweb: ~s~n", [Reason]),
- throw({error, Reason})
- end.
-
-
-stop() ->
- mochiweb_http:stop(couch_httpd),
- catch mochiweb_http:stop(https).
-
-
-set_auth_handlers() ->
- AuthenticationSrcs = make_fun_spec_strs(
- config:get("httpd", "authentication_handlers", "")),
- AuthHandlers = lists:map(
- fun(A) -> {auth_handler_name(A), make_arity_1_fun(A)} end, AuthenticationSrcs),
- AuthenticationFuns = AuthHandlers ++ [
- fun couch_httpd_auth:party_mode_handler/1 %% must be last
- ],
- ok = application:set_env(couch, auth_handlers, AuthenticationFuns).
-
-auth_handler_name(SpecStr) ->
- lists:nth(?HANDLER_NAME_IN_MODULE_POS, re:split(SpecStr, "[\\W_]", [])).
-
-get_httpd_handlers() ->
- {ok, HttpdGlobalHandlers} = application:get_env(couch, httpd_global_handlers),
-
- UrlHandlersList = lists:map(
- fun({UrlKey, SpecStr}) ->
- {?l2b(UrlKey), make_arity_1_fun(SpecStr)}
- end, HttpdGlobalHandlers),
-
- {ok, HttpdDbHandlers} = application:get_env(couch, httpd_db_handlers),
-
- DbUrlHandlersList = lists:map(
- fun({UrlKey, SpecStr}) ->
- {?l2b(UrlKey), make_arity_2_fun(SpecStr)}
- end, HttpdDbHandlers),
-
- {ok, HttpdDesignHandlers} = application:get_env(couch, httpd_design_handlers),
-
- DesignUrlHandlersList = lists:map(
- fun({UrlKey, SpecStr}) ->
- {?l2b(UrlKey), make_arity_3_fun(SpecStr)}
- end, HttpdDesignHandlers),
-
- UrlHandlers = dict:from_list(UrlHandlersList),
- DbUrlHandlers = dict:from_list(DbUrlHandlersList),
- DesignUrlHandlers = dict:from_list(DesignUrlHandlersList),
- DefaultFun = make_arity_1_fun("{couch_httpd_db, handle_request}"),
- [DefaultFun, UrlHandlers, DbUrlHandlers, DesignUrlHandlers].
% SpecStr is a string like "{my_module, my_fun}"
% or "{my_module, my_fun, <<"my_arg">>}"
@@ -221,175 +72,6 @@ make_arity_3_fun(SpecStr) ->
make_fun_spec_strs(SpecStr) ->
re:split(SpecStr, "(?<=})\\s*,\\s*(?={)", [{return, list}]).
-handle_request(MochiReq) ->
- Body = proplists:get_value(body, MochiReq:get(opts)),
- erlang:put(mochiweb_request_body, Body),
- apply(?MODULE, handle_request, [MochiReq | get_httpd_handlers()]).
-
-handle_request(MochiReq, DefaultFun, UrlHandlers, DbUrlHandlers,
- DesignUrlHandlers) ->
- %% reset rewrite count for new request
- erlang:put(?REWRITE_COUNT, 0),
-
- MochiReq1 = couch_httpd_vhost:dispatch_host(MochiReq),
-
- handle_request_int(MochiReq1, DefaultFun,
- UrlHandlers, DbUrlHandlers, DesignUrlHandlers).
-
-handle_request_int(MochiReq, DefaultFun,
- UrlHandlers, DbUrlHandlers, DesignUrlHandlers) ->
- Begin = os:timestamp(),
- % for the path, use the raw path with the query string and fragment
- % removed, but URL quoting left intact
- RawUri = MochiReq:get(raw_path),
- {"/" ++ Path, _, _} = mochiweb_util:urlsplit_path(RawUri),
-
- % get requested path
- RequestedPath = case MochiReq:get_header_value("x-couchdb-vhost-path") of
- undefined ->
- case MochiReq:get_header_value("x-couchdb-requested-path") of
- undefined -> RawUri;
- R -> R
- end;
- P -> P
- end,
-
- HandlerKey =
- case mochiweb_util:partition(Path, "/") of
- {"", "", ""} ->
- <<"/">>; % Special case the root url handler
- {FirstPart, _, _} ->
- list_to_binary(FirstPart)
- end,
- couch_log:debug("~p ~s ~p from ~p~nHeaders: ~p", [
- MochiReq:get(method),
- RawUri,
- MochiReq:get(version),
- peer(MochiReq),
- mochiweb_headers:to_list(MochiReq:get(headers))
- ]),
-
- Method1 =
- case MochiReq:get(method) of
- % already an atom
- Meth when is_atom(Meth) -> Meth;
-
- % Non standard HTTP verbs aren't atoms (COPY, MOVE etc) so convert when
- % possible (if any module references the atom, then it's existing).
- Meth -> couch_util:to_existing_atom(Meth)
- end,
- increment_method_stats(Method1),
-
- % allow broken HTTP clients to fake a full method vocabulary with an X-HTTP-METHOD-OVERRIDE header
- MethodOverride = MochiReq:get_primary_header_value("X-HTTP-Method-Override"),
- Method2 = case lists:member(MethodOverride, ["GET", "HEAD", "POST",
- "PUT", "DELETE",
- "TRACE", "CONNECT",
- "COPY"]) of
- true ->
- couch_log:info("MethodOverride: ~s (real method was ~s)",
- [MethodOverride, Method1]),
- case Method1 of
- 'POST' -> couch_util:to_existing_atom(MethodOverride);
- _ ->
- % Ignore X-HTTP-Method-Override when the original verb isn't POST.
- % I'd like to send a 406 error to the client, but that'd require a nasty refactor.
- % throw({not_acceptable, <<"X-HTTP-Method-Override may only be used with POST requests.">>})
- Method1
- end;
- _ -> Method1
- end,
-
- % alias HEAD to GET as mochiweb takes care of stripping the body
- Method = case Method2 of
- 'HEAD' -> 'GET';
- Other -> Other
- end,
-
- HttpReq = #httpd{
- mochi_req = MochiReq,
- peer = peer(MochiReq),
- method = Method,
- requested_path_parts =
- [?l2b(unquote(Part)) || Part <- string:tokens(RequestedPath, "/")],
- path_parts = [?l2b(unquote(Part)) || Part <- string:tokens(Path, "/")],
- db_url_handlers = DbUrlHandlers,
- design_url_handlers = DesignUrlHandlers,
- default_fun = DefaultFun,
- url_handlers = UrlHandlers,
- user_ctx = erlang:erase(pre_rewrite_user_ctx),
- auth = erlang:erase(pre_rewrite_auth)
- },
-
- HandlerFun = couch_util:dict_find(HandlerKey, UrlHandlers, DefaultFun),
-
- {ok, Resp} =
- try
- validate_host(HttpReq),
- check_request_uri_length(RawUri),
- case chttpd_cors:maybe_handle_preflight_request(HttpReq) of
- not_preflight ->
- case authenticate_request(HttpReq) of
- #httpd{} = Req ->
- HandlerFun(Req);
- Response ->
- Response
- end;
- Response ->
- Response
- end
- catch
- throw:{http_head_abort, Resp0} ->
- {ok, Resp0};
- throw:{invalid_json, S} ->
- couch_log:error("attempted upload of invalid JSON"
- " (set log_level to debug to log it)", []),
- couch_log:debug("Invalid JSON: ~p",[S]),
- send_error(HttpReq, {bad_request, invalid_json});
- throw:unacceptable_encoding ->
- couch_log:error("unsupported encoding method for the response", []),
- send_error(HttpReq, {not_acceptable, "unsupported encoding"});
- throw:bad_accept_encoding_value ->
- couch_log:error("received invalid Accept-Encoding header", []),
- send_error(HttpReq, bad_request);
- exit:normal ->
- exit(normal);
- exit:snappy_nif_not_loaded ->
- ErrorReason = "To access the database or view index, Apache CouchDB"
- " must be built with Erlang OTP R13B04 or higher.",
- couch_log:error("~s", [ErrorReason]),
- send_error(HttpReq, {bad_otp_release, ErrorReason});
- exit:{body_too_large, _} ->
- send_error(HttpReq, request_entity_too_large);
- exit:{uri_too_long, _} ->
- send_error(HttpReq, request_uri_too_long);
- throw:Error ->
- Stack = erlang:get_stacktrace(),
- couch_log:debug("Minor error in HTTP request: ~p",[Error]),
- couch_log:debug("Stacktrace: ~p",[Stack]),
- send_error(HttpReq, Error);
- error:badarg ->
- Stack = erlang:get_stacktrace(),
- couch_log:error("Badarg error in HTTP request",[]),
- couch_log:info("Stacktrace: ~p",[Stack]),
- send_error(HttpReq, badarg);
- error:function_clause ->
- Stack = erlang:get_stacktrace(),
- couch_log:error("function_clause error in HTTP request",[]),
- couch_log:info("Stacktrace: ~p",[Stack]),
- send_error(HttpReq, function_clause);
- Tag:Error ->
- Stack = erlang:get_stacktrace(),
- couch_log:error("Uncaught error in HTTP request: ~p",
- [{Tag, Error}]),
- couch_log:info("Stacktrace: ~p",[Stack]),
- send_error(HttpReq, Error)
- end,
- RequestTime = round(timer:now_diff(os:timestamp(), Begin)/1000),
- couch_stats:update_histogram([couchdb, request_time], RequestTime),
- couch_stats:increment_counter([couchdb, httpd, requests]),
- {ok, Resp}.
-
validate_host(#httpd{} = Req) ->
case config:get_boolean("httpd", "validate_host", false) of
true ->
@@ -418,26 +100,6 @@ valid_hosts() ->
List = config:get("httpd", "valid_hosts", ""),
re:split(List, ",", [{return, list}]).
-check_request_uri_length(Uri) ->
- check_request_uri_length(Uri, config:get("httpd", "max_uri_length")).
-
-check_request_uri_length(_Uri, undefined) ->
- ok;
-check_request_uri_length(Uri, MaxUriLen) when is_list(MaxUriLen) ->
- case length(Uri) > list_to_integer(MaxUriLen) of
- true ->
- throw(request_uri_too_long);
- false ->
- ok
- end.
-
-authenticate_request(Req) ->
- {ok, AuthenticationFuns} = application:get_env(couch, auth_handlers),
- chttpd:authenticate_request(Req, couch_auth_cache, AuthenticationFuns).
-
-increment_method_stats(Method) ->
- couch_stats:increment_counter([couchdb, httpd_request_methods, Method]).
-
validate_referer(Req) ->
Host = host_for_request(Req),
Referer = header_value(Req, "Referer", fail),
@@ -1225,13 +887,6 @@ http_respond_(#httpd{mochi_req = MochiReq}, 413, Headers, Args, Type) ->
http_respond_(#httpd{mochi_req = MochiReq}, Code, Headers, Args, Type) ->
MochiReq:Type({Code, Headers, Args}).
-peer(MochiReq) ->
- case MochiReq:get(socket) of
- {remote, Pid, _} ->
- node(Pid);
- _ ->
- MochiReq:get(peer)
- end.
%%%%%%%% module tests below %%%%%%%%
diff --git a/src/couch/src/couch_secondary_sup.erl b/src/couch/src/couch_secondary_sup.erl
index bb7821555..4ccd0c9dd 100644
--- a/src/couch/src/couch_secondary_sup.erl
+++ b/src/couch/src/couch_secondary_sup.erl
@@ -33,11 +33,6 @@ init([]) ->
{uuids, {couch_uuids, start, []}}
],
- MaybeHttp = case http_enabled() of
- true -> [{httpd, {couch_httpd, start_link, []}}];
- false -> couch_httpd:set_auth_handlers(), []
- end,
-
MaybeHttps = case https_enabled() of
true -> [{httpsd, {chttpd, start_link, [https]}}];
false -> []
@@ -55,13 +50,10 @@ init([]) ->
[Module]}
end
|| {Name, Spec}
- <- Daemons ++ MaybeHttp ++ MaybeHttps, Spec /= ""],
+ <- Daemons ++ MaybeHttps, Spec /= ""],
{ok, {{one_for_one, 50, 3600},
couch_epi:register_service(couch_db_epi, Children)}}.
-http_enabled() ->
- config:get_boolean("httpd", "enable", false).
-
https_enabled() ->
% 1. [ssl] enable = true | false
% 2. if [daemons] httpsd == {chttpd, start_link, [https]} -> pretend true as well
diff --git a/src/couch/test/eunit/chttpd_endpoints_tests.erl b/src/couch/test/eunit/chttpd_endpoints_tests.erl
index 3c8586a14..f164ae684 100644
--- a/src/couch/test/eunit/chttpd_endpoints_tests.erl
+++ b/src/couch/test/eunit/chttpd_endpoints_tests.erl
@@ -47,10 +47,10 @@ url_handlers() ->
{<<"_replicate">>, chttpd_misc, handle_replicate_req},
{<<"_uuids">>, chttpd_misc, handle_uuids_req},
{<<"_session">>, chttpd_auth, handle_session_req},
- {<<"_up">>, chttpd_misc, handle_up_req},
- {<<"_membership">>, mem3_httpd, handle_membership_req},
- {<<"_db_updates">>, global_changes_httpd, handle_global_changes_req},
- {<<"_cluster_setup">>, setup_httpd, handle_setup_req}
+ {<<"_membership">>, chttpd_httpd_handlers, not_supported},
+ {<<"_db_updates">>, chttpd_httpd_handlers, not_implemented},
+ {<<"_cluster_setup">>, chttpd_httpd_handlers, not_implemented},
+ {<<"_up">>, chttpd_misc, handle_up_req}
],
lists:foreach(fun({Path, Mod, Fun}) ->
@@ -67,9 +67,9 @@ db_handlers() ->
{<<"_view_cleanup">>, chttpd_db, handle_view_cleanup_req},
{<<"_compact">>, chttpd_db, handle_compact_req},
{<<"_design">>, chttpd_db, handle_design_req},
- {<<"_temp_view">>, chttpd_view, handle_temp_view_req},
+ {<<"_temp_view">>, chttpd_httpd_handlers, not_supported},
{<<"_changes">>, chttpd_db, handle_changes_req},
- {<<"_shards">>, mem3_httpd, handle_shards_req},
+ {<<"_shards">>, chttpd_httpd_handlers, not_supported},
{<<"_index">>, mango_httpd, handle_req},
{<<"_explain">>, mango_httpd, handle_req},
{<<"_find">>, mango_httpd, handle_req}
@@ -87,11 +87,11 @@ db_handlers() ->
design_handlers() ->
Handlers = [
{<<"_view">>, chttpd_view, handle_view_req},
- {<<"_show">>, chttpd_show, handle_doc_show_req},
- {<<"_list">>, chttpd_show, handle_view_list_req},
+ {<<"_show">>, chttpd_httpd_handlers, not_supported},
+ {<<"_list">>, chttpd_httpd_handlers, not_supported},
{<<"_update">>, chttpd_show, handle_doc_update_req},
{<<"_info">>, chttpd_db, handle_design_info_req},
- {<<"_rewrite">>, chttpd_rewrite, handle_rewrite_req}
+ {<<"_rewrite">>, chttpd_httpd_handlers, not_supported}
],
lists:foreach(fun({Path, Mod, Fun}) ->
diff --git a/src/couch_replicator/src/couch_replicator_ids.erl b/src/couch_replicator/src/couch_replicator_ids.erl
index d1cbe571c..44b9e47e6 100644
--- a/src/couch_replicator/src/couch_replicator_ids.erl
+++ b/src/couch_replicator/src/couch_replicator_ids.erl
@@ -58,7 +58,7 @@ base_id(#{?SOURCE := Src0, ?TARGET := Tgt0} = Rep, 3) ->
base_id(#{?SOURCE := Src0, ?TARGET := Tgt0} = Rep, 2) ->
{ok, HostName} = inet:gethostname(),
- Port = case (catch mochiweb_socket_server:get(couch_httpd, port)) of
+ Port = case (catch mochiweb_socket_server:get(chttpd, port)) of
P when is_number(P) ->
P;
_ ->