index.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // muri
  2. /**
  3. * MongoDB URI parser as described here:
  4. * http://www.mongodb.org/display/DOCS/Connections
  5. */
  6. /**
  7. * Module dependencies
  8. */
  9. var qs = require('querystring');
  10. /**
  11. * Defaults
  12. */
  13. var DEFAULT_PORT = 27017;
  14. var DEFAULT_DB = 'test';
  15. var ADMIN_DB = 'admin';
  16. /**
  17. * Muri
  18. */
  19. module.exports = exports = function muri (str) {
  20. if (!/^mongodb:\/\//.test(str)) {
  21. throw new Error('Invalid mongodb uri "' + str + '". Must begin with "mongodb://"');
  22. }
  23. var ret = {
  24. hosts: []
  25. , db: DEFAULT_DB
  26. , options: {}
  27. }
  28. var match = /^mongodb:\/\/([^?]+)(\??.*)$/.exec(str);
  29. if (!match || '/' == match[1]) {
  30. throw new Error('Invalid mongodb uri "' + str + '". Missing hostname');
  31. }
  32. var uris = match[1];
  33. var path = match[2];
  34. var db;
  35. uris.split(',').forEach(function (uri) {
  36. var o = parse(uri);
  37. if (o.host) {
  38. ret.hosts.push({
  39. host: o.host
  40. , port: parseInt(o.port, 10)
  41. })
  42. if (!db && o.db) {
  43. db = o.db;
  44. }
  45. } else if (o.ipc) {
  46. ret.hosts.push({ ipc: o.ipc });
  47. }
  48. if (o.auth) {
  49. ret.auth = {
  50. user: o.auth.user ? (o.auth.user) : void 0
  51. , pass: o.auth.pass ? (o.auth.pass) : void 0
  52. }
  53. }
  54. })
  55. if (!ret.hosts.length) {
  56. throw new Error('Invalid mongodb uri "' + str + '". Missing hostname');
  57. }
  58. var parts = path.split('?');
  59. if (!db) {
  60. if (parts[0]) {
  61. db = parts[0].replace(/^\//, '');
  62. } else {
  63. // deal with ipc formats
  64. db = /\/([^\.]+)$/.exec(match[1]);
  65. if (db && db[1]) {
  66. db = db[1];
  67. }
  68. }
  69. }
  70. if (db) {
  71. ret.db = db;
  72. } else if (ret.auth) {
  73. ret.db = ADMIN_DB;
  74. }
  75. if (parts[1]) {
  76. ret.options = options(parts[1]);
  77. }
  78. return ret;
  79. }
  80. /**
  81. * Parse str into key/val pairs casting values appropriately.
  82. */
  83. function options (str) {
  84. var sep = /;/.test(str)
  85. ? ';'
  86. : '&';
  87. var ret = qs.parse(str, sep);
  88. Object.keys(ret).forEach(function (key) {
  89. var val = ret[key];
  90. if ('readPreferenceTags' == key) {
  91. val = readPref(val);
  92. if (val) {
  93. ret[key] = Array.isArray(val)
  94. ? val
  95. : [val];
  96. }
  97. } else {
  98. ret[key] = format(val);
  99. }
  100. });
  101. return ret;
  102. }
  103. function format (val) {
  104. var num;
  105. if ('true' == val) {
  106. return true;
  107. } else if ('false' == val) {
  108. return false;
  109. } else {
  110. num = parseInt(+val, 10);
  111. if (!isNaN(num)) {
  112. return num;
  113. }
  114. }
  115. return val;
  116. }
  117. function readPref (val) {
  118. var ret;
  119. if (Array.isArray(val)) {
  120. ret = val.map(readPref).filter(Boolean);
  121. return ret.length
  122. ? ret
  123. : undefined
  124. }
  125. var pair = val.split(',');
  126. var hasKeys;
  127. ret = {};
  128. pair.forEach(function (kv) {
  129. kv = (kv || '').trim();
  130. if (!kv) return;
  131. hasKeys = true;
  132. var split = kv.split(':');
  133. ret[split[0]] = format(split[1]);
  134. });
  135. return hasKeys && ret;
  136. }
  137. var ipcRgx = /\.sock/;
  138. function parse (uriString) {
  139. // do not use require('url').parse b/c it can't handle # in username or pwd
  140. // mongo uris are strange
  141. var uri = uriString;
  142. var ret = {};
  143. var parts;
  144. var auth;
  145. var ipcs;
  146. // skip protocol
  147. uri = uri.replace(/^mongodb:\/\//, '');
  148. // auth
  149. if (/@/.test(uri)) {
  150. parts = uri.split(/@/);
  151. auth = parts[0];
  152. uri = parts[1];
  153. parts = auth.split(':');
  154. ret.auth = {};
  155. ret.auth.user = decodeURIComponent(parts[0]);
  156. ret.auth.pass = parts[1] ? decodeURIComponent(parts[1]) : void 0;
  157. }
  158. // unix domain sockets
  159. if (ipcRgx.test(uri)) {
  160. ipcs = uri.split(ipcRgx);
  161. ret.ipc = ipcs[0] + '.sock';
  162. // included a database?
  163. if (ipcs[1]) {
  164. // strip leading / from database name
  165. ipcs[1] = ipcs[1].replace(/^\//, '');
  166. if (ipcs[1]) {
  167. ret.db = ipcs[1];
  168. }
  169. }
  170. return ret;
  171. }
  172. // database name
  173. parts = uri.split('/');
  174. if (parts[1]) ret.db = parts[1];
  175. // ipv6, [ip]:host
  176. if (/^\[[^\]]+\]:\d+/.test(parts[0])) {
  177. ret.host = parts[0].substring(1, parts[0].indexOf(']:'));
  178. ret.port = parts[0].substring(parts[0].indexOf(']:') + ']:'.length);
  179. } else {
  180. // host:port
  181. parts = parts[0].split(':');
  182. ret.host = parts[0];
  183. ret.port = parts[1] || DEFAULT_PORT;
  184. }
  185. return ret;
  186. }
  187. /**
  188. * Version
  189. */
  190. module.exports.version = require('../package.json').version;