Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 6 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Commits on Mar 05, 2012
Robert Newson Add ejje for bigcouch+ b85026c
Commits on May 02, 2012
Robert Newson Include line number in json_stack if possible
In R15 onwards, stack trace elements changed from;

{Module, Function, Arguments}
to;
{Module, Function, Arguments, Location}

where Location is a proplists with file and line items.

This patch includes the value of line if present and fixes the
fall-through to "Bad entry in stacktrace" for everything else.

BugzID: 13471
7d3055e
Commits on Jun 19, 2012
Robert Newson Add search 2.0 endpoints 859c23c
Commits on Aug 02, 2012
Robert Newson Support the keys parameter in GET requests. dba3edd
Robert Newson Send attachment encoding information
BugzID: 13778
252b023
Robert Newson Support X-HTTP-Method-Override for POST requests
BugzID: 13399
61a2597
View
57 src/chttpd.erl
@@ -16,7 +16,7 @@
-export([start_link/0, start_link/1, start_link/2,
stop/0, handle_request/1, config_change/2,
primary_header_value/2, header_value/2, header_value/3, qs_value/2,
- qs_value/3, qs/1, path/1, absolute_uri/2, body_length/1,
+ qs_value/3, qs/1, qs_json_value/3, path/1, absolute_uri/2, body_length/1,
verify_is_server_admin/1, unquote/1, quote/1, recv/2, recv_chunked/4,
error_info/1, parse_form/1, json_body/1, json_body_obj/1, body/1,
doc_etag/1, make_etag/1, etag_respond/3, partition/1, serve_file/3,
@@ -172,8 +172,25 @@ handle_request(MochiReq) ->
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 ->
+ ?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 Method1 of
+ Method = case Method2 of
'HEAD' -> 'GET';
Other -> Other
end,
@@ -339,7 +356,8 @@ db_url_handlers() ->
{<<"_design">>, fun chttpd_db:handle_design_req/2},
{<<"_temp_view">>, fun chttpd_view:handle_temp_view_req/2},
{<<"_changes">>, fun chttpd_db:handle_changes_req/2},
- {<<"_search">>, fun chttpd_external:handle_search_req/2}
+ {<<"_search">>, fun ejje_httpd:handle_search_req/2},
+ {<<"_search_cleanup">>, fun dreyfus_httpd:handle_cleanup_req/2}
].
design_url_handlers() ->
@@ -349,7 +367,9 @@ design_url_handlers() ->
{<<"_list">>, fun chttpd_show:handle_view_list_req/3},
{<<"_update">>, fun chttpd_show:handle_doc_update_req/3},
{<<"_info">>, fun chttpd_db:handle_design_info_req/3},
- {<<"_rewrite">>, fun chttpd_rewrite:handle_rewrite_req/3}
+ {<<"_rewrite">>, fun chttpd_rewrite:handle_rewrite_req/3},
+ {<<"_search">>, fun dreyfus_httpd:handle_search_req/3},
+ {<<"_search_info">>, fun dreyfus_httpd:handle_info_req/3}
].
% Utilities
@@ -379,6 +399,14 @@ qs_value(Req, Key) ->
qs_value(Req, Key, Default) ->
couch_util:get_value(Key, qs(Req), Default).
+qs_json_value(Req, Key, Default) ->
+ case qs_value(Req, Key, Default) of
+ Default ->
+ Default;
+ Result ->
+ ?JSON_DECODE(Result)
+ end.
+
qs(#httpd{mochi_req=MochiReq}) ->
MochiReq:parse_qs().
@@ -772,11 +800,20 @@ reqid() ->
{"X-Couch-Request-ID", get(nonce)}.
json_stack({_Error, _Reason, Stack}) ->
- lists:map(fun({M,F,A0}) ->
- A = if is_integer(A0) -> A0; is_list(A0) -> length(A0); true -> 0 end,
- list_to_binary(io_lib:format("~s:~s/~B", [M,F,A]));
- (_) ->
- <<"bad entry in stacktrace">>
- end, Stack);
+ lists:map(fun json_stack_item/1, Stack);
json_stack(_) ->
[].
+
+json_stack_item({M,F,A}) ->
+ list_to_binary(io_lib:format("~s:~s/~B", [M, F, json_stack_arity(A)]));
+json_stack_item({M,F,A,L}) ->
+ case proplists:get_value(line, L) of
+ undefined -> json_stack_item({M,F,A});
+ Line -> list_to_binary(io_lib:format("~s:~s/~B L~B",
+ [M, F, json_stack_arity(A), Line]))
+ end;
+json_stack_item(_) ->
+ <<"bad entry in stacktrace">>.
+
+json_stack_arity(A) ->
+ if is_integer(A) -> A; is_list(A) -> length(A); true -> 0 end.
View
11 src/chttpd_db.erl
@@ -355,7 +355,14 @@ db_req(#httpd{path_parts=[_,<<"_purge">>]}=Req, _Db) ->
send_method_not_allowed(Req, "POST");
db_req(#httpd{method='GET',path_parts=[_,<<"_all_docs">>]}=Req, Db) ->
- all_docs_view(Req, Db, nil);
+ case chttpd:qs_json_value(Req, "keys", nil) of
+ Keys when is_list(Keys) ->
+ all_docs_view(Req, Db, Keys);
+ nil ->
+ all_docs_view(Req, Db, nil);
+ _ ->
+ throw({bad_request, "`keys` parameter must be an array."})
+ end;
db_req(#httpd{method='POST',path_parts=[_,<<"_all_docs">>]}=Req, Db) ->
{Fields} = chttpd:json_body_obj(Req),
@@ -697,7 +704,7 @@ send_doc_efficiently(Req, #doc{atts=Atts}=Doc, Headers, Options) ->
true ->
Boundary = couch_uuids:random(),
JsonBytes = ?JSON_ENCODE(couch_doc:to_json_obj(Doc,
- [attachments, follows|Options])),
+ [attachments, follows, att_encoding_info | Options])),
{ContentType, Len} = couch_doc:len_doc_to_multi_part_stream(
Boundary,JsonBytes, Atts, true),
CType = {<<"Content-Type">>, ContentType},
View
6 src/chttpd_show.erl
@@ -148,12 +148,14 @@ send_doc_update_response(Req, Db, DDoc, UpdateName, Doc, DocId) ->
% view-list request with view and list from same design doc.
handle_view_list_req(#httpd{method='GET',
path_parts=[_, _, DesignName, _, ListName, ViewName]}=Req, Db, DDoc) ->
- handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, nil);
+ Keys = chttpd:qs_json_value(Req, "keys", nil),
+ 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='GET',
path_parts=[_, _, _, _, ListName, DesignName, ViewName]}=Req, Db, DDoc) ->
- handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, nil);
+ Keys = chttpd:qs_json_value(Req, "keys", nil),
+ handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, Keys);
handle_view_list_req(#httpd{method='GET'}=Req, _Db, _DDoc) ->
chttpd:send_error(Req, 404, <<"list_error">>, <<"Invalid path.">>);
View
3  src/chttpd_view.erl
@@ -101,7 +101,8 @@ extract_view_type(ViewName, [View|Rest], IsReduce) ->
handle_view_req(#httpd{method='GET',
path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) ->
- design_doc_view(Req, Db, DDoc, ViewName, nil);
+ Keys = couch_httpd:qs_json_value(Req, "keys", nil),
+ design_doc_view(Req, Db, DDoc, ViewName, Keys);
handle_view_req(#httpd{method='POST',
path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) ->

No commit comments for this range

Something went wrong with that request. Please try again.