
org.htmlunit.javascript.host.URLSearchParams Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xlt Show documentation
Show all versions of xlt Show documentation
XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.
/*
* Copyright (c) 2002-2023 Gargoyle Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.htmlunit.javascript.host;
import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.htmlunit.FormEncodingType;
import org.htmlunit.WebRequest;
import org.htmlunit.javascript.HtmlUnitScriptable;
import org.htmlunit.javascript.configuration.JsxClass;
import org.htmlunit.javascript.configuration.JsxConstructor;
import org.htmlunit.javascript.configuration.JsxFunction;
import org.htmlunit.util.NameValuePair;
import org.htmlunit.util.UrlUtils;
import org.htmlunit.corejs.javascript.Context;
import org.htmlunit.corejs.javascript.ES6Iterator;
import org.htmlunit.corejs.javascript.Function;
import org.htmlunit.corejs.javascript.ScriptRuntime;
import org.htmlunit.corejs.javascript.Scriptable;
import org.htmlunit.corejs.javascript.ScriptableObject;
import org.htmlunit.corejs.javascript.Undefined;
/**
* A JavaScript object for {@code URLSearchParams}.
*
* @author Ahmed Ashour
* @author Ronald Brill
* @author Ween Jiann
* @author cd alexndr
* @author Lai Quang Duong
*/
@JsxClass({CHROME, EDGE, FF, FF_ESR})
public class URLSearchParams extends HtmlUnitScriptable {
private static final Log LOG = LogFactory.getLog(URLSearchParams.class);
/** Constant used to register the prototype in the context. */
public static final String URL_SEARCH_PARMS_TAG = "URLSearchParams";
private final URL url_;
public static final class NativeParamsIterator extends ES6Iterator {
private final Type type_;
private final String className_;
private final transient Iterator iterator_;
enum Type { KEYS, VALUES, BOTH }
public static void init(final ScriptableObject scope, final String className) {
ES6Iterator.init(scope, false, new NativeParamsIterator(className), URL_SEARCH_PARMS_TAG);
}
public NativeParamsIterator(final String className) {
iterator_ = Collections.emptyIterator();
type_ = Type.BOTH;
className_ = className;
}
public NativeParamsIterator(final Scriptable scope, final String className, final Type type,
final Iterator iterator) {
super(scope, URL_SEARCH_PARMS_TAG);
iterator_ = iterator;
type_ = type;
className_ = className;
}
@Override
public String getClassName() {
return className_;
}
@Override
protected boolean isDone(final Context cx, final Scriptable scope) {
return !iterator_.hasNext();
}
@Override
protected Object nextValue(final Context cx, final Scriptable scope) {
final NameValuePair e = iterator_.next();
switch (type_) {
case KEYS:
return e.getName();
case VALUES:
return e.getValue();
case BOTH:
return cx.newArray(scope, new Object[] {e.getName(), e.getValue()});
default:
throw new AssertionError();
}
}
}
/**
* Constructs a new instance.
*/
public URLSearchParams() {
url_ = null;
}
/**
* Constructs a new instance for the given js url.
* @param url the base url
*/
URLSearchParams(final URL url) {
url_ = url;
}
/**
* Constructs a new instance.
* @param params the params string
*/
@JsxConstructor
public URLSearchParams(final Object params) {
// TODO: Pass in a sequence
// new URLSearchParams([["foo", 1],["bar", 2]]);
// TODO: Pass in a record
// new URLSearchParams({"foo" : 1 , "bar" : 2});
url_ = new URL("http://www.htmlunit.org", "");
if (params == null || Undefined.isUndefined(params)) {
return;
}
try {
url_.setSearch(splitQuery(Context.toString(params)));
}
catch (final MalformedURLException e) {
LOG.error(e.getMessage(), e);
}
}
private List splitQuery() {
return splitQuery(url_.getSearch());
}
private static List splitQuery(String params) {
final List splitted = new ArrayList<>();
params = StringUtils.stripStart(params, "?");
if (StringUtils.isEmpty(params)) {
return splitted;
}
final String[] parts = StringUtils.split(params, '&');
for (final String part : parts) {
final NameValuePair pair = splitQueryParameter(part);
splitted.add(new NameValuePair(UrlUtils.decode(pair.getName()), UrlUtils.decode(pair.getValue())));
}
return splitted;
}
private static NameValuePair splitQueryParameter(final String singleParam) {
final int idx = singleParam.indexOf('=');
if (idx > -1) {
final String key = singleParam.substring(0, idx);
String value = null;
if (idx < singleParam.length()) {
value = singleParam.substring(idx + 1);
}
return new NameValuePair(key, value);
}
final String value = "";
return new NameValuePair(singleParam, value);
}
/**
* The append() method of the URLSearchParams interface appends a specified
* key/value pair as a new search parameter.
*
* @param name The name of the parameter to append.
* @param value The value of the parameter to append.
*/
@JsxFunction
public void append(final String name, final String value) {
final String search = url_.getSearch();
final List pairs;
if (search == null || search.isEmpty()) {
pairs = new ArrayList<>(1);
}
else {
pairs = splitQuery(search);
}
pairs.add(new NameValuePair(name, value));
try {
url_.setSearch(pairs);
}
catch (final MalformedURLException e) {
LOG.error(e.getMessage(), e);
}
}
/**
* The delete() method of the URLSearchParams interface deletes the given search
* parameter and its associated value, from the list of all search parameters.
*
* @param name The name of the parameter to be deleted.
*/
@JsxFunction
@Override
public void delete(final String name) {
final List splitted = splitQuery();
splitted.removeIf(entry -> entry.getName().equals(name));
if (splitted.size() == 0) {
try {
url_.setSearch((String) null);
}
catch (final MalformedURLException e) {
LOG.error(e.getMessage(), e);
}
return;
}
try {
url_.setSearch(splitted);
}
catch (final MalformedURLException e) {
LOG.error(e.getMessage(), e);
}
}
/**
* The get() method of the URLSearchParams interface returns the
* first value associated to the given search parameter.
*
* @param name The name of the parameter to return.
* @return An array of USVStrings.
*/
@JsxFunction
public String get(final String name) {
final List splitted = splitQuery();
for (final NameValuePair param : splitted) {
if (param.getName().equals(name)) {
return param.getValue();
}
}
return null;
}
/**
* The getAll() method of the URLSearchParams interface returns all the values
* associated with a given search parameter as an array.
*
* @param name The name of the parameter to return.
* @return An array of USVStrings.
*/
@JsxFunction
public Scriptable getAll(final String name) {
final List splitted = splitQuery();
final List result = new ArrayList<>(splitted.size());
for (final NameValuePair param : splitted) {
if (param.getName().equals(name)) {
result.add(param.getValue());
}
}
return Context.getCurrentContext().newArray(getWindow(this), result.toArray());
}
/**
* The set() method of the URLSearchParams interface sets the value associated with a
* given search parameter to the given value. If there were several matching values,
* this method deletes the others. If the search parameter doesn't exist, this method
* creates it.
*
* @param name The name of the parameter to set.
* @param value The value of the parameter to set.
*/
@JsxFunction
public void set(final String name, final String value) {
final List splitted = splitQuery();
boolean change = true;
final ListIterator iter = splitted.listIterator();
while (iter.hasNext()) {
final NameValuePair entry = iter.next();
if (entry.getName().equals(name)) {
if (change) {
iter.set(new NameValuePair(name, value));
change = false;
}
else {
iter.remove();
}
}
}
if (change) {
splitted.add(new NameValuePair(name, value));
}
try {
url_.setSearch(splitted);
}
catch (final MalformedURLException e) {
LOG.error(e.getMessage(), e);
}
}
/**
* The has() method of the URLSearchParams interface returns a Boolean that
* indicates whether a parameter with the specified name exists.
*
* @param name The name of the parameter to find.
* @return A Boolean.
*/
@JsxFunction
public boolean has(final String name) {
final List splitted = splitQuery();
for (final NameValuePair param : splitted) {
if (param.getName().equals(name)) {
return true;
}
}
return false;
}
/**
* The URLSearchParams.forEach() method allows iteration through
* all key/value pairs contained in this object via a callback function.
* @param callback Function to execute on each key/value pairs
*/
@JsxFunction
public void forEach(final Object callback) {
if (!(callback instanceof Function)) {
throw ScriptRuntime.typeError(
"Foreach callback '" + ScriptRuntime.toString(callback) + "' is not a function");
}
final Function fun = (Function) callback;
String currentSearch = null;
List params = null;
// This must be indexes instead of iterator() for correct behavior when of list changes while iterating
for (int i = 0;; i++) {
final String search = url_.getSearch();
if (!search.equals(currentSearch)) {
params = splitQuery(search);
currentSearch = search;
}
if (i >= params.size()) {
break;
}
final NameValuePair param = params.get(i);
fun.call(Context.getCurrentContext(), getParentScope(), this,
new Object[] {param.getValue(), param.getName(), this});
}
}
/**
* The URLSearchParams.entries() method returns an iterator allowing to go through
* all key/value pairs contained in this object. The key and value of each pair
* are USVString objects.
*
* @return an iterator.
*/
@JsxFunction
public Object entries() {
final List splitted = splitQuery();
return new NativeParamsIterator(getParentScope(),
"URLSearchParams Iterator", NativeParamsIterator.Type.BOTH, splitted.iterator());
}
/**
* The URLSearchParams.keys() method returns an iterator allowing to go through
* all keys contained in this object. The keys are USVString objects.
*
* @return an iterator.
*/
@JsxFunction
public Object keys() {
final List splitted = splitQuery();
return new NativeParamsIterator(getParentScope(),
"URLSearchParams Iterator", NativeParamsIterator.Type.KEYS, splitted.iterator());
}
/**
* The URLSearchParams.values() method returns an iterator allowing to go through
* all values contained in this object. The values are USVString objects.
*
* @return an iterator.
*/
@JsxFunction
public Object values() {
final List splitted = splitQuery();
return new NativeParamsIterator(getParentScope(),
"URLSearchParams Iterator", NativeParamsIterator.Type.VALUES, splitted.iterator());
}
/**
* Returns the text of the Range.
* @return the text
*/
@JsxFunction(functionName = "toString")
public String jsToString() {
final StringBuilder newSearch = new StringBuilder();
for (final NameValuePair nameValuePair : splitQuery(url_.getSearch())) {
if (newSearch.length() > 0) {
newSearch.append('&');
}
newSearch
.append(UrlUtils.encodeQueryPart(nameValuePair.getName()))
.append('=')
.append(UrlUtils.encodeQueryPart(nameValuePair.getValue()));
}
return newSearch.toString();
}
/**
* Calls for instance for implicit conversion to string.
* @see org.htmlunit.javascript.HtmlUnitScriptable#getDefaultValue(java.lang.Class)
* @param hint the type hint
* @return the default value
*/
@Override
public Object getDefaultValue(final Class> hint) {
return jsToString();
}
/**
* Sets the specified request with the parameters in this {@code FormData}.
* @param webRequest the web request to fill
*/
public void fillRequest(final WebRequest webRequest) {
webRequest.setRequestBody(null);
webRequest.setEncodingType(FormEncodingType.URL_ENCODED);
final List splitted = splitQuery();
if (splitted.size() > 0) {
final List params = new ArrayList<>();
for (final NameValuePair entry : splitted) {
params.add(new NameValuePair(entry.getName(), entry.getValue()));
}
webRequest.setRequestParameters(params);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy