Skip to content

Commit 773e5d1

Browse files
committed
add QUERY method support
1 parent c8365b0 commit 773e5d1

6 files changed

Lines changed: 65 additions & 50 deletions

File tree

src/chttpd/src/chttpd_db.erl

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ handle_request(#httpd{path_parts = [DbName | RestParts], method = Method} = Req)
106106
do_db_req(Req, Handler)
107107
end.
108108

109-
handle_changes_req(#httpd{method = 'POST'} = Req, Db) ->
109+
handle_changes_req(#httpd{method = Method} = Req, Db) when ?POST_OR_QUERY(Method) ->
110110
chttpd:validate_ctype(Req, "application/json"),
111111
case chttpd:body_length(Req) of
112112
0 ->
@@ -118,7 +118,7 @@ handle_changes_req(#httpd{method = 'POST'} = Req, Db) ->
118118
handle_changes_req(#httpd{method = 'GET'} = Req, Db) ->
119119
handle_changes_req1(Req, Db);
120120
handle_changes_req(#httpd{path_parts = [_, <<"_changes">>]} = Req, _Db) ->
121-
send_method_not_allowed(Req, "GET,POST,HEAD").
121+
send_method_not_allowed(Req, "GET,POST,QUERY,HEAD").
122122

123123
handle_changes_req1(#httpd{} = Req, Db) ->
124124
#changes_args{filter = Raw, style = Style} = Args0 = parse_changes_query(Req),
@@ -163,7 +163,7 @@ handle_changes_req1(#httpd{} = Req, Db) ->
163163

164164
% callbacks for continuous feed (newline-delimited JSON Objects)
165165
changes_callback(start, #cacc{feed = continuous} = Acc) ->
166-
{ok, Resp} = chttpd:start_delayed_json_response(Acc#cacc.mochi, 200),
166+
{ok, Resp} = chttpd:start_delayed_json_response(Acc#cacc.mochi, 200, [?ACCEPT_QUERY]),
167167
{ok, Acc#cacc{mochi = Resp, responding = true}};
168168
changes_callback({change, Change}, #cacc{feed = continuous} = Acc) ->
169169
chttpd_stats:incr_rows(),
@@ -185,7 +185,8 @@ changes_callback(start, #cacc{feed = eventsource} = Acc) ->
185185
#cacc{mochi = Req} = Acc,
186186
Headers = [
187187
{"Content-Type", "text/event-stream"},
188-
{"Cache-Control", "no-cache"}
188+
{"Cache-Control", "no-cache"},
189+
?ACCEPT_QUERY
189190
],
190191
{ok, Resp} = chttpd:start_delayed_json_response(Req, 200, Headers),
191192
{ok, Acc#cacc{mochi = Resp, responding = true}};
@@ -218,14 +219,14 @@ changes_callback(start, #cacc{feed = normal} = Acc) ->
218219
{ok, Resp} = chttpd:start_delayed_json_response(
219220
Req,
220221
200,
221-
[{"ETag", Etag}],
222+
[{"ETag", Etag}, ?ACCEPT_QUERY],
222223
FirstChunk
223224
),
224225
{ok, Acc#cacc{mochi = Resp, responding = true}};
225226
changes_callback(start, Acc) ->
226227
#cacc{mochi = Req} = Acc,
227228
FirstChunk = "{\"results\":[\n",
228-
{ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [], FirstChunk),
229+
{ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [?ACCEPT_QUERY], FirstChunk),
229230
{ok, Acc#cacc{mochi = Resp, responding = true}};
230231
changes_callback({change, Change}, Acc) ->
231232
chttpd_stats:incr_rows(),
@@ -708,7 +709,9 @@ db_req(#httpd{method = 'POST', path_parts = [_, <<"_bulk_docs">>], user_ctx = Ct
708709
end;
709710
db_req(#httpd{path_parts = [_, <<"_bulk_docs">>]} = Req, _Db) ->
710711
send_method_not_allowed(Req, "POST");
711-
db_req(#httpd{method = 'POST', path_parts = [_, <<"_bulk_get">>]} = Req, Db) ->
712+
db_req(#httpd{method = Method, path_parts = [_, <<"_bulk_get">>]} = Req, Db) when
713+
?POST_OR_QUERY(Method)
714+
->
712715
couch_stats:increment_counter([couchdb, httpd, bulk_requests]),
713716
couch_httpd:validate_ctype(Req, "application/json"),
714717
{JsonProps} = chttpd:json_body_obj(Req),
@@ -726,7 +729,7 @@ db_req(#httpd{method = 'POST', path_parts = [_, <<"_bulk_get">>]} = Req, Db) ->
726729
end
727730
end;
728731
db_req(#httpd{path_parts = [_, <<"_bulk_get">>]} = Req, _Db) ->
729-
send_method_not_allowed(Req, "POST");
732+
send_method_not_allowed(Req, "POST,QUERY");
730733
db_req(#httpd{method = 'POST', path_parts = [_, <<"_purge">>]} = Req, Db) ->
731734
couch_stats:increment_counter([couchdb, httpd, purge_requests]),
732735
chttpd:validate_ctype(Req, "application/json"),
@@ -780,11 +783,11 @@ db_req(#httpd{method = 'GET', path_parts = [_, OP]} = Req, Db) when ?IS_ALL_DOCS
780783
end;
781784
db_req(
782785
#httpd{
783-
method = 'POST',
786+
method = Method,
784787
path_parts = [_, OP, <<"queries">>]
785788
} = Req,
786789
Db
787-
) when ?IS_ALL_DOCS(OP) ->
790+
) when ?IS_ALL_DOCS(OP), ?POST_OR_QUERY(Method) ->
788791
Props = chttpd:json_body_obj(Req),
789792
case couch_mrview_util:get_view_queries(Props) of
790793
undefined ->
@@ -796,8 +799,10 @@ db_req(
796799
#httpd{path_parts = [_, OP, <<"queries">>]} = Req,
797800
_Db
798801
) when ?IS_ALL_DOCS(OP) ->
799-
send_method_not_allowed(Req, "POST");
800-
db_req(#httpd{method = 'POST', path_parts = [_, OP]} = Req, Db) when ?IS_ALL_DOCS(OP) ->
802+
send_method_not_allowed(Req, "POST,QUERY");
803+
db_req(#httpd{method = Method, path_parts = [_, OP]} = Req, Db) when
804+
?IS_ALL_DOCS(OP), ?POST_OR_QUERY(Method)
805+
->
801806
chttpd:validate_ctype(Req, "application/json"),
802807
{Fields} = chttpd:json_body_obj(Req),
803808
case couch_util:get_value(<<"keys">>, Fields, nil) of
@@ -809,8 +814,10 @@ db_req(#httpd{method = 'POST', path_parts = [_, OP]} = Req, Db) when ?IS_ALL_DOC
809814
throw({bad_request, "`keys` body member must be an array."})
810815
end;
811816
db_req(#httpd{path_parts = [_, OP]} = Req, _Db) when ?IS_ALL_DOCS(OP) ->
812-
send_method_not_allowed(Req, "GET,HEAD,POST");
813-
db_req(#httpd{method = 'POST', path_parts = [_, <<"_missing_revs">>]} = Req, Db) ->
817+
send_method_not_allowed(Req, "GET,HEAD,POST,QUERY");
818+
db_req(#httpd{method = Method, path_parts = [_, <<"_missing_revs">>]} = Req, Db) when
819+
?POST_OR_QUERY(Method)
820+
->
814821
chttpd:validate_ctype(Req, "application/json"),
815822
{JsonDocIdRevs} = chttpd:json_body_obj(Req),
816823
case fabric:get_missing_revs(Db, JsonDocIdRevs) of
@@ -829,8 +836,10 @@ db_req(#httpd{method = 'POST', path_parts = [_, <<"_missing_revs">>]} = Req, Db)
829836
)
830837
end;
831838
db_req(#httpd{path_parts = [_, <<"_missing_revs">>]} = Req, _Db) ->
832-
send_method_not_allowed(Req, "POST");
833-
db_req(#httpd{method = 'POST', path_parts = [_, <<"_revs_diff">>]} = Req, Db) ->
839+
send_method_not_allowed(Req, "POST,QUERY");
840+
db_req(#httpd{method = Method, path_parts = [_, <<"_revs_diff">>]} = Req, Db) when
841+
?POST_OR_QUERY(Method)
842+
->
834843
chttpd:validate_ctype(Req, "application/json"),
835844
{JsonDocIdRevs} = chttpd:json_body_obj(Req),
836845
case fabric:get_missing_revs(Db, JsonDocIdRevs) of
@@ -858,7 +867,7 @@ db_req(#httpd{method = 'POST', path_parts = [_, <<"_revs_diff">>]} = Req, Db) ->
858867
send_json(Req, {Results2})
859868
end;
860869
db_req(#httpd{path_parts = [_, <<"_revs_diff">>]} = Req, _Db) ->
861-
send_method_not_allowed(Req, "POST");
870+
send_method_not_allowed(Req, "POST,QUERY");
862871
db_req(
863872
#httpd{method = 'PUT', path_parts = [_, <<"_security">>], user_ctx = Ctx} = Req,
864873
Db
@@ -983,7 +992,7 @@ multi_all_docs_view(Req, Db, OP, Queries) ->
983992
{ok, Resp0} = chttpd:start_delayed_json_response(
984993
VAcc0#vacc.req,
985994
200,
986-
[],
995+
[?ACCEPT_QUERY],
987996
FirstChunk
988997
),
989998
VAcc1 = VAcc0#vacc{resp = Resp0},

src/chttpd/src/chttpd_misc.erl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ all_dbs_info_callback({error, Reason}, #vacc{resp = Resp0} = Acc) ->
174174

175175
handle_dbs_info_req(#httpd{method = 'GET', path_parts = [<<"_dbs_info">>]} = Req) ->
176176
handle_all_dbs_info_req(Req);
177-
handle_dbs_info_req(#httpd{method = 'POST', path_parts = [<<"_dbs_info">>]} = Req) ->
177+
handle_dbs_info_req(#httpd{method = Method, path_parts = [<<"_dbs_info">>]} = Req) when
178+
?POST_OR_QUERY(Method)
179+
->
178180
chttpd:validate_ctype(Req, "application/json"),
179181
Props = chttpd:json_body_obj(Req),
180182
Keys = couch_mrview_util:get_view_keys(Props),
@@ -191,7 +193,7 @@ handle_dbs_info_req(#httpd{method = 'POST', path_parts = [<<"_dbs_info">>]} = Re
191193
true -> ok;
192194
false -> throw({bad_request, too_many_keys})
193195
end,
194-
{ok, Resp} = chttpd:start_json_response(Req, 200),
196+
{ok, Resp} = chttpd:start_json_response(Req, 200, [?ACCEPT_QUERY]),
195197
send_chunk(Resp, "["),
196198
lists:foldl(
197199
fun(DbName, AccSeparator) ->
@@ -212,11 +214,11 @@ handle_dbs_info_req(#httpd{method = 'POST', path_parts = [<<"_dbs_info">>]} = Re
212214
send_chunk(Resp, "]"),
213215
chttpd:end_json_response(Resp);
214216
handle_dbs_info_req(#httpd{method = Method, path_parts = [<<"_dbs_info">> | _]} = Req) when
215-
Method == 'GET'; Method == 'POST'
217+
Method == 'GET'; ?POST_OR_QUERY(Method)
216218
->
217219
chttpd:send_error(Req, not_found);
218220
handle_dbs_info_req(Req) ->
219-
send_method_not_allowed(Req, "GET,HEAD,POST").
221+
send_method_not_allowed(Req, "GET,HEAD,POST,QUERY").
220222

221223
handle_task_status_req(#httpd{method = 'GET'} = Req) ->
222224
ok = chttpd:verify_is_server_admin(Req),

src/couch/include/couch_db.hrl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
-define(term_to_bin(T, O), term_to_binary(T, O ++ [{minor_version, 1}])).
3737
-define(term_size(T), erlang:external_size(T, [{minor_version, 1}])).
3838

39+
-define(POST_OR_QUERY(Method), Method == 'POST'; Method == 'QUERY').
40+
-define(ACCEPT_QUERY, {<<"Accept-Query">>, <<"\"application/json\"">>}).
41+
3942
-define(DEFAULT_ATTACHMENT_CONTENT_TYPE, <<"application/octet-stream">>).
4043

4144
-define(ADMIN_USER, #user_ctx{roles=[<<"_admin">>]}).

src/couch_mrview/src/couch_mrview_http.erl

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,25 @@
4545

4646
handle_all_docs_req(#httpd{method = 'GET'} = Req, Db) ->
4747
all_docs_req(Req, Db, undefined);
48-
handle_all_docs_req(#httpd{method = 'POST'} = Req, Db) ->
48+
handle_all_docs_req(#httpd{method = Method} = Req, Db) when ?POST_OR_QUERY(Method) ->
4949
chttpd:validate_ctype(Req, "application/json"),
5050
Keys = couch_mrview_util:get_view_keys(chttpd:json_body_obj(Req)),
5151
all_docs_req(Req, Db, Keys);
5252
handle_all_docs_req(Req, _Db) ->
53-
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
53+
chttpd:send_method_not_allowed(Req, "GET,POST,QUERY,HEAD").
5454

5555
handle_local_docs_req(#httpd{method = 'GET'} = Req, Db) ->
5656
all_docs_req(Req, Db, undefined, <<"_local">>);
57-
handle_local_docs_req(#httpd{method = 'POST'} = Req, Db) ->
57+
handle_local_docs_req(#httpd{method = Method} = Req, Db) when ?POST_OR_QUERY(Method) ->
5858
chttpd:validate_ctype(Req, "application/json"),
5959
Keys = couch_mrview_util:get_view_keys(chttpd:json_body_obj(Req)),
6060
all_docs_req(Req, Db, Keys, <<"_local">>);
6161
handle_local_docs_req(Req, _Db) ->
62-
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
62+
chttpd:send_method_not_allowed(Req, "GET,POST,QUERY,HEAD").
6363

6464
handle_design_docs_req(#httpd{method = 'GET'} = Req, Db) ->
6565
all_docs_req(Req, Db, undefined, <<"_design">>);
66-
handle_design_docs_req(#httpd{method = 'POST'} = Req, Db) ->
66+
handle_design_docs_req(#httpd{method = Method} = Req, Db) when ?POST_OR_QUERY(Method) ->
6767
chttpd:validate_ctype(Req, "application/json"),
6868
Keys = couch_mrview_util:get_view_keys(chttpd:json_body_obj(Req)),
6969
all_docs_req(Req, Db, Keys, <<"_design">>);
@@ -108,7 +108,7 @@ handle_view_req(#httpd{method = 'GET'} = Req, Db, DDoc) ->
108108
[_, _, _, _, ViewName] = Req#httpd.path_parts,
109109
couch_stats:increment_counter([couchdb, httpd, view_reads]),
110110
design_doc_view(Req, Db, DDoc, ViewName, undefined);
111-
handle_view_req(#httpd{method = 'POST'} = Req, Db, DDoc) ->
111+
handle_view_req(#httpd{method = Method} = Req, Db, DDoc) when ?POST_OR_QUERY(Method) ->
112112
chttpd:validate_ctype(Req, "application/json"),
113113
[_, _, _, _, ViewName] = Req#httpd.path_parts,
114114
Props = chttpd:json_body_obj(Req),
@@ -125,13 +125,13 @@ handle_view_req(#httpd{method = 'POST'} = Req, Db, DDoc) ->
125125
{undefined, undefined} ->
126126
throw({
127127
bad_request,
128-
"POST body must contain `keys` or `queries` field"
128+
"request body must contain `keys` or `queries` field"
129129
});
130130
{_, _} ->
131131
throw({bad_request, "`keys` and `queries` are mutually exclusive"})
132132
end;
133133
handle_view_req(Req, _Db, _DDoc) ->
134-
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
134+
chttpd:send_method_not_allowed(Req, "GET,POST,QUERY,HEAD").
135135

136136
handle_temp_view_req(#httpd{method = 'POST'} = Req, Db) ->
137137
chttpd:validate_ctype(Req, "application/json"),
@@ -346,11 +346,12 @@ view_cb({error, Reason}, #vacc{resp = undefined} = Acc) ->
346346
{ok, Acc#vacc{resp = Resp}};
347347
view_cb(complete, #vacc{resp = undefined} = Acc) ->
348348
% Nothing in view
349-
{ok, Resp} = chttpd:send_json(Acc#vacc.req, 200, {[{rows, []}]}),
349+
Headers = [?ACCEPT_QUERY],
350+
{ok, Resp} = chttpd:send_json(Acc#vacc.req, 200, Headers, {[{rows, []}]}),
350351
{ok, Acc#vacc{resp = Resp}};
351352
view_cb(Msg, #vacc{resp = undefined} = Acc) ->
352353
%% Start response
353-
Headers = [],
354+
Headers = [?ACCEPT_QUERY],
354355
{ok, Resp} = chttpd:start_delayed_json_response(Acc#vacc.req, 200, Headers),
355356
view_cb(Msg, Acc#vacc{resp = Resp, should_close = true});
356357
%% ---------------------------------------------------
@@ -502,7 +503,7 @@ parse_params(Props, Keys, #mrargs{} = Args0, Options) ->
502503
Props
503504
).
504505

505-
parse_body_and_query(#httpd{method = 'POST'} = Req, Keys) ->
506+
parse_body_and_query(#httpd{method = Method} = Req, Keys) when ?POST_OR_QUERY(Method) ->
506507
Props = chttpd:json_body_obj(Req),
507508
parse_body_and_query(Req, Props, Keys);
508509
parse_body_and_query(Req, Keys) ->

src/dreyfus/src/dreyfus_httpd.erl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
-include_lib("couch/include/couch_db.hrl").
2727
-import(chttpd, [
2828
send_method_not_allowed/2,
29-
send_json/2, send_json/3,
29+
send_json/2, send_json/3, send_json/4,
3030
send_error/2
3131
]).
3232

@@ -40,7 +40,7 @@ handle_search_req(
4040
RetryCount,
4141
RetryPause
4242
) when
43-
Method == 'GET'; Method == 'POST'
43+
Method == 'GET'; ?POST_OR_QUERY(Method)
4444
->
4545
verify_search_available(),
4646
DbName = couch_db:name(Db),
@@ -85,7 +85,7 @@ handle_search_req(
8585
_ ->
8686
[{ranges, facets_to_json(Ranges0)}]
8787
end,
88-
send_json(Req, 200, {
88+
send_json(Req, 200, [?ACCEPT_QUERY], {
8989
[
9090
{total_rows, TotalHits},
9191
{bookmark, Bookmark},
@@ -132,7 +132,7 @@ handle_search_req(
132132
couch_stats:update_histogram([dreyfus, httpd, search], RequestTime),
133133
Response;
134134
handle_search_req(#httpd{path_parts = [_, _, _, _, _]} = Req, _Db, _DDoc, _RetryCount, _RetryPause) ->
135-
send_method_not_allowed(Req, "GET,POST");
135+
send_method_not_allowed(Req, "GET,POST,QUERY");
136136
handle_search_req(Req, _Db, _DDoc, _RetryCount, _RetryPause) ->
137137
send_error(Req, {bad_request, "path not recognized"}).
138138

@@ -195,15 +195,15 @@ handle_analyze_req(#httpd{method = 'GET'} = Req) ->
195195
Analyzer = couch_httpd:qs_value(Req, "analyzer"),
196196
Text = couch_httpd:qs_value(Req, "text"),
197197
analyze(Req, Analyzer, Text);
198-
handle_analyze_req(#httpd{method = 'POST'} = Req) ->
198+
handle_analyze_req(#httpd{method = Method} = Req) when ?POST_OR_QUERY(Method) ->
199199
verify_search_available(),
200200
couch_httpd:validate_ctype(Req, "application/json"),
201201
{Fields} = chttpd:json_body_obj(Req),
202202
Analyzer = couch_util:get_value(<<"analyzer">>, Fields),
203203
Text = couch_util:get_value(<<"text">>, Fields),
204204
analyze(Req, Analyzer, Text);
205205
handle_analyze_req(Req) ->
206-
send_method_not_allowed(Req, "GET,POST").
206+
send_method_not_allowed(Req, "GET,POST,QUERY").
207207

208208
analyze(Req, Analyzer, Text) ->
209209
case Analyzer of
@@ -235,7 +235,7 @@ analyze(Req, Analyzer, Text) ->
235235
)
236236
of
237237
{ok, Tokens} ->
238-
send_json(Req, 200, {[{tokens, Tokens}]});
238+
send_json(Req, 200, [?ACCEPT_QUERY], {[{tokens, Tokens}]});
239239
{error, Reason} ->
240240
send_error(Req, Reason)
241241
end.
@@ -246,7 +246,7 @@ parse_index_params(#httpd{method = 'GET'} = Req, Db) ->
246246
chttpd:qs(Req)
247247
),
248248
parse_index_params(IndexParams, Db);
249-
parse_index_params(#httpd{method = 'POST'} = Req, Db) ->
249+
parse_index_params(#httpd{method = Method} = Req, Db) when ?POST_OR_QUERY(Method) ->
250250
{JsonBody} = chttpd:json_body_obj(Req),
251251
QSEntry =
252252
case chttpd:qs_value(Req, "partition") of
@@ -692,7 +692,7 @@ send_grouped_response(Req, {TotalHits, TotalGroupedHits, Groups}, UseNewApi) ->
692692
false ->
693693
[{total_hits, TotalHits}, {total_grouped_hits, TotalGroupedHits}, {groups, Groups}]
694694
end,
695-
send_json(Req, 200, {GroupResponsePairs}).
695+
send_json(Req, 200, [?ACCEPT_QUERY], {GroupResponsePairs}).
696696

697697
handle_error(Req, Db, DDoc, RetryCount, RetryPause, {exit, _} = Err) ->
698698
backoff_and_retry(Req, Db, DDoc, RetryCount, RetryPause, Err);

0 commit comments

Comments
 (0)