summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2019-11-21 16:54:44 -0600
committerPaul J. Davis <paul.joseph.davis@gmail.com>2019-11-22 09:39:14 -0600
commitbe22ef9decd9b4f9a6f1704d274f7f67aaed9686 (patch)
tree3d3e799a0094cc6bd453cb71f0ad88bb2144fa48
parent5e47f501c1b756e56a1b57b852e0c1715cf16e1a (diff)
downloadcouchdb-be22ef9decd9b4f9a6f1704d274f7f67aaed9686.tar.gz
Add operation names for all HTTP endpoints
This adds operation names to all valid HTTP end points. This covers all of `make elixir` except for seven requests that are testing specific error conditions in URL and Methods for various endpoints.
-rw-r--r--src/chttpd/src/chttpd.erl6
-rw-r--r--src/chttpd/src/chttpd_handlers.erl18
-rw-r--r--src/chttpd/src/chttpd_httpd_handlers.erl454
-rw-r--r--src/global_changes/src/global_changes_httpd_handlers.erl8
-rw-r--r--src/mango/src/mango_httpd_handlers.erl31
-rw-r--r--src/mem3/src/mem3_httpd_handlers.erl38
-rw-r--r--src/setup/src/setup_httpd_handlers.erl12
7 files changed, 540 insertions, 27 deletions
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index 46b3b2411..c4bfa602f 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -1246,12 +1246,16 @@ start_span(Req) ->
path_parts = PathParts
} = Req,
{OperationName, ExtraTags} = get_action(Req),
+ Path = case PathParts of
+ [] -> <<"">>;
+ [_ | _] -> filename:join(PathParts)
+ end,
Tags = maps:merge(#{
peer => Peer,
'http.method' => Method,
nonce => Nonce,
'http.url' => MochiReq:get(raw_path),
- path_parts => PathParts,
+ path_parts => Path,
'span.kind' => <<"server">>,
component => <<"couchdb.chttpd">>
}, ExtraTags),
diff --git a/src/chttpd/src/chttpd_handlers.erl b/src/chttpd/src/chttpd_handlers.erl
index c07b2097b..17d2952b3 100644
--- a/src/chttpd/src/chttpd_handlers.erl
+++ b/src/chttpd/src/chttpd_handlers.erl
@@ -37,8 +37,24 @@ design_handler(HandlerKey, DefaultFun) ->
select(collect(design_handler, [HandlerKey]), DefaultFun).
handler_info(HttpReq) ->
+ #httpd{
+ method = Method,
+ path_parts = PathParts
+ } = HttpReq,
Default = {'unknown.unknown', #{}},
- select(collect(handler_info, [HttpReq]), Default).
+ try
+ select(collect(handler_info, [Method, PathParts, HttpReq]), Default)
+ catch Type:Reason ->
+ Stack = erlang:get_stacktrace(),
+ couch_log:error("~s :: handler_info failure for ~p : ~p:~p :: ~p", [
+ ?MODULE,
+ get(nonce),
+ Type,
+ Reason,
+ Stack
+ ]),
+ Default
+ end.
%% ------------------------------------------------------------------
%% Internal Function Definitions
diff --git a/src/chttpd/src/chttpd_httpd_handlers.erl b/src/chttpd/src/chttpd_httpd_handlers.erl
index de7f3a01c..7c657f5c6 100644
--- a/src/chttpd/src/chttpd_httpd_handlers.erl
+++ b/src/chttpd/src/chttpd_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(chttpd_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1, handler_info/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
-include_lib("couch/include/couch_db.hrl").
@@ -48,27 +48,439 @@ design_handler(<<"_info">>) -> fun chttpd_db:handle_design_info_req/3;
design_handler(<<"_rewrite">>) -> fun chttpd_rewrite:handle_rewrite_req/3;
design_handler(_) -> no_match.
-%% TODO Populate in another PR
-handler_info(#httpd{path_parts=[<<"_all_dbs">>], method=Method})
- when Method =:= 'HEAD' orelse Method =:= 'GET' ->
- {'all-dbs.read', #{}};
-handler_info(#httpd{path_parts=[<<"_session">>], method=Method})
- when Method =:= 'HEAD' orelse Method =:= 'GET' ->
+handler_info('GET', [], _) ->
+ {'welcome_message.read', #{}};
+
+handler_info('GET', [<<"_active_tasks">>], _) ->
+ {'active_tasks.read', #{}};
+
+handler_info('GET', [<<"_all_dbs">>], _) ->
+ {'all_dbs.read', #{}};
+
+handler_info('POST', [<<"_dbs_info">>], _) ->
+ {'dbs_info.read', #{}};
+
+handler_info('GET', [<<"_node">>, <<"_local">>], _) ->
+ {'node.name.read', #{}};
+
+handler_info(Method, [<<"_node">>, <<"_local">> | Rest], HttpReq) ->
+ handler_info(Method, [<<"_node">>, node() | Rest], HttpReq);
+
+handler_info('GET', [<<"_node">>, Node, <<"_config">>], _) ->
+ {'node.config.all.read', #{node => Node}};
+
+handler_info('GET', [<<"_node">>, Node, <<"_config">>, Section], _) ->
+ {'node.config.section.read', #{node => Node, 'config.section' => Section}};
+
+handler_info('GET', [<<"_node">>, Node, <<"_config">>, Section, Key], _) ->
+ {'node.config.key.read', #{
+ node => Node,
+ 'config.section' => Section,
+ 'config.key' => Key
+ }};
+
+handler_info('PUT', [<<"_node">>, Node, <<"_config">>, Section, Key], _) ->
+ {'node.config.key.write', #{
+ node => Node,
+ 'config.section' => Section,
+ 'config.key' => Key
+ }};
+
+handler_info('DELETE', [<<"_node">>, Node, <<"_config">>, Section, Key], _) ->
+ {'node.config.key.delete', #{
+ node => Node,
+ 'config.section' => Section,
+ 'config.key' => Key
+ }};
+
+handler_info('GET', [<<"_node">>, Node, <<"_stats">> | Path], _) ->
+ {'node.stats.read', #{node => Node, 'stat.path' => Path}};
+
+handler_info('GET', [<<"_node">>, Node, <<"_system">>], _) ->
+ {'node.system.read', #{node => Node}};
+
+handler_info('POST', [<<"_node">>, Node, <<"_restart">>], _) ->
+ {'node.restart.execute', #{node => Node}};
+
+handler_info('POST', [<<"_reload_query_servers">>], _) ->
+ {'query_servers.reload', #{}};
+
+handler_info('POST', [<<"_replicate">>], _) ->
+ {'replication.create', #{}};
+
+handler_info('GET', [<<"_scheduler">>, <<"jobs">>], _) ->
+ {'replication.jobs.read', #{}};
+
+handler_info('GET', [<<"_scheduler">>, <<"jobs">>, JobId], _) ->
+ {'replication.job.read', #{'job.id' => JobId}};
+
+handler_info('GET', [<<"_scheduler">>, <<"docs">>], _) ->
+ {'replication.docs.read', #{'db.name' => <<"_replicator">>}};
+
+handler_info('GET', [<<"_scheduler">>, <<"docs">>, Db], _) ->
+ {'replication.docs.read', #{'db.name' => Db}};
+
+handler_info('GET', [<<"_scheduler">>, <<"docs">>, Db, DocId], _) ->
+ {'replication.doc.read', #{'db.name' => Db, 'doc.id' => DocId}};
+
+handler_info('GET', [<<"_scheduler">>, <<"docs">> | Path], _) ->
+ case lists:splitwith(fun(Elem) -> Elem /= <<"_replicator">> end, Path) of
+ {_, [<<"_replicator">>]} ->
+ {'replication.docs.read', #{
+ 'db.name' => filename:join(Path)
+ }};
+ {DbParts, [<<"_replicator">>, DocId]} ->
+ {'replication.doc.read', #{
+ 'db.name' => filename:join(DbParts ++ [<<"_replicator">>]),
+ 'doc.id' => DocId
+ }};
+ _ ->
+ no_match
+ end;
+
+handler_info('GET', [<<"_session">>], _) ->
{'session.read', #{}};
-handler_info(#httpd{path_parts=[<<"_session">>], method='POST'}) ->
- {'session.write', #{}};
-handler_info(#httpd{path_parts=[<<"_session">>], method='DELETE'}) ->
+
+handler_info('POST', [<<"_session">>], _) ->
+ {'session.create', #{}};
+
+handler_info('DELETE', [<<"_session">>], _) ->
{'session.delete', #{}};
-handler_info(#httpd{path_parts=[_Db], method=Method})
- when Method =:= 'HEAD' orelse Method =:= 'GET' ->
- {'database-info.read', #{}};
-handler_info(#httpd{path_parts=[_Db], method='POST'}) ->
- {'document.write', #{}};
-handler_info(#httpd{path_parts=[_Db], method='PUT'}) ->
- {'database.create', #{}};
-handler_info(#httpd{path_parts=[_Db], method='DELETE'}) ->
- {'database.delete', #{}};
-
-handler_info(_) -> no_match.
+handler_info('GET', [<<"_up">>], _) ->
+ {'health.read', #{}};
+
+handler_info('GET', [<<"_utils">> | Path], _) ->
+ {'utils.read', #{'file.path' => filename:join(Path)}};
+
+handler_info('GET', [<<"_uuids">>], _) ->
+ {'uuids.read', #{}};
+
+handler_info('GET', [<<"favicon.ico">>], _) ->
+ {'favicon.ico.read', #{}};
+
+
+handler_info(Method, [<<"_", _/binary>> = Part| Rest], Req) ->
+ % Maybe bail here so that we don't trample over a
+ % different url_handler plugin. However, we continue
+ % on for known system databases.
+ DbName = case Part of
+ <<"_dbs">> -> '_dbs';
+ <<"_global_changes">> -> '_global_changes';
+ <<"_metadata">> -> '_metadata';
+ <<"_nodes">> -> '_nodes';
+ <<"_replicator">> -> '_replicator';
+ <<"_users">> -> '_users';
+ _ -> no_match
+ end,
+ if DbName == no_match -> no_match; true ->
+ handler_info(Method, [DbName | Rest], Req)
+ end;
+
+handler_info('GET', [Db], _) ->
+ {'db.info.read', #{'db.name' => Db}};
+
+handler_info('PUT', [Db], _) ->
+ {'db.create', #{'db.name' => Db}};
+
+handler_info('POST', [Db], _) ->
+ {'db.doc.write', #{'db.name' => Db}};
+
+handler_info('DELETE', [Db], _) ->
+ {'db.delete', #{'db.name' => Db}};
+
+handler_info(M, [Db, <<"_all_docs">>], _) when M == 'GET'; M == 'POST' ->
+ {'db.all_docs.read', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_all_docs">>, <<"queries">>], _) ->
+ {'db.all_docs.read', #{'db.name' => Db, multi => true}};
+
+handler_info('POST', [Db, <<"_bulk_docs">>], _) ->
+ {'db.docs.write', #{'db.name' => Db, bulk => true}};
+
+handler_info('POST', [Db, <<"_bulk_get">>], _) ->
+ {'db.docs.read', #{'db.name' => Db, bulk => true}};
+
+handler_info('GET', [Db, <<"_changes">>], _) ->
+ {'db.changes.read', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_changes">>], _) ->
+ {'db.changes.read', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_compact">>], _) ->
+ {'db.compact.execute', #{'db.name' => Db}};
+
+handler_info('GET', [Db, <<"_design">>, Name], _) ->
+ {'db.design.doc.read', #{'db.name' => Db, 'design.id' => Name}};
+
+handler_info('POST', [Db, <<"_design">>, Name], _) ->
+ {'db.design.doc.write', #{'db.name' => Db, 'design.id' => Name}};
+
+handler_info('PUT', [Db, <<"_design">>, Name], _) ->
+ {'db.design.doc.write', #{'db.name' => Db, 'design.id' => Name}};
+
+handler_info('COPY', [Db, <<"_design">>, Name], Req) ->
+ {'db.design.doc.write', #{
+ 'db.name' => Db,
+ 'design.id' => get_copy_destination(Req),
+ 'copy.source.doc.id' => <<"_design/", Name/binary>>
+ }};
+
+handler_info('DELETE', [Db, <<"_design">>, Name], _) ->
+ {'db.design.doc.delete', #{'db.name' => Db, 'design.id' => Name}};
+
+handler_info('GET', [Db, <<"_design">>, Name, <<"_info">>], _) ->
+ {'db.design.info.read', #{'db.name' => Db, 'design.id' => Name}};
+
+handler_info(M, [Db, <<"_design">>, Name, <<"_list">>, List, View], _)
+ when M == 'GET'; M == 'POST', M == 'OPTIONS' ->
+ {'db.design.list.read', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'design.list.name' => List,
+ 'design.view.name' => View
+ }};
+
+handler_info(M, [Db, <<"_design">>, Name, <<"_list">>, List, Design, View], _)
+ when M == 'GET'; M == 'POST', M == 'OPTIONS' ->
+ {'db.design.list.read', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'design.list.name' => List,
+ 'design.view.source.id' => Design,
+ 'design.view.name' => View
+ }};
+
+handler_info(_, [Db, <<"_design">>, Name, <<"_rewrite">> | Path], _) ->
+ {'db.design.rewrite.execute', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'rewrite.path' => filename:join(Path)
+ }};
+
+handler_info(_, [Db, <<"_design">>, Name, <<"_show">>, Show, DocId], _) ->
+ {'db.design.show.execute', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'design.show.name' => Show,
+ 'design.show.doc.id' => DocId
+ }};
+
+handler_info(_, [Db, <<"_design">>, Name, <<"_update">>, Update | Rest], _) ->
+ BaseTags = #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'design.update.name' => Update
+ },
+ Tags = case Rest of
+ [] ->
+ BaseTags;
+ _ ->
+ DocId = filename:join(Rest),
+ maps:put('design.update.doc.id', DocId, BaseTags)
+ end,
+ {'db.design.update.execute', Tags};
+
+handler_info('POST', [Db, <<"_design">>, Name, <<"_view">>, View, <<"queries">>], _) ->
+ {'db.design.view.multi.read', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'design.view.name' => View
+ }};
+
+handler_info(M, [Db, <<"_design">>, Name, <<"_view">>, View], _)
+ when M == 'GET'; M == 'POST' ->
+ {'db.design.view.read', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'design.view.name' => View
+ }};
+
+handler_info(_, [_Db, <<"_design">>, _Name, <<"_", _/binary>> | _], _) ->
+ % Bail here so that we don't treat a plugin
+ % design handler in place of a design attachment
+ no_match;
+
+handler_info('GET', [Db, <<"_design">>, Name | Path], _) ->
+ {'db.design.doc.attachment.read', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'attachment.name' => filename:join(Path)
+ }};
+
+handler_info('PUT', [Db, <<"_design">>, Name | Path], _) ->
+ {'db.design.doc.attachment.write', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'attachment.name' => filename:join(Path)
+ }};
+
+handler_info('DELETE', [Db, <<"_design">>, Name | Path], _) ->
+ {'db.design.doc.attachment.delete', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'attachment.name' => filename:join(Path)
+ }};
+
+handler_info(_, [Db, <<"_design/", Name/binary>> | Rest], Req) ->
+ % Recurse if someone sent us `_design%2Fname`
+ chttpd_handlers:handler_info(Req#httpd{
+ path_parts = [Db, <<"_design">>, Name | Rest]
+ });
+
+handler_info(M, [Db, <<"_design_docs">>], _) when M == 'GET'; M == 'POST' ->
+ {'db.design_docs.read', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_design_docs">>, <<"queries">>], _) ->
+ {'db.design_docs.read', #{'db.name' => Db, multi => true}};
+
+handler_info('POST', [Db, <<"_ensure_full_commit">>], _) ->
+ {'db.ensure_full_commit.execute', #{'db.name' => Db}};
+
+handler_info('GET', [Db, <<"_local">>, Name], _) ->
+ {'db.local.doc.read', #{'db.name' => Db, 'local.id' => Name}};
+
+handler_info('POST', [Db, <<"_local">>, Name], _) ->
+ {'db.local.doc.write', #{'db.name' => Db, 'local.id' => Name}};
+
+handler_info('PUT', [Db, <<"_local">>, Name], _) ->
+ {'db.local.doc.write', #{'db.name' => Db, 'local.id' => Name}};
+
+handler_info('COPY', [Db, <<"_local">>, Name], Req) ->
+ {'db.local.doc.write', #{
+ 'db.name' => Db,
+ 'local.id' => get_copy_destination(Req),
+ 'copy.source.doc.id' => <<"_local/", Name/binary>>
+ }};
+
+handler_info('DELETE', [Db, <<"_local">>, Name], _) ->
+ {'db.local.doc.delete', #{'db.name' => Db, 'local.id' => Name}};
+
+handler_info(_, [Db, <<"_local">>, Name | _Path], _) ->
+ {'db.local.doc.invalid_attachment_req', #{
+ 'db.name' => Db,
+ 'local.id' => Name
+ }};
+
+handler_info(M, [Db, <<"_local_docs">>], _) when M == 'GET'; M == 'POST' ->
+ {'db.local_docs.read', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_local_docs">>, <<"queries">>], _) ->
+ {'db.local_docs.read', #{'db.name' => Db, multi => true}};
+
+handler_info('POST', [Db, <<"_missing_revs">>], _) ->
+ {'db.docs.missing_revs.execute', #{'db.name' => Db}};
+
+handler_info('GET', [Db, <<"_partition">>, Partition], _) ->
+ {'db.partition.info.read', #{'db.name' => Db, partition => Partition}};
+
+handler_info(_, [Db, <<"_partition">>, Partition | Rest], Req) ->
+ NewPath = case Rest of
+ [<<"_all_docs">> | _] ->
+ [Db | Rest];
+ [<<"_index">> | _] ->
+ [Db | Rest];
+ [<<"_find">> | _] ->
+ [Db | Rest];
+ [<<"_explain">> | _] ->
+ [Db | Rest];
+ [<<"_design">>, _Name, <<"_", _/binary>> | _] ->
+ [Db | Rest];
+ _ ->
+ no_match
+ end,
+ if NewPath == no_match -> no_match; true ->
+ {OpName, Tags} = chttpd_handlers:handler_info(Req#httpd{
+ path_parts = NewPath
+ }),
+ NewOpName = case atom_to_list(OpName) of
+ "db." ++ Name -> list_to_atom("db.partition." ++ Name);
+ Else -> list_to_atom(Else ++ ".partition")
+ end,
+ {NewOpName, maps:put(partition, Partition, Tags)}
+ end;
+
+handler_info('POST', [Db, <<"_purge">>], _) ->
+ {'db.docs.purge', #{'db.name' => Db}};
+
+handler_info('GET', [Db, <<"_purged_infos_limit">>], _) ->
+ {'db.purged_infos_limit.read', #{'db.name' => Db}};
+
+handler_info('PUT', [Db, <<"_purged_infos_limit">>], _) ->
+ {'db.purged_infos_limit.write', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_revs_diff">>], _) ->
+ {'db.docs.revs_diff.execute', #{'db.name' => Db}};
+
+handler_info('GET', [Db, <<"_revs_limit">>], _) ->
+ {'db.revs_limit.read', #{'db.name' => Db}};
+
+handler_info('PUT', [Db, <<"_revs_limit">>], _) ->
+ {'db.revs_limit.write', #{'db.name' => Db}};
+
+handler_info('GET', [Db, <<"_security">>], _) ->
+ {'db.security.read', #{'db.name' => Db}};
+
+handler_info('PUT', [Db, <<"_security">>], _) ->
+ {'db.security.write', #{'db.name' => Db}};
+
+handler_info(_, [Db, <<"_view_cleanup">>], _) ->
+ {'views.cleanup.execute', #{'db.name' => Db}};
+
+handler_info(_, [_Db, <<"_", _/binary>> | _], _) ->
+ % Bail here for other possible db_handleres
+ no_match;
+
+handler_info('GET', [Db, DocId], _) ->
+ {'db.doc.read', #{'db.name' => Db, 'doc.id' => DocId}};
+
+handler_info('POST', [Db, DocId], _) ->
+ {'db.doc.write', #{'db.name' => Db, 'design.id' => DocId}};
+
+handler_info('PUT', [Db, DocId], _) ->
+ {'db.doc.write', #{'db.name' => Db, 'design.id' => DocId}};
+
+handler_info('COPY', [Db, DocId], Req) ->
+ {'db.doc.write', #{
+ 'db.name' => Db,
+ 'doc.id' => get_copy_destination(Req),
+ 'copy.source.doc.id' => DocId
+ }};
+
+handler_info('DELETE', [Db, DocId], _) ->
+ {'db.doc.delete', #{'db.name' => Db, 'doc.id' => DocId}};
+
+handler_info('GET', [Db, DocId | Path], _) ->
+ {'db.doc.attachment.read', #{
+ 'db.name' => Db,
+ 'doc.id' => DocId,
+ 'attachment.name' => filename:join(Path)
+ }};
+
+handler_info('PUT', [Db, DocId | Path], _) ->
+ {'db.doc.attachment.write', #{
+ 'db.name' => Db,
+ 'doc.id' => DocId,
+ 'attachment.name' => filename:join(Path)
+ }};
+
+handler_info('DELETE', [Db, DocId | Path], _) ->
+ {'db.doc.attachment.delete', #{
+ 'db.name' => Db,
+ 'doc.id' => DocId,
+ 'attachment.name' => filename:join(Path)
+ }};
+
+handler_info(_, _, _) ->
+ no_match.
+
+
+get_copy_destination(Req) ->
+ try
+ {DocIdStr, _} = couch_httpd_db:parse_copy_destination_header(Req),
+ list_to_binary(mochiweb_util:unquote(DocIdStr))
+ catch _:_ ->
+ unknown
+ end.
+
diff --git a/src/global_changes/src/global_changes_httpd_handlers.erl b/src/global_changes/src/global_changes_httpd_handlers.erl
index b21a64b8f..94a50abc8 100644
--- a/src/global_changes/src/global_changes_httpd_handlers.erl
+++ b/src/global_changes/src/global_changes_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(global_changes_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
url_handler(<<"_db_updates">>) -> fun global_changes_httpd:handle_global_changes_req/1;
url_handler(_) -> no_match.
@@ -20,3 +20,9 @@ url_handler(_) -> no_match.
db_handler(_) -> no_match.
design_handler(_) -> no_match.
+
+handler_info('GET', [<<"_db_updates">>], _) ->
+ {'db_updates.read', #{}};
+
+handler_info(_, _, _) ->
+ no_match. \ No newline at end of file
diff --git a/src/mango/src/mango_httpd_handlers.erl b/src/mango/src/mango_httpd_handlers.erl
index 80e5e277e..c1ddd6c4e 100644
--- a/src/mango/src/mango_httpd_handlers.erl
+++ b/src/mango/src/mango_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(mango_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
url_handler(_) -> no_match.
@@ -22,3 +22,32 @@ db_handler(<<"_find">>) -> fun mango_httpd:handle_req/2;
db_handler(_) -> no_match.
design_handler(_) -> no_match.
+
+handler_info('GET', [Db, <<"_index">>], _) ->
+ {'db.mango.index.read', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_index">>], _) ->
+ {'db.mango.index.create', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_index">>, <<"_bulk_delete">>], _) ->
+ {'db.mango.index.delete', #{'db.name' => Db, multi => true}};
+
+handler_info('DELETE', [Db, <<"_index">>, <<"_design">>, Name, Type, Idx], _) ->
+ {'db.mango.index.delete', #{
+ 'db.name' => Db,
+ 'design.id' => Name,
+ 'index.type' => Type,
+ 'index.name' => Idx
+ }};
+
+handler_info(M, [Db, <<"_index">>, <<"_design/", N/binary>>, T, I], R) ->
+ handler_info(M, [Db, <<"_index">>, <<"_design">>, N, T, I], R);
+
+handler_info('POST', [Db, <<"_explain">>], _) ->
+ {'db.mango.explain.execute', #{'db.name' => Db}};
+
+handler_info('POST', [Db, <<"_find">>], _) ->
+ {'db.mango.find.execute', #{'db.name' => Db}};
+
+handler_info(_, _, _) ->
+ no_match. \ No newline at end of file
diff --git a/src/mem3/src/mem3_httpd_handlers.erl b/src/mem3/src/mem3_httpd_handlers.erl
index 7dd6ab052..eeec1edf3 100644
--- a/src/mem3/src/mem3_httpd_handlers.erl
+++ b/src/mem3/src/mem3_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(mem3_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
url_handler(<<"_membership">>) -> fun mem3_httpd:handle_membership_req/1;
url_handler(<<"_reshard">>) -> fun mem3_reshard_httpd:handle_reshard_req/1;
@@ -23,3 +23,39 @@ db_handler(<<"_sync_shards">>) -> fun mem3_httpd:handle_sync_req/2;
db_handler(_) -> no_match.
design_handler(_) -> no_match.
+
+handler_info('GET', [<<"_membership">>], _) ->
+ {'cluster.membership.read', #{}};
+
+handler_info('GET', [<<"_reshard">>], _) ->
+ {'reshard.summary.read', #{}};
+
+handler_info('GET', [<<"_reshard">>, <<"state">>], _) ->
+ {'reshard.state.read', #{}};
+
+handler_info('PUT', [<<"_reshard">>, <<"state">>], _) ->
+ {'reshard.state.write', #{}};
+
+handler_info('GET', [<<"_reshard">>, <<"jobs">>], _) ->
+ {'reshard.jobs.read', #{}};
+
+handler_info('POST', [<<"_reshard">>, <<"jobs">>], _) ->
+ {'reshard.jobs.create', #{}};
+
+handler_info('GET', [<<"_reshard">>, <<"jobs">>, JobId], _) ->
+ {'reshard.job.read', #{'job.id' => JobId}};
+
+handler_info('DELETE', [<<"_reshard">>, <<"jobs">>, JobId], _) ->
+ {'reshard.job.delete', #{'job.id' => JobId}};
+
+handler_info('GET', [DbName, <<"_shards">>], _) ->
+ {'db.shards.read', #{'db.name' => DbName}};
+
+handler_info('GET', [DbName, <<"_shards">>, DocId], _) ->
+ {'db.shards.read', #{'db.name' => DbName, 'doc.id' => DocId}};
+
+handler_info('POST', [DbName, <<"_sync_shards">>], _) ->
+ {'db.shards.sync', #{'db.name' => DbName}};
+
+handler_info(_, _, _) ->
+ no_match.
diff --git a/src/setup/src/setup_httpd_handlers.erl b/src/setup/src/setup_httpd_handlers.erl
index 994c217e8..e26fbc3c4 100644
--- a/src/setup/src/setup_httpd_handlers.erl
+++ b/src/setup/src/setup_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(setup_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
url_handler(<<"_cluster_setup">>) -> fun setup_httpd:handle_setup_req/1;
url_handler(_) -> no_match.
@@ -20,3 +20,13 @@ url_handler(_) -> no_match.
db_handler(_) -> no_match.
design_handler(_) -> no_match.
+
+
+handler_info('GET', [<<"_cluster_setup">>], _) ->
+ {'cluster_setup.read', #{}};
+
+handler_info('POST', [<<"_cluster_setup">>], _) ->
+ {'cluster_setup.write', #{}};
+
+handler_info(_, _, _) ->
+ no_match. \ No newline at end of file