diff options
author | Jan Lehnardt <jan@apache.org> | 2022-06-24 15:24:22 +0200 |
---|---|---|
committer | Jan Lehnardt <jan@apache.org> | 2022-12-16 16:56:18 +0100 |
commit | 9bc4dda0e48aa42977b9362ba3828737f26ba827 (patch) | |
tree | e88e8a70a3e92752779afce21355de0db02881cd | |
parent | 23a2d85e58563783762c464c23ab61c49d7e7459 (diff) | |
download | couchdb-9bc4dda0e48aa42977b9362ba3828737f26ba827.tar.gz |
feat(access): add access handling to chttpd
-rw-r--r-- | src/chttpd/src/chttpd.erl | 2 | ||||
-rw-r--r-- | src/chttpd/src/chttpd_db.erl | 21 | ||||
-rw-r--r-- | src/chttpd/src/chttpd_view.erl | 15 |
3 files changed, 33 insertions, 5 deletions
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl index c25c18838..3c9ddd138 100644 --- a/src/chttpd/src/chttpd.erl +++ b/src/chttpd/src/chttpd.erl @@ -1031,6 +1031,8 @@ error_info({bad_request, Error, Reason}) -> {400, couch_util:to_binary(Error), couch_util:to_binary(Reason)}; error_info({query_parse_error, Reason}) -> {400, <<"query_parse_error">>, Reason}; +error_info(access) -> + {403, <<"forbidden">>, <<"access">>}; error_info(database_does_not_exist) -> {404, <<"not_found">>, <<"Database does not exist.">>}; error_info(not_found) -> diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl index 748b356fd..46fdb444a 100644 --- a/src/chttpd/src/chttpd_db.erl +++ b/src/chttpd/src/chttpd_db.erl @@ -955,16 +955,18 @@ view_cb(Msg, Acc) -> couch_mrview_http:view_cb(Msg, Acc). db_doc_req(#httpd{method = 'DELETE'} = Req, Db, DocId) -> - % check for the existence of the doc to handle the 404 case. - couch_doc_open(Db, DocId, nil, []), - case chttpd:qs_value(Req, "rev") of + % fetch the old doc revision, so we can compare access control + % in send_update_doc() later. + Doc0 = couch_doc_open(Db, DocId, nil, [{user_ctx, Req#httpd.user_ctx}]), + Revs = chttpd:qs_value(Req, "rev"), + case Revs of undefined -> Body = {[{<<"_deleted">>, true}]}; Rev -> Body = {[{<<"_rev">>, ?l2b(Rev)}, {<<"_deleted">>, true}]} end, - Doc = couch_doc_from_req(Req, Db, DocId, Body), - send_updated_doc(Req, Db, DocId, Doc); + Doc = Doc0#doc{revs=Revs,body=Body,deleted=true}, + send_updated_doc(Req, Db, DocId, couch_doc_from_req(Req, Db, DocId, Doc)); db_doc_req(#httpd{method = 'GET', mochi_req = MochiReq} = Req, Db, DocId) -> #doc_query_args{ rev = Rev0, @@ -1414,6 +1416,8 @@ receive_request_data(Req, LenLeft) when LenLeft > 0 -> receive_request_data(_Req, _) -> throw(<<"expected more data">>). +update_doc_result_to_json({#doc{id=Id,revs=Rev}, access}) -> + update_doc_result_to_json({{Id, Rev}, access}); update_doc_result_to_json({error, _} = Error) -> {_Code, Err, Msg} = chttpd:error_info(Error), {[ @@ -1968,6 +1972,7 @@ parse_shards_opt(Req) -> [ {n, parse_shards_opt("n", Req, config:get_integer("cluster", "n", 3))}, {q, parse_shards_opt("q", Req, config:get_integer("cluster", "q", 2))}, + {access, parse_shards_opt_access(chttpd:qs_value(Req, "access", false))}, {placement, parse_shards_opt( "placement", Req, config:get("cluster", "placement") @@ -2004,6 +2009,12 @@ parse_shards_opt(Param, Req, Default) -> false -> throw({bad_request, Err}) end. +parse_shards_opt_access(Value) when is_boolean(Value) -> + Value; +parse_shards_opt_access(_Value) -> + Err = ?l2b(["The `access` value should be a boolean."]), + throw({bad_request, Err}). + parse_engine_opt(Req) -> case chttpd:qs_value(Req, "engine") of undefined -> diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl index 1d721d189..f74088dbc 100644 --- a/src/chttpd/src/chttpd_view.erl +++ b/src/chttpd/src/chttpd_view.erl @@ -69,6 +69,21 @@ fabric_query_view(Db, Req, DDoc, ViewName, Args) -> Max = chttpd:chunked_response_buffer_size(), VAcc = #vacc{db = Db, req = Req, threshold = Max}, Options = [{user_ctx, Req#httpd.user_ctx}], +% {ok, Resp} = fabric:query_view(Db, Options, DDoc, ViewName, +% fun view_cb/2, VAcc, Args), +% {ok, Resp#vacc.resp}. +% % TODO: This might just be a debugging leftover, we might be able +% % to undo this by just returning {ok, Resp#vacc.resp} +% % However, this *might* be here because we need to handle +% % errors here now, because access might tell us to. +% case fabric:query_view(Db, Options, DDoc, ViewName, +% fun view_cb/2, VAcc, Args) of +% {ok, Resp} -> +% {ok, Resp#vacc.resp}; +% {error, Error} -> +% throw(Error) +% end. + {ok, Resp} = fabric:query_view( Db, Options, |