1 /*!
2 * parseurl
3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2014 Douglas Christopher Wilson
5 * MIT Licensed
6 */
8 'use strict'
10 /**
11 * Module dependencies.
12 */
14 var url = require('url')
15 var parse = url.parse
16 var Url = url.Url
18 /**
19 * Pattern for a simple path case.
20 * See: https://github.com/joyent/node/pull/7878
21 */
23 var simplePathRegExp = /^(\/\/?(?!\/)[^\?#\s]*)(\?[^#\s]*)?$/
25 /**
26 * Exports.
27 */
29 module.exports = parseurl
30 module.exports.original = originalurl
32 /**
33 * Parse the `req` url with memoization.
34 *
35 * @param {ServerRequest} req
36 * @return {Object}
37 * @api public
38 */
40 function parseurl(req) {
41 var url = req.url
43 if (url === undefined) {
44 // URL is undefined
45 return undefined
46 }
48 var parsed = req._parsedUrl
50 if (fresh(url, parsed)) {
51 // Return cached URL parse
52 return parsed
53 }
55 // Parse the URL
56 parsed = fastparse(url)
57 parsed._raw = url
59 return req._parsedUrl = parsed
60 };
62 /**
63 * Parse the `req` original url with fallback and memoization.
64 *
65 * @param {ServerRequest} req
66 * @return {Object}
67 * @api public
68 */
70 function originalurl(req) {
71 var url = req.originalUrl
73 if (typeof url !== 'string') {
74 // Fallback
75 return parseurl(req)
76 }
78 var parsed = req._parsedOriginalUrl
80 if (fresh(url, parsed)) {
81 // Return cached URL parse
82 return parsed
83 }
85 // Parse the URL
86 parsed = fastparse(url)
87 parsed._raw = url
89 return req._parsedOriginalUrl = parsed
90 };
92 /**
93 * Parse the `str` url with fast-path short-cut.
94 *
95 * @param {string} str
96 * @return {Object}
97 * @api private
98 */
100 function fastparse(str) {
101 // Try fast path regexp
102 // See: https://github.com/joyent/node/pull/7878
103 var simplePath = typeof str === 'string' && simplePathRegExp.exec(str)
105 // Construct simple URL
106 if (simplePath) {
107 var pathname = simplePath[1]
108 var search = simplePath[2] || null
109 var url = Url !== undefined
110 ? new Url()
111 : {}
112 url.path = str
113 url.href = str
114 url.pathname = pathname
115 url.search = search
116 url.query = search && search.substr(1)
118 return url
119 }
121 return parse(str)
122 }
124 /**
125 * Determine if parsed is still fresh for url.
126 *
127 * @param {string} url
128 * @param {object} parsedUrl
129 * @return {boolean}
130 * @api private
131 */
133 function fresh(url, parsedUrl) {
134 return typeof parsedUrl === 'object'
135 && parsedUrl !== null
136 && (Url === undefined || parsedUrl instanceof Url)
137 && parsedUrl._raw === url
138 }