summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lehnardt <jan@apache.org>2022-06-24 15:24:22 +0200
committerJan Lehnardt <jan@apache.org>2022-12-16 16:56:18 +0100
commit9bc4dda0e48aa42977b9362ba3828737f26ba827 (patch)
treee88e8a70a3e92752779afce21355de0db02881cd
parent23a2d85e58563783762c464c23ab61c49d7e7459 (diff)
downloadcouchdb-9bc4dda0e48aa42977b9362ba3828737f26ba827.tar.gz
feat(access): add access handling to chttpd
-rw-r--r--src/chttpd/src/chttpd.erl2
-rw-r--r--src/chttpd/src/chttpd_db.erl21
-rw-r--r--src/chttpd/src/chttpd_view.erl15
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,