summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>2012-03-28 16:58:20 +0200
committerJan Lehnardt <jan@apache.org>2012-05-01 14:03:45 +0100
commit30334ac87a90fc88804037cab073caf9fc48de38 (patch)
tree586763ab202accf5b19da0cdee979cc4eddddb27
parent56744f2f4b63c396a68e892fcfaec1a84ab95bf2 (diff)
downloadcouchdb-30334ac87a90fc88804037cab073caf9fc48de38.tar.gz
Limit rewrite recursion depth
Loops in the rewriter would end up pegging the CPU until memory was exhausted. Max recursion is now configurable and limited to 100 iterations. Fixes: COUCHDB-1441
-rw-r--r--CHANGES2
-rw-r--r--share/www/script/test/rewrite.js16
-rw-r--r--src/couchdb/couch_httpd_rewrite.erl11
3 files changed, 29 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 8524110b0..ac55bd48c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -10,6 +10,8 @@ HTTP Interface:
* No longer rewrites the X-CouchDB-Requested-Path during recursive
calls to the rewriter.
+ * Limit recursion depth in the URL rewriter. Defaults to a maximum
+ of 100 invocations but is configurable.
Version 1.2.0
-------------
diff --git a/share/www/script/test/rewrite.js b/share/www/script/test/rewrite.js
index aaf8b69e9..352e6b99b 100644
--- a/share/www/script/test/rewrite.js
+++ b/share/www/script/test/rewrite.js
@@ -457,4 +457,20 @@ couchTests.rewrite = function(debug) {
var url = "/test_suite_db/_design/requested_path/_rewrite/show_rewritten";
var res = CouchDB.request("GET", url);
TEquals(url, res.responseText, "returned the original url");
+
+ var ddoc_loop = {
+ _id: "_design/loop",
+ rewrites: [{ "from": "loop", "to": "_rewrite/loop"}]
+ };
+ db.save(ddoc_loop);
+
+ run_on_modified_server(
+ [{section: "httpd",
+ key: "rewrite_limit",
+ value: "2"}],
+ function(){
+ var url = "/test_suite_db/_design/loop/_rewrite/loop";
+ var xhr = CouchDB.request("GET", url);
+ T(xhr.status = 400);
+ });
}
diff --git a/src/couchdb/couch_httpd_rewrite.erl b/src/couchdb/couch_httpd_rewrite.erl
index cb164cd1f..207891ab9 100644
--- a/src/couchdb/couch_httpd_rewrite.erl
+++ b/src/couchdb/couch_httpd_rewrite.erl
@@ -119,6 +119,17 @@ handle_rewrite_req(#httpd{
Prefix = <<"/", DbName/binary, "/", DesignId/binary>>,
QueryList = lists:map(fun decode_query_value/1, couch_httpd:qs(Req)),
+ MaxRewritesList = couch_config:get("httpd", "rewrite_limit", "100"),
+ MaxRewrites = list_to_integer(MaxRewritesList),
+ NRewrites = case get(couch_rewrite_count) of
+ undefined ->
+ put(couch_rewrite_count, 1);
+ NumRewrites when NumRewrites < MaxRewrites ->
+ put(couch_rewrite_count, NumRewrites + 1);
+ _ ->
+ throw({bad_request, <<"Exceeded rewrite recursion limit">>})
+ end,
+
#doc{body={Props}} = DDoc,
% get rules from ddoc