net/request.js

/**
 * @fileoverview Simple implementation of
 *               <code>javax.servlet.ServletRequest.</code> and
 *               <code>javax.servlet.http.HttpServletRequest</code>.
 *
 * @see https://google.github.io/styleguide/javascriptguide.xml
 * @see https://developers.google.com/closure/compiler/docs/js-for-compiler
 * @see https://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequest.html
 * @see https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html
 * @module glize/net/requests
 * @requires glize/dom/cookies
 * @requires glize/utils/number
 */

import { cookies } from '../dom/index.js';
import { uint32 } from '../utils/number.js';

/**
 * Returns the query string that is contained in the request URL after the
 *     path.
 * @param {?Element|?Location|?URL|string=} opt_location Optional location object.
 * @return {string} Returns the query string that is contained in the request
 *     URL after the path.
 * @method
 */
export const getQueryString = (opt_location) => {
  opt_location = getLocation_(opt_location);
  return opt_location.search && opt_location.search.substr(1);
};

/**
 * Returns an <code>Array</code> of all the cookies included
 *    with this request.
 * @return {!Array<!Object>} Returns an <code>Array</code> of all the cookies
 *     included with this request.
 * @method
 */
export const getCookies = function() {
  const keys = cookies.keys();
  const length = uint32(keys.length);
  const result = [];

  for (let i = 0; i < length;) {
    const name = keys[i++];
    result[i] = {'name': name, 'value': cookies.get(name)};
  }

  return result;
};

/**
 * Returns the value of a request parameter as a <code>string</code>, or empty
 * <code>string</code> if the parameter does not exist.
 * @param {string} name A <code>string</code> specifying the name of the
 *     parameter.
 * @param {?Element|?Location|string=} opt_location Optional location object.
 * @return {string} Returns a <code>string</code> representing the single
 *     value of the parameter.
 * @method
 */
export const getParameter = (name, opt_location) => {
  const map = getParameterMap(opt_location);
  return map[name] || '';
};

/**
 * @param {?Element|?Location|string=} opt_location Optional location object.
 * @return {!Array<string>} Returns an <code>Array</code> of
 * <code>string</code> objects, each <code>string</code> containing the name
 * of a request parameter; or an empty <code>Array</code> if the request has
 * no parameters.
 * @method
 */
export const getParameterNames = (opt_location) => {
  const map = getParameterMap(opt_location);
  return Object.keys(map);
};

/**
 * Returns a map of the parameters of this request including parameters from
 * parsed from query string and hash.
 * @param {?Element|?Location|?URL|string=} opt_location Optional location.
 * @return {!Object<string, string>} Map containing parameter names as keys
 *     and parameter values as map values.
 * @method
 */
export const getParameterMap = (opt_location) => {
  opt_location = getLocation_(opt_location);
  const url = opt_location.toString();
  const map = {};

  if (!(url in maps_)) {
    const pairs = opt_location.search.substr(1).split('&').concat(
        opt_location.hash.substr(1).split('&'));
    let index = uint32(pairs.length);
    while (index--) {
      const pair = pairs[index].split('=');
      const key = pair[0];
      if (key) map[key] = decodeURIComponent(pair[1]);
    }
    maps_[url] = map;
  }

  return maps_[url];
};

/**
 * @param {?Element|?Location|?URL|string=} opt_location Optional location.
 * @return {!URL}
 * @method
 * @private
 */
const getLocation_ = (opt_location) => {
  opt_location = opt_location || location;

  if ('string' === typeof opt_location) {
    opt_location = new URL(opt_location);
  }

  return /** @type {!URL} */ (opt_location);
};

/**
 * Cache for parsed parameters maps.
 * @type {!Object<string, !Object<string,string>>}
 * @private
 */
const maps_ = {};