index.js 3.9 KB

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