summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/www/script/couch_tests.js100
-rw-r--r--src/couchdb/couch_httpd.erl9
-rw-r--r--src/couchdb/couch_httpd_db.erl7
3 files changed, 63 insertions, 53 deletions
diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js
index 3e2bb381..a7a341e9 100644
--- a/share/www/script/couch_tests.js
+++ b/share/www/script/couch_tests.js
@@ -1235,60 +1235,64 @@ var tests = {
},
design_paths : function(debug) {
- var db = new CouchDB("test_suite_db");
- db.deleteDb();
- db.createDb();
if (debug) debugger;
-
- // create a ddoc w bulk_docs
- db.bulkSave([{
- _id : "_design/test",
- views : {
- "testing" : {
- "map" : "function(){emit(1,1)}"
- }
- }
- }])
-
- // ddoc is getable
- var xhr = CouchDB.request("GET", "/test_suite_db/_design/test");
- var resp = JSON.parse(xhr.responseText);
- T(resp._id == "_design/test");
-
- // it's at 2 urls...
- var xhr = CouchDB.request("GET", "/test_suite_db/_design%2Ftest");
- var resp = JSON.parse(xhr.responseText);
- T(resp._id == "_design/test");
-
- // ensure that views are addressable
- resp = db.view("test/testing")
- T(resp.total_rows == 0)
-
- // create a ddoc by putting to url with raw slash
- var xhr = CouchDB.request("PUT", "/test_suite_db/_design/test2",{
- body : JSON.stringify({
- _id : "_design/test2",
+ var dbNames = ["test_suite_db", "test_suite_db/with_slashes"];
+ for (var i=0; i < dbNames.length; i++) {
+ var db = new CouchDB(dbNames[i]);
+ var dbName = encodeURIComponent(dbNames[i]);
+ db.deleteDb();
+ db.createDb();
+
+ // create a ddoc w bulk_docs
+ db.bulkSave([{
+ _id : "_design/test",
views : {
"testing" : {
"map" : "function(){emit(1,1)}"
}
}
- })
- });
-
- // ddoc is getable
- var xhr = CouchDB.request("GET", "/test_suite_db/_design/test2");
- var resp = JSON.parse(xhr.responseText);
- T(resp._id == "_design/test2");
-
- // it's at 2 urls...
- var xhr = CouchDB.request("GET", "/test_suite_db/_design%2Ftest2");
- var resp = JSON.parse(xhr.responseText);
- T(resp._id == "_design/test2");
-
- // ensure that views are addressable
- resp = db.view("test2/testing")
- T(resp.total_rows == 0)
+ }]);
+
+ // ddoc is getable
+ var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test");
+ var resp = JSON.parse(xhr.responseText);
+ T(resp._id == "_design/test");
+
+ // it's at 2 urls...
+ var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Ftest");
+ var resp = JSON.parse(xhr.responseText);
+ T(resp._id == "_design/test");
+
+ // ensure that views are addressable
+ resp = db.view("test/testing")
+ T(resp.total_rows == 0)
+
+ // create a ddoc by putting to url with raw slash
+ var xhr = CouchDB.request("PUT", "/"+dbName+"/_design/test2",{
+ body : JSON.stringify({
+ _id : "_design/test2",
+ views : {
+ "testing" : {
+ "map" : "function(){emit(1,1)}"
+ }
+ }
+ })
+ });
+
+ // ddoc is getable
+ var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test2");
+ var resp = JSON.parse(xhr.responseText);
+ T(resp._id == "_design/test2");
+
+ // it's at 2 urls...
+ var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Ftest2");
+ var resp = JSON.parse(xhr.responseText);
+ T(resp._id == "_design/test2");
+
+ // ensure that views are addressable
+ resp = db.view("test2/testing");
+ T(resp.total_rows == 0);
+ };
},
content_negotiation: function(debug) {
diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl
index e6b1c895..a9c7320a 100644
--- a/src/couchdb/couch_httpd.erl
+++ b/src/couchdb/couch_httpd.erl
@@ -16,7 +16,7 @@
-export([start_link/0, stop/0, handle_request/3]).
-export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,path/1]).
--export([verify_is_server_admin/1,unquote/1,recv/2]).
+-export([verify_is_server_admin/1,unquote/1,quote/1,recv/2]).
-export([parse_form/1,json_body/1,body/1,doc_etag/1]).
-export([primary_header_value/2,partition/1,serve_file/3]).
-export([start_chunked_response/3,send_chunk/2]).
@@ -152,7 +152,9 @@ handle_request(MochiReq, UrlHandlers, DbUrlHandlers) ->
try
HandlerFun(HttpReq#httpd{user_ctx=AuthenticationFun(HttpReq)})
catch
- _Tag:Error ->
+ Tag:Error ->
+ ?LOG_ERROR("Uncaught error in HTTP request: ~p",[{Tag, Error}]),
+ ?LOG_DEBUG("Stacktrace: ~p",[erlang:get_stacktrace()]),
send_error(HttpReq, Error)
end,
@@ -241,6 +243,9 @@ path(#httpd{mochi_req=MochiReq}) ->
unquote(UrlEncodedString) ->
mochiweb_util:unquote(UrlEncodedString).
+quote(UrlDecodedString) ->
+ mochiweb_util:quote_plus(UrlDecodedString).
+
parse_form(#httpd{mochi_req=MochiReq}) ->
mochiweb_multipart:parse_form(MochiReq).
diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl
index cdebb1e3..fc13622d 100644
--- a/src/couchdb/couch_httpd_db.erl
+++ b/src/couchdb/couch_httpd_db.erl
@@ -256,9 +256,10 @@ db_req(#httpd{path_parts=[_,<<"_admins">>]}=Req, _Db) ->
% Special case to enable using an unencoded slash in the URL of design docs,
% as slashes in document IDs must otherwise be URL encoded.
db_req(#httpd{method='GET',mochi_req=MochiReq, path_parts=[DbName,<<"_design/",_/binary>>|_]}=Req, _Db) ->
- PathFront = "/" ++ binary_to_list(DbName) ++ "/_design",
- {ok, [PathFront|PathTail]} = regexp:split(MochiReq:get(raw_path),"%2F"),
- RedirectTo = PathFront ++ "/" ++ mochiweb_util:join(PathTail, "%2F"),
+ PathFront = "/" ++ couch_httpd:quote(binary_to_list(DbName)) ++ "/",
+ RawSplit = regexp:split(MochiReq:get(raw_path),"_design%2F"),
+ {ok, [PathFront|PathTail]} = RawSplit,
+ RedirectTo = PathFront ++ "_design/" ++ mochiweb_util:join(PathTail, "%2F"),
couch_httpd:send_response(Req, 301, [{"Location", RedirectTo}], <<>>);
db_req(#httpd{path_parts=[_DbName,<<"_design">>,Name]}=Req, Db) ->