index.js (2809B)
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 }