index.js 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*!
  2. * parseurl
  3. * Copyright(c) 2014 Jonathan Ong
  4. * Copyright(c) 2014-2017 Douglas Christopher Wilson
  5. * MIT Licensed
  6. */
  7. 'use strict'
  8. /**
  9. * Module dependencies.
  10. * @private
  11. */
  12. var url = require('url')
  13. var parse = url.parse
  14. var Url = url.Url
  15. /**
  16. * Module exports.
  17. * @public
  18. */
  19. module.exports = parseurl
  20. module.exports.original = originalurl
  21. /**
  22. * Parse the `req` url with memoization.
  23. *
  24. * @param {ServerRequest} req
  25. * @return {Object}
  26. * @public
  27. */
  28. function parseurl (req) {
  29. var url = req.url
  30. if (url === undefined) {
  31. // URL is undefined
  32. return undefined
  33. }
  34. var parsed = req._parsedUrl
  35. if (fresh(url, parsed)) {
  36. // Return cached URL parse
  37. return parsed
  38. }
  39. // Parse the URL
  40. parsed = fastparse(url)
  41. parsed._raw = url
  42. return (req._parsedUrl = parsed)
  43. };
  44. /**
  45. * Parse the `req` original url with fallback and memoization.
  46. *
  47. * @param {ServerRequest} req
  48. * @return {Object}
  49. * @public
  50. */
  51. function originalurl (req) {
  52. var url = req.originalUrl
  53. if (typeof url !== 'string') {
  54. // Fallback
  55. return parseurl(req)
  56. }
  57. var parsed = req._parsedOriginalUrl
  58. if (fresh(url, parsed)) {
  59. // Return cached URL parse
  60. return parsed
  61. }
  62. // Parse the URL
  63. parsed = fastparse(url)
  64. parsed._raw = url
  65. return (req._parsedOriginalUrl = parsed)
  66. };
  67. /**
  68. * Parse the `str` url with fast-path short-cut.
  69. *
  70. * @param {string} str
  71. * @return {Object}
  72. * @private
  73. */
  74. function fastparse (str) {
  75. if (typeof str !== 'string' || str.charCodeAt(0) !== 0x2f /* / */) {
  76. return parse(str)
  77. }
  78. var pathname = str
  79. var query = null
  80. var search = null
  81. // This takes the regexp from https://github.com/joyent/node/pull/7878
  82. // Which is /^(\/[^?#\s]*)(\?[^#\s]*)?$/
  83. // And unrolls it into a for loop
  84. for (var i = 1; i < str.length; i++) {
  85. switch (str.charCodeAt(i)) {
  86. case 0x3f: /* ? */
  87. if (search === null) {
  88. pathname = str.substring(0, i)
  89. query = str.substring(i + 1)
  90. search = str.substring(i)
  91. }
  92. break
  93. case 0x09: /* \t */
  94. case 0x0a: /* \n */
  95. case 0x0c: /* \f */
  96. case 0x0d: /* \r */
  97. case 0x20: /* */
  98. case 0x23: /* # */
  99. case 0xa0:
  100. case 0xfeff:
  101. return parse(str)
  102. }
  103. }
  104. var url = Url !== undefined
  105. ? new Url()
  106. : {}
  107. url.path = str
  108. url.href = str
  109. url.pathname = pathname
  110. url.query = query
  111. url.search = search
  112. return url
  113. }
  114. /**
  115. * Determine if parsed is still fresh for url.
  116. *
  117. * @param {string} url
  118. * @param {object} parsedUrl
  119. * @return {boolean}
  120. * @private
  121. */
  122. function fresh (url, parsedUrl) {
  123. return typeof parsedUrl === 'object' &&
  124. parsedUrl !== null &&
  125. (Url === undefined || parsedUrl instanceof Url) &&
  126. parsedUrl._raw === url
  127. }