| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| couchTests.elixir = true; |
| |
| couchTests.rewrite = function(debug) { |
| if (debug) debugger; |
| 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(); |
| |
| |
| run_on_modified_server( |
| [{section: "httpd", |
| key: "authentication_handlers", |
| value: "{couch_httpd_auth, special_test_authentication_handler}"}, |
| {section:"httpd", |
| key: "WWW-Authenticate", |
| value: "X-Couch-Test-Auth"}], |
| |
| function(){ |
| var designDoc = { |
| _id:"_design/test", |
| language: "javascript", |
| _attachments:{ |
| "foo.txt": { |
| content_type:"text/plain", |
| data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=" |
| } |
| }, |
| rewrites: [ |
| { |
| "from": "foo", |
| "to": "foo.txt" |
| }, |
| { |
| "from": "foo2", |
| "to": "foo.txt", |
| "method": "GET" |
| }, |
| { |
| "from": "hello/:id", |
| "to": "_update/hello/:id", |
| "method": "PUT" |
| }, |
| { |
| "from": "/welcome", |
| "to": "_show/welcome" |
| }, |
| { |
| "from": "/welcome/:name", |
| "to": "_show/welcome", |
| "query": { |
| "name": ":name" |
| } |
| }, |
| { |
| "from": "/welcome2", |
| "to": "_show/welcome", |
| "query": { |
| "name": "user" |
| } |
| }, |
| { |
| "from": "/welcome3/:name", |
| "to": "_update/welcome2/:name", |
| "method": "PUT" |
| }, |
| { |
| "from": "/welcome3/:name", |
| "to": "_show/welcome2/:name", |
| "method": "GET" |
| }, |
| { |
| "from": "/welcome4/*", |
| "to" : "_show/welcome3", |
| "query": { |
| "name": "*" |
| } |
| }, |
| { |
| "from": "/welcome5/*", |
| "to" : "_show/*", |
| "query": { |
| "name": "*" |
| } |
| }, |
| { |
| "from": "basicView", |
| "to": "_view/basicView", |
| }, |
| { |
| "from": "simpleForm/basicView", |
| "to": "_list/simpleForm/basicView", |
| }, |
| { |
| "from": "simpleForm/basicViewFixed", |
| "to": "_list/simpleForm/basicView", |
| "query": { |
| "startkey": 3, |
| "endkey": 8 |
| } |
| }, |
| { |
| "from": "simpleForm/basicViewPath/:start/:end", |
| "to": "_list/simpleForm/basicView", |
| "query": { |
| "startkey": ":start", |
| "endkey": ":end" |
| }, |
| "formats": { |
| "start": "int", |
| "end": "int" |
| } |
| }, |
| { |
| "from": "simpleForm/complexView", |
| "to": "_list/simpleForm/complexView", |
| "query": { |
| "key": [1, 2] |
| } |
| }, |
| { |
| "from": "simpleForm/complexView2", |
| "to": "_list/simpleForm/complexView", |
| "query": { |
| "key": ["test", {}] |
| } |
| }, |
| { |
| "from": "simpleForm/complexView3", |
| "to": "_list/simpleForm/complexView", |
| "query": { |
| "key": ["test", ["test", "essai"]] |
| } |
| }, |
| { |
| "from": "simpleForm/complexView4", |
| "to": "_list/simpleForm/complexView2", |
| "query": { |
| "key": {"c": 1} |
| } |
| }, |
| { |
| "from": "simpleForm/complexView5/:a/:b", |
| "to": "_list/simpleForm/complexView3", |
| "query": { |
| "key": [":a", ":b"] |
| } |
| }, |
| { |
| "from": "simpleForm/complexView6", |
| "to": "_list/simpleForm/complexView3", |
| "query": { |
| "key": [":a", ":b"] |
| } |
| }, |
| { |
| "from": "simpleForm/complexView7/:a/:b", |
| "to": "_view/complexView3", |
| "query": { |
| "key": [":a", ":b"], |
| "include_docs": ":doc" |
| }, |
| "format": { |
| "doc": "bool" |
| } |
| |
| }, |
| { |
| "from": "/", |
| "to": "_view/basicView", |
| }, |
| { |
| "from": "/db/*", |
| "to": "../../*" |
| } |
| ], |
| lists: { |
| simpleForm: stringFun(function(head, req) { |
| log("simpleForm"); |
| send('<ul>'); |
| var row, row_number = 0, prevKey, firstKey = null; |
| while (row = getRow()) { |
| row_number += 1; |
| if (!firstKey) firstKey = row.key; |
| prevKey = row.key; |
| send('\n<li>Key: '+row.key |
| +' Value: '+row.value |
| +' LineNo: '+row_number+'</li>'); |
| } |
| return '</ul><p>FirstKey: '+ firstKey + ' LastKey: '+ prevKey+'</p>'; |
| }), |
| }, |
| shows: { |
| "welcome": stringFun(function(doc,req) { |
| return "Welcome " + req.query["name"]; |
| }), |
| "welcome2": stringFun(function(doc, req) { |
| return "Welcome " + doc.name; |
| }), |
| "welcome3": stringFun(function(doc,req) { |
| return "Welcome " + req.query["name"]; |
| }) |
| }, |
| updates: { |
| "hello" : stringFun(function(doc, req) { |
| if (!doc) { |
| if (req.id) { |
| return [{ |
| _id : req.id |
| }, "New World"] |
| } |
| return [null, "Empty World"]; |
| } |
| doc.world = "hello"; |
| doc.edited_by = req.userCtx; |
| return [doc, "hello doc"]; |
| }), |
| "welcome2": stringFun(function(doc, req) { |
| if (!doc) { |
| if (req.id) { |
| return [{ |
| _id: req.id, |
| name: req.id |
| }, "New World"] |
| } |
| return [null, "Empty World"]; |
| } |
| return [doc, "hello doc"]; |
| }) |
| }, |
| views : { |
| basicView : { |
| map : stringFun(function(doc) { |
| if (doc.integer) { |
| emit(doc.integer, doc.string); |
| } |
| |
| }) |
| }, |
| complexView: { |
| map: stringFun(function(doc) { |
| if (doc.type == "complex") { |
| emit([doc.a, doc.b], doc.string); |
| } |
| }) |
| }, |
| complexView2: { |
| map: stringFun(function(doc) { |
| if (doc.type == "complex") { |
| emit(doc.a, doc.string); |
| } |
| }) |
| }, |
| complexView3: { |
| map: stringFun(function(doc) { |
| if (doc.type == "complex") { |
| emit(doc.b, doc.string); |
| } |
| }) |
| } |
| } |
| } |
| |
| db.save(designDoc); |
| |
| var docs = makeDocs(0, 10); |
| db.bulkSave(docs); |
| |
| var docs2 = [ |
| {"a": 1, "b": 1, "string": "doc 1", "type": "complex"}, |
| {"a": 1, "b": 2, "string": "doc 2", "type": "complex"}, |
| {"a": "test", "b": {}, "string": "doc 3", "type": "complex"}, |
| {"a": "test", "b": ["test", "essai"], "string": "doc 4", "type": "complex"}, |
| {"a": {"c": 1}, "b": "", "string": "doc 5", "type": "complex"} |
| ]; |
| |
| db.bulkSave(docs2); |
| |
| // test simple rewriting |
| |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/foo"); |
| T(req.responseText == "This is a base64 encoded text"); |
| T(req.getResponseHeader("Content-Type") == "text/plain"); |
| |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/foo2"); |
| T(req.responseText == "This is a base64 encoded text"); |
| T(req.getResponseHeader("Content-Type") == "text/plain"); |
| |
| |
| // test POST |
| // hello update world |
| |
| var doc = {"word":"plankton", "name":"Rusty"} |
| var resp = db.save(doc); |
| T(resp.ok); |
| var docid = resp.id; |
| |
| xhr = CouchDB.request("PUT", "/"+dbName+"/_design/test/_rewrite/hello/"+docid); |
| T(xhr.status == 201); |
| T(xhr.responseText == "hello doc"); |
| T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type"))) |
| |
| doc = db.open(docid); |
| T(doc.world == "hello"); |
| |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome?name=user"); |
| T(req.responseText == "Welcome user"); |
| |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome/user"); |
| T(req.responseText == "Welcome user"); |
| |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome2"); |
| T(req.responseText == "Welcome user"); |
| |
| xhr = CouchDB.request("PUT", "/"+dbName+"/_design/test/_rewrite/welcome3/test"); |
| T(xhr.status == 201); |
| T(xhr.responseText == "New World"); |
| T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type"))); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome3/test"); |
| T(xhr.responseText == "Welcome test"); |
| |
| /* // XXX: THESE ARE BUGGED and I don't know what the right response is |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome4/user"); |
| T(req.responseText == "Welcome user", req.responseText); |
| |
| req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome5/welcome3"); |
| T(req.responseText == "Welcome welcome3", req.responseText); |
| */ |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/basicView"); |
| T(xhr.status == 200, "view call"); |
| T(/{"total_rows":9/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/"); |
| T(xhr.status == 200, "view call"); |
| T(/{"total_rows":9/.test(xhr.responseText)); |
| |
| |
| // get with query params |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicView?startkey=3&endkey=8"); |
| T(xhr.status == 200, "with query params"); |
| T(!(/Key: 1/.test(xhr.responseText))); |
| T(/FirstKey: 3/.test(xhr.responseText)); |
| T(/LastKey: 8/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicViewFixed"); |
| T(xhr.status == 200, "with query params"); |
| T(!(/Key: 1/.test(xhr.responseText))); |
| T(/FirstKey: 3/.test(xhr.responseText)); |
| T(/LastKey: 8/.test(xhr.responseText)); |
| |
| // get with query params |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicViewFixed?startkey=4"); |
| T(xhr.status == 200, "with query params"); |
| T(!(/Key: 1/.test(xhr.responseText))); |
| T(/FirstKey: 3/.test(xhr.responseText)); |
| T(/LastKey: 8/.test(xhr.responseText)); |
| |
| // get with query params |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicViewPath/3/8"); |
| T(xhr.status == 200, "with query params"); |
| T(!(/Key: 1/.test(xhr.responseText))); |
| T(/FirstKey: 3/.test(xhr.responseText)); |
| T(/LastKey: 8/.test(xhr.responseText)); |
| |
| // get with query params |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView"); |
| T(xhr.status == 200, "with query params"); |
| T(/FirstKey: [1, 2]/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView2"); |
| T(xhr.status == 200, "with query params"); |
| T(/Value: doc 3/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView3"); |
| T(xhr.status == 200, "with query params"); |
| T(/Value: doc 4/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView4"); |
| T(xhr.status == 200, "with query params"); |
| T(/Value: doc 5/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView5/test/essai"); |
| T(xhr.status == 200, "with query params"); |
| T(/Value: doc 4/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView6?a=test&b=essai"); |
| T(xhr.status == 200, "with query params"); |
| T(/Value: doc 4/.test(xhr.responseText)); |
| |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView7/test/essai?doc=true"); |
| T(xhr.status == 200, "with query params"); |
| var result = JSON.parse(xhr.responseText); |
| T(typeof(result.rows[0].doc) === "object"); |
| |
| // COUCHDB-2031 - path normalization versus qs params |
| xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/db/_design/test?meta=true"); |
| T(xhr.status == 200, "path normalization works with qs params"); |
| var result = JSON.parse(xhr.responseText); |
| T(result['_id'] == "_design/test"); |
| T(typeof(result['_revs_info']) === "object"); |
| |
| // test path relative to server |
| T(db.save({ |
| _id: "_design/test2", |
| rewrites: [{ |
| "from": "uuids", |
| "to": "../../../_uuids" |
| }] |
| }).ok); |
| |
| var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test2/_rewrite/uuids"); |
| T(xhr.status == 500); |
| var result = JSON.parse(xhr.responseText); |
| T(result.error == "insecure_rewrite_rule"); |
| |
| run_on_modified_server( |
| [{section: "httpd", |
| key: "secure_rewrites", |
| value: "false"}], |
| function() { |
| var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test2/_rewrite/uuids?cache=bust"); |
| T(xhr.status == 200); |
| var result = JSON.parse(xhr.responseText); |
| T(result.uuids.length == 1); |
| var first = result.uuids[0]; |
| }); |
| }); |
| |
| /* // XXX: we have actual failures here that we need to get to |
| // test invalid rewrites |
| // string |
| var ddoc = { |
| _id: "_design/invalid", |
| rewrites: "[{\"from\":\"foo\",\"to\":\"bar\"}]" |
| } |
| db.save(ddoc); |
| var res = CouchDB.request("GET", "/"+dbName+"/_design/invalid/_rewrite/foo"); |
| TEquals(400, res.status, "should return 400"); |
| |
| var ddoc_requested_path = { |
| _id: "_design/requested_path", |
| rewrites:[ |
| {"from": "show", "to": "_show/origin/0"}, |
| {"from": "show_rewritten", "to": "_rewrite/show"} |
| ], |
| shows: { |
| origin: stringFun(function(doc, req) { |
| return req.headers["x-couchdb-requested-path"]; |
| })} |
| }; |
| |
| db.save(ddoc_requested_path); |
| var url = "/"+dbName+"/_design/requested_path/_rewrite/show"; |
| var res = CouchDB.request("GET", url); |
| TEquals(url, res.responseText, "should return the original url"); |
| |
| var url = "/"+dbName+"/_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); |
| |
| // Assert loop detection |
| run_on_modified_server( |
| [{section: "httpd", |
| key: "rewrite_limit", |
| value: "2"}], |
| function(){ |
| var url = "/"+dbName+"/_design/loop/_rewrite/loop"; |
| var xhr = CouchDB.request("GET", url); |
| TEquals(400, xhr.status); |
| }); |
| |
| // Assert serial execution is not spuriously counted as loop |
| run_on_modified_server( |
| [{section: "httpd", |
| key: "rewrite_limit", |
| value: "2"}, |
| {section: "httpd", |
| key: "secure_rewrites", |
| value: "false"}], |
| function(){ |
| var url = "/"+dbName+"/_design/test/_rewrite/foo"; |
| for (var i=0; i < 5; i++) { |
| var xhr = CouchDB.request("GET", url); |
| TEquals(200, xhr.status); |
| } |
| }); |
| // cleanup |
| db.deleteDb(); |
| } |
| } |