| /*! |
| * parseurl |
| * Copyright(c) 2014 Jonathan Ong |
| * Copyright(c) 2014-2017 Douglas Christopher Wilson |
| * MIT Licensed |
| */ |
| |
| 'use strict' |
| |
| /** |
| * Module dependencies. |
| * @private |
| */ |
| |
| var url = require('url') |
| var parse = url.parse |
| var Url = url.Url |
| |
| /** |
| * Module exports. |
| * @public |
| */ |
| |
| module.exports = parseurl |
| module.exports.original = originalurl |
| |
| /** |
| * Parse the `req` url with memoization. |
| * |
| * @param {ServerRequest} req |
| * @return {Object} |
| * @public |
| */ |
| |
| function parseurl (req) { |
| var url = req.url |
| |
| if (url === undefined) { |
| // URL is undefined |
| return undefined |
| } |
| |
| var parsed = req._parsedUrl |
| |
| if (fresh(url, parsed)) { |
| // Return cached URL parse |
| return parsed |
| } |
| |
| // Parse the URL |
| parsed = fastparse(url) |
| parsed._raw = url |
| |
| return (req._parsedUrl = parsed) |
| }; |
| |
| /** |
| * Parse the `req` original url with fallback and memoization. |
| * |
| * @param {ServerRequest} req |
| * @return {Object} |
| * @public |
| */ |
| |
| function originalurl (req) { |
| var url = req.originalUrl |
| |
| if (typeof url !== 'string') { |
| // Fallback |
| return parseurl(req) |
| } |
| |
| var parsed = req._parsedOriginalUrl |
| |
| if (fresh(url, parsed)) { |
| // Return cached URL parse |
| return parsed |
| } |
| |
| // Parse the URL |
| parsed = fastparse(url) |
| parsed._raw = url |
| |
| return (req._parsedOriginalUrl = parsed) |
| }; |
| |
| /** |
| * Parse the `str` url with fast-path short-cut. |
| * |
| * @param {string} str |
| * @return {Object} |
| * @private |
| */ |
| |
| function fastparse (str) { |
| if (typeof str !== 'string' || str.charCodeAt(0) !== 0x2f /* / */) { |
| return parse(str) |
| } |
| |
| var pathname = str |
| var query = null |
| var search = null |
| |
| // This takes the regexp from https://github.com/joyent/node/pull/7878 |
| // Which is /^(\/[^?#\s]*)(\?[^#\s]*)?$/ |
| // And unrolls it into a for loop |
| for (var i = 1; i < str.length; i++) { |
| switch (str.charCodeAt(i)) { |
| case 0x3f: /* ? */ |
| if (search === null) { |
| pathname = str.substring(0, i) |
| query = str.substring(i + 1) |
| search = str.substring(i) |
| } |
| break |
| case 0x09: /* \t */ |
| case 0x0a: /* \n */ |
| case 0x0c: /* \f */ |
| case 0x0d: /* \r */ |
| case 0x20: /* */ |
| case 0x23: /* # */ |
| case 0xa0: |
| case 0xfeff: |
| return parse(str) |
| } |
| } |
| |
| var url = Url !== undefined |
| ? new Url() |
| : {} |
| |
| url.path = str |
| url.href = str |
| url.pathname = pathname |
| |
| if (search !== null) { |
| url.query = query |
| url.search = search |
| } |
| |
| return url |
| } |
| |
| /** |
| * Determine if parsed is still fresh for url. |
| * |
| * @param {string} url |
| * @param {object} parsedUrl |
| * @return {boolean} |
| * @private |
| */ |
| |
| function fresh (url, parsedUrl) { |
| return typeof parsedUrl === 'object' && |
| parsedUrl !== null && |
| (Url === undefined || parsedUrl instanceof Url) && |
| parsedUrl._raw === url |
| } |