PageRenderTime 53ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/test/javascript/tests/rewrite.js

http://github.com/apache/couchdb
JavaScript | 513 lines | 403 code | 48 blank | 62 comment | 48 complexity | 400b1505012076e0064578d4c6157d49 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  2. // use this file except in compliance with the License. You may obtain a copy of
  3. // the License at
  4. //
  5. // http://www.apache.org/licenses/LICENSE-2.0
  6. //
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  9. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  10. // License for the specific language governing permissions and limitations under
  11. // the License.
  12. couchTests.rewrite = function(debug) {
  13. if (debug) debugger;
  14. var dbNames = ["test_suite_db", "test_suite_db/with_slashes"];
  15. for (var i=0; i < dbNames.length; i++) {
  16. var db = new CouchDB(dbNames[i]);
  17. var dbName = encodeURIComponent(dbNames[i]);
  18. db.deleteDb();
  19. db.createDb();
  20. run_on_modified_server(
  21. [{section: "httpd",
  22. key: "authentication_handlers",
  23. value: "{couch_httpd_auth, special_test_authentication_handler}"},
  24. {section:"httpd",
  25. key: "WWW-Authenticate",
  26. value: "X-Couch-Test-Auth"}],
  27. function(){
  28. var designDoc = {
  29. _id:"_design/test",
  30. language: "javascript",
  31. _attachments:{
  32. "foo.txt": {
  33. content_type:"text/plain",
  34. data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
  35. }
  36. },
  37. rewrites: [
  38. {
  39. "from": "foo",
  40. "to": "foo.txt"
  41. },
  42. {
  43. "from": "foo2",
  44. "to": "foo.txt",
  45. "method": "GET"
  46. },
  47. {
  48. "from": "hello/:id",
  49. "to": "_update/hello/:id",
  50. "method": "PUT"
  51. },
  52. {
  53. "from": "/welcome",
  54. "to": "_show/welcome"
  55. },
  56. {
  57. "from": "/welcome/:name",
  58. "to": "_show/welcome",
  59. "query": {
  60. "name": ":name"
  61. }
  62. },
  63. {
  64. "from": "/welcome2",
  65. "to": "_show/welcome",
  66. "query": {
  67. "name": "user"
  68. }
  69. },
  70. {
  71. "from": "/welcome3/:name",
  72. "to": "_update/welcome2/:name",
  73. "method": "PUT"
  74. },
  75. {
  76. "from": "/welcome3/:name",
  77. "to": "_show/welcome2/:name",
  78. "method": "GET"
  79. },
  80. {
  81. "from": "/welcome4/*",
  82. "to" : "_show/welcome3",
  83. "query": {
  84. "name": "*"
  85. }
  86. },
  87. {
  88. "from": "/welcome5/*",
  89. "to" : "_show/*",
  90. "query": {
  91. "name": "*"
  92. }
  93. },
  94. {
  95. "from": "basicView",
  96. "to": "_view/basicView",
  97. },
  98. {
  99. "from": "simpleForm/basicView",
  100. "to": "_list/simpleForm/basicView",
  101. },
  102. {
  103. "from": "simpleForm/basicViewFixed",
  104. "to": "_list/simpleForm/basicView",
  105. "query": {
  106. "startkey": 3,
  107. "endkey": 8
  108. }
  109. },
  110. {
  111. "from": "simpleForm/basicViewPath/:start/:end",
  112. "to": "_list/simpleForm/basicView",
  113. "query": {
  114. "startkey": ":start",
  115. "endkey": ":end"
  116. },
  117. "formats": {
  118. "start": "int",
  119. "end": "int"
  120. }
  121. },
  122. {
  123. "from": "simpleForm/complexView",
  124. "to": "_list/simpleForm/complexView",
  125. "query": {
  126. "key": [1, 2]
  127. }
  128. },
  129. {
  130. "from": "simpleForm/complexView2",
  131. "to": "_list/simpleForm/complexView",
  132. "query": {
  133. "key": ["test", {}]
  134. }
  135. },
  136. {
  137. "from": "simpleForm/complexView3",
  138. "to": "_list/simpleForm/complexView",
  139. "query": {
  140. "key": ["test", ["test", "essai"]]
  141. }
  142. },
  143. {
  144. "from": "simpleForm/complexView4",
  145. "to": "_list/simpleForm/complexView2",
  146. "query": {
  147. "key": {"c": 1}
  148. }
  149. },
  150. {
  151. "from": "simpleForm/complexView5/:a/:b",
  152. "to": "_list/simpleForm/complexView3",
  153. "query": {
  154. "key": [":a", ":b"]
  155. }
  156. },
  157. {
  158. "from": "simpleForm/complexView6",
  159. "to": "_list/simpleForm/complexView3",
  160. "query": {
  161. "key": [":a", ":b"]
  162. }
  163. },
  164. {
  165. "from": "simpleForm/complexView7/:a/:b",
  166. "to": "_view/complexView3",
  167. "query": {
  168. "key": [":a", ":b"],
  169. "include_docs": ":doc"
  170. },
  171. "format": {
  172. "doc": "bool"
  173. }
  174. },
  175. {
  176. "from": "/",
  177. "to": "_view/basicView",
  178. },
  179. {
  180. "from": "/db/*",
  181. "to": "../../*"
  182. }
  183. ],
  184. lists: {
  185. simpleForm: stringFun(function(head, req) {
  186. log("simpleForm");
  187. send('<ul>');
  188. var row, row_number = 0, prevKey, firstKey = null;
  189. while (row = getRow()) {
  190. row_number += 1;
  191. if (!firstKey) firstKey = row.key;
  192. prevKey = row.key;
  193. send('\n<li>Key: '+row.key
  194. +' Value: '+row.value
  195. +' LineNo: '+row_number+'</li>');
  196. }
  197. return '</ul><p>FirstKey: '+ firstKey + ' LastKey: '+ prevKey+'</p>';
  198. }),
  199. },
  200. shows: {
  201. "welcome": stringFun(function(doc,req) {
  202. return "Welcome " + req.query["name"];
  203. }),
  204. "welcome2": stringFun(function(doc, req) {
  205. return "Welcome " + doc.name;
  206. }),
  207. "welcome3": stringFun(function(doc,req) {
  208. return "Welcome " + req.query["name"];
  209. })
  210. },
  211. updates: {
  212. "hello" : stringFun(function(doc, req) {
  213. if (!doc) {
  214. if (req.id) {
  215. return [{
  216. _id : req.id
  217. }, "New World"]
  218. }
  219. return [null, "Empty World"];
  220. }
  221. doc.world = "hello";
  222. doc.edited_by = req.userCtx;
  223. return [doc, "hello doc"];
  224. }),
  225. "welcome2": stringFun(function(doc, req) {
  226. if (!doc) {
  227. if (req.id) {
  228. return [{
  229. _id: req.id,
  230. name: req.id
  231. }, "New World"]
  232. }
  233. return [null, "Empty World"];
  234. }
  235. return [doc, "hello doc"];
  236. })
  237. },
  238. views : {
  239. basicView : {
  240. map : stringFun(function(doc) {
  241. if (doc.integer) {
  242. emit(doc.integer, doc.string);
  243. }
  244. })
  245. },
  246. complexView: {
  247. map: stringFun(function(doc) {
  248. if (doc.type == "complex") {
  249. emit([doc.a, doc.b], doc.string);
  250. }
  251. })
  252. },
  253. complexView2: {
  254. map: stringFun(function(doc) {
  255. if (doc.type == "complex") {
  256. emit(doc.a, doc.string);
  257. }
  258. })
  259. },
  260. complexView3: {
  261. map: stringFun(function(doc) {
  262. if (doc.type == "complex") {
  263. emit(doc.b, doc.string);
  264. }
  265. })
  266. }
  267. }
  268. }
  269. db.save(designDoc);
  270. var docs = makeDocs(0, 10);
  271. db.bulkSave(docs);
  272. var docs2 = [
  273. {"a": 1, "b": 1, "string": "doc 1", "type": "complex"},
  274. {"a": 1, "b": 2, "string": "doc 2", "type": "complex"},
  275. {"a": "test", "b": {}, "string": "doc 3", "type": "complex"},
  276. {"a": "test", "b": ["test", "essai"], "string": "doc 4", "type": "complex"},
  277. {"a": {"c": 1}, "b": "", "string": "doc 5", "type": "complex"}
  278. ];
  279. db.bulkSave(docs2);
  280. // test simple rewriting
  281. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/foo");
  282. T(req.responseText == "This is a base64 encoded text");
  283. T(req.getResponseHeader("Content-Type") == "text/plain");
  284. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/foo2");
  285. T(req.responseText == "This is a base64 encoded text");
  286. T(req.getResponseHeader("Content-Type") == "text/plain");
  287. // test POST
  288. // hello update world
  289. var doc = {"word":"plankton", "name":"Rusty"}
  290. var resp = db.save(doc);
  291. T(resp.ok);
  292. var docid = resp.id;
  293. xhr = CouchDB.request("PUT", "/"+dbName+"/_design/test/_rewrite/hello/"+docid);
  294. T(xhr.status == 201);
  295. T(xhr.responseText == "hello doc");
  296. T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type")))
  297. doc = db.open(docid);
  298. T(doc.world == "hello");
  299. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome?name=user");
  300. T(req.responseText == "Welcome user");
  301. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome/user");
  302. T(req.responseText == "Welcome user");
  303. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome2");
  304. T(req.responseText == "Welcome user");
  305. xhr = CouchDB.request("PUT", "/"+dbName+"/_design/test/_rewrite/welcome3/test");
  306. T(xhr.status == 201);
  307. T(xhr.responseText == "New World");
  308. T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type")));
  309. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome3/test");
  310. T(xhr.responseText == "Welcome test");
  311. /* // XXX: THESE ARE BUGGED and I don't know what the right response is
  312. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome4/user");
  313. T(req.responseText == "Welcome user", req.responseText);
  314. req = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/welcome5/welcome3");
  315. T(req.responseText == "Welcome welcome3", req.responseText);
  316. */
  317. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/basicView");
  318. T(xhr.status == 200, "view call");
  319. T(/{"total_rows":9/.test(xhr.responseText));
  320. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/");
  321. T(xhr.status == 200, "view call");
  322. T(/{"total_rows":9/.test(xhr.responseText));
  323. // get with query params
  324. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicView?startkey=3&endkey=8");
  325. T(xhr.status == 200, "with query params");
  326. T(!(/Key: 1/.test(xhr.responseText)));
  327. T(/FirstKey: 3/.test(xhr.responseText));
  328. T(/LastKey: 8/.test(xhr.responseText));
  329. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicViewFixed");
  330. T(xhr.status == 200, "with query params");
  331. T(!(/Key: 1/.test(xhr.responseText)));
  332. T(/FirstKey: 3/.test(xhr.responseText));
  333. T(/LastKey: 8/.test(xhr.responseText));
  334. // get with query params
  335. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicViewFixed?startkey=4");
  336. T(xhr.status == 200, "with query params");
  337. T(!(/Key: 1/.test(xhr.responseText)));
  338. T(/FirstKey: 3/.test(xhr.responseText));
  339. T(/LastKey: 8/.test(xhr.responseText));
  340. // get with query params
  341. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/basicViewPath/3/8");
  342. T(xhr.status == 200, "with query params");
  343. T(!(/Key: 1/.test(xhr.responseText)));
  344. T(/FirstKey: 3/.test(xhr.responseText));
  345. T(/LastKey: 8/.test(xhr.responseText));
  346. // get with query params
  347. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView");
  348. T(xhr.status == 200, "with query params");
  349. T(/FirstKey: [1, 2]/.test(xhr.responseText));
  350. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView2");
  351. T(xhr.status == 200, "with query params");
  352. T(/Value: doc 3/.test(xhr.responseText));
  353. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView3");
  354. T(xhr.status == 200, "with query params");
  355. T(/Value: doc 4/.test(xhr.responseText));
  356. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView4");
  357. T(xhr.status == 200, "with query params");
  358. T(/Value: doc 5/.test(xhr.responseText));
  359. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView5/test/essai");
  360. T(xhr.status == 200, "with query params");
  361. T(/Value: doc 4/.test(xhr.responseText));
  362. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView6?a=test&b=essai");
  363. T(xhr.status == 200, "with query params");
  364. T(/Value: doc 4/.test(xhr.responseText));
  365. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/simpleForm/complexView7/test/essai?doc=true");
  366. T(xhr.status == 200, "with query params");
  367. var result = JSON.parse(xhr.responseText);
  368. T(typeof(result.rows[0].doc) === "object");
  369. // COUCHDB-2031 - path normalization versus qs params
  370. xhr = CouchDB.request("GET", "/"+dbName+"/_design/test/_rewrite/db/_design/test?meta=true");
  371. T(xhr.status == 200, "path normalization works with qs params");
  372. var result = JSON.parse(xhr.responseText);
  373. T(result['_id'] == "_design/test");
  374. T(typeof(result['_revs_info']) === "object");
  375. // test path relative to server
  376. T(db.save({
  377. _id: "_design/test2",
  378. rewrites: [{
  379. "from": "uuids",
  380. "to": "../../../_uuids"
  381. }]
  382. }).ok);
  383. var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test2/_rewrite/uuids");
  384. T(xhr.status == 500);
  385. var result = JSON.parse(xhr.responseText);
  386. T(result.error == "insecure_rewrite_rule");
  387. run_on_modified_server(
  388. [{section: "httpd",
  389. key: "secure_rewrites",
  390. value: "false"}],
  391. function() {
  392. var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test2/_rewrite/uuids?cache=bust");
  393. T(xhr.status == 200);
  394. var result = JSON.parse(xhr.responseText);
  395. T(result.uuids.length == 1);
  396. var first = result.uuids[0];
  397. });
  398. });
  399. /* // XXX: we have actual failures here that we need to get to
  400. // test invalid rewrites
  401. // string
  402. var ddoc = {
  403. _id: "_design/invalid",
  404. rewrites: "[{\"from\":\"foo\",\"to\":\"bar\"}]"
  405. }
  406. db.save(ddoc);
  407. var res = CouchDB.request("GET", "/"+dbName+"/_design/invalid/_rewrite/foo");
  408. TEquals(400, res.status, "should return 400");
  409. var ddoc_requested_path = {
  410. _id: "_design/requested_path",
  411. rewrites:[
  412. {"from": "show", "to": "_show/origin/0"},
  413. {"from": "show_rewritten", "to": "_rewrite/show"}
  414. ],
  415. shows: {
  416. origin: stringFun(function(doc, req) {
  417. return req.headers["x-couchdb-requested-path"];
  418. })}
  419. };
  420. db.save(ddoc_requested_path);
  421. var url = "/"+dbName+"/_design/requested_path/_rewrite/show";
  422. var res = CouchDB.request("GET", url);
  423. TEquals(url, res.responseText, "should return the original url");
  424. var url = "/"+dbName+"/_design/requested_path/_rewrite/show_rewritten";
  425. var res = CouchDB.request("GET", url);
  426. TEquals(url, res.responseText, "returned the original url");
  427. */
  428. var ddoc_loop = {
  429. _id: "_design/loop",
  430. rewrites: [{ "from": "loop", "to": "_rewrite/loop"}]
  431. };
  432. db.save(ddoc_loop);
  433. // Assert loop detection
  434. run_on_modified_server(
  435. [{section: "httpd",
  436. key: "rewrite_limit",
  437. value: "2"}],
  438. function(){
  439. var url = "/"+dbName+"/_design/loop/_rewrite/loop";
  440. var xhr = CouchDB.request("GET", url);
  441. TEquals(400, xhr.status);
  442. });
  443. // Assert serial execution is not spuriously counted as loop
  444. run_on_modified_server(
  445. [{section: "httpd",
  446. key: "rewrite_limit",
  447. value: "2"},
  448. {section: "httpd",
  449. key: "secure_rewrites",
  450. value: "false"}],
  451. function(){
  452. var url = "/"+dbName+"/_design/test/_rewrite/foo";
  453. for (var i=0; i < 5; i++) {
  454. var xhr = CouchDB.request("GET", url);
  455. TEquals(200, xhr.status);
  456. }
  457. });
  458. // cleanup
  459. db.deleteDb();
  460. }
  461. }