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