Skip to content
Snippets Groups Projects
index.js 2.74 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jay's avatar
    Jay committed
    /*!
     * 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
    }