Merge branch 'COUCHDB-3298-improve-couch-btree-chunkify'
diff --git a/src/couch_doc.erl b/src/couch_doc.erl
index af14038..a913eee 100644
--- a/src/couch_doc.erl
+++ b/src/couch_doc.erl
@@ -174,6 +174,14 @@
validate_docid(<<"_local/">>) ->
throw({illegal_docid, <<"Illegal document id `_local/`">>});
validate_docid(Id) when is_binary(Id) ->
+ MaxLen = case config:get("couchdb", "max_document_id_length", "infinity") of
+ "infinity" -> infinity;
+ IntegerVal -> list_to_integer(IntegerVal)
+ end,
+ case MaxLen > 0 andalso byte_size(Id) > MaxLen of
+ true -> throw({illegal_docid, <<"Document id is too long">>});
+ false -> ok
+ end,
case couch_util:validate_utf8(Id) of
false -> throw({illegal_docid, <<"Document id must be valid UTF-8">>});
true -> ok
diff --git a/src/couch_server.erl b/src/couch_server.erl
index 59bffa5..893b957 100644
--- a/src/couch_server.erl
+++ b/src/couch_server.erl
@@ -71,18 +71,17 @@
open(DbName, Options0) ->
- Options = maybe_add_sys_db_callbacks(DbName, Options0),
- Ctx = couch_util:get_value(user_ctx, Options, #user_ctx{}),
+ Ctx = couch_util:get_value(user_ctx, Options0, #user_ctx{}),
case ets:lookup(couch_dbs, DbName) of
- [#db{fd=Fd, fd_monitor=Lock} = Db] when Lock =/= locked ->
+ [#db{fd=Fd, fd_monitor=Lock, options=Options} = Db] when Lock =/= locked ->
update_lru(DbName, Options),
{ok, Db#db{user_ctx=Ctx, fd_monitor=erlang:monitor(process,Fd)}};
_ ->
+ Options = maybe_add_sys_db_callbacks(DbName, Options0),
Timeout = couch_util:get_value(timeout, Options, infinity),
Create = couch_util:get_value(create_if_missing, Options, false),
case gen_server:call(couch_server, {open, DbName, Options}, Timeout) of
{ok, #db{fd=Fd} = Db} ->
- update_lru(DbName, Options),
{ok, Db#db{user_ctx=Ctx, fd_monitor=erlang:monitor(process,Fd)}};
{not_found, no_db_file} when Create ->
couch_log:warning("creating missing database: ~s", [DbName]),
diff --git a/src/test_request.erl b/src/test_request.erl
index d757593..8dd0d1a 100644
--- a/src/test_request.erl
+++ b/src/test_request.erl
@@ -15,47 +15,51 @@
-export([get/1, get/2, get/3]).
-export([post/2, post/3, post/4]).
-export([put/2, put/3, put/4]).
--export([delete/1, delete/2]).
+-export([delete/1, delete/2, delete/3]).
-export([options/1, options/2, options/3]).
-export([request/3, request/4]).
get(Url) ->
- request(get, Url, []).
+ get(Url, []).
get(Url, Headers) ->
- request(get, Url, Headers).
+ get(Url, Headers, []).
+
get(Url, Headers, Opts) ->
request(get, Url, Headers, [], Opts).
post(Url, Body) ->
- request(post, Url, [], Body).
+ post(Url, [], Body).
post(Url, Headers, Body) ->
- request(post, Url, Headers, Body).
+ post(Url, Headers, Body, []).
post(Url, Headers, Body, Opts) ->
request(post, Url, Headers, Body, Opts).
put(Url, Body) ->
- request(put, Url, [], Body).
+ put(Url, [], Body).
put(Url, Headers, Body) ->
- request(put, Url, Headers, Body).
+ put(Url, Headers, Body, []).
put(Url, Headers, Body, Opts) ->
request(put, Url, Headers, Body, Opts).
delete(Url) ->
- request(delete, Url, []).
+ delete(Url, []).
delete(Url, Opts) ->
- request(delete, Url, [], [], Opts).
+ delete(Url, [], Opts).
+
+delete(Url, Headers, Opts) ->
+ request(delete, Url, Headers, [], Opts).
options(Url) ->
- request(options, Url, []).
+ options(Url, []).
options(Url, Headers) ->
- request(options, Url, Headers).
+ options(Url, Headers, []).
options(Url, Headers, Opts) ->
request(options, Url, Headers, [], Opts).
diff --git a/test/couch_doc_json_tests.erl b/test/couch_doc_json_tests.erl
index ae4d73c..9003d06 100644
--- a/test/couch_doc_json_tests.erl
+++ b/test/couch_doc_json_tests.erl
@@ -18,11 +18,13 @@
setup() ->
mock(couch_log),
+ mock(config),
mock(couch_db_plugin),
ok.
teardown(_) ->
meck:unload(couch_log),
+ meck:unload(config),
meck:unload(couch_db_plugin),
ok.
@@ -33,6 +35,11 @@
mock(couch_log) ->
ok = meck:new(couch_log, [passthrough]),
ok = meck:expect(couch_log, debug, fun(_, _) -> ok end),
+ ok;
+mock(config) ->
+ meck:new(config, [passthrough]),
+ meck:expect(config, get, fun(_, _) -> undefined end),
+ meck:expect(config, get, fun(_, _, Default) -> Default end),
ok.
diff --git a/test/couch_doc_tests.erl b/test/couch_doc_tests.erl
index fce4ff7..d24cd67 100644
--- a/test/couch_doc_tests.erl
+++ b/test/couch_doc_tests.erl
@@ -29,8 +29,10 @@
ContentType = "multipart/related;boundary=multipart_related_boundary~~~~~~~~~~~~~~~~~~~~",
DataFun = fun() -> request(start) end,
+ mock_config_max_document_id_length(),
{ok, #doc{id = <<"doc0">>, atts = [_]}, _Fun, _Parser} =
couch_doc:doc_from_multi_part_stream(ContentType, DataFun),
+ meck:unload(config),
ok.
doc_to_multi_part_stream_test() ->
@@ -75,16 +77,19 @@
validate_docid_test_() ->
{setup,
fun() ->
+ mock_config_max_document_id_length(),
ok = meck:new(couch_db_plugin, [passthrough]),
meck:expect(couch_db_plugin, validate_docid, fun(_) -> false end)
end,
fun(_) ->
+ meck:unload(config),
meck:unload(couch_db_plugin)
end,
[
?_assertEqual(ok, couch_doc:validate_docid(<<"idx">>)),
?_assertEqual(ok, couch_doc:validate_docid(<<"_design/idx">>)),
?_assertEqual(ok, couch_doc:validate_docid(<<"_local/idx">>)),
+ ?_assertEqual(ok, couch_doc:validate_docid(large_id(1024))),
?_assertThrow({illegal_docid, _},
couch_doc:validate_docid(<<>>)),
?_assertThrow({illegal_docid, _},
@@ -96,10 +101,15 @@
?_assertThrow({illegal_docid, _},
couch_doc:validate_docid(<<"_design/">>)),
?_assertThrow({illegal_docid, _},
- couch_doc:validate_docid(<<"_local/">>))
+ couch_doc:validate_docid(<<"_local/">>)),
+ ?_assertThrow({illegal_docid, _},
+ couch_doc:validate_docid(large_id(1025)))
]
}.
+large_id(N) ->
+ << <<"x">> || _ <- lists:seq(1, N) >>.
+
request(start) ->
{ok, Doc} = file:read_file(?REQUEST_FIXTURE),
{Doc, fun() -> request(stop) end};
@@ -116,3 +126,11 @@
collected() ->
B = binary:replace(iolist_to_binary(get(data)), <<"\r\n">>, <<0>>, [global]),
binary:split(B, [<<0>>], [global]).
+
+mock_config_max_document_id_length() ->
+ ok = meck:new(config, [passthrough]),
+ meck:expect(config, get,
+ fun("couchdb", "max_document_id_length", "infinity") -> "1024";
+ (Key, Val, Default) -> meck:passthrough([Key, Val, Default])
+ end
+ ).