From: <rb...@us...> - 2018-01-02 19:14:49
|
Revision: 15057 http://sourceforge.net/p/htmlunit/code/15057 Author: rbri Date: 2018-01-02 19:14:46 +0000 (Tue, 02 Jan 2018) Log Message: ----------- URLSearchParams implementation finished (entries(), keys(), values()) URLSearchParams parser fixed (handling of '=' as first char of a part) Issue 1931 Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParams.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParamsTest.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2018-01-01 19:03:26 UTC (rev 15056) +++ trunk/htmlunit/src/changes/changes.xml 2018-01-02 19:14:46 UTC (rev 15057) @@ -7,7 +7,13 @@ </properties> <body> - <release version="2.30" date="xx, 2018" description="Bugfixes"> + <release version="2.30" date="xx, 2018" description="Bugfixes, URLSearchParams implemented"> + <action type="add" dev="rbri"> + JavaScript: URLSearchParams implementation finished (entries(), keys(), values()). + </action> + <action type="fix" dev="rbri"> + JavaScript: URLSearchParams parser fixed (handling of '=' as first char of a part). + </action> <action type="fix" dev="rbri" issue="1944"> JavaScript: Invalid 'Origin' header was sent as part of XMLHttpRequest if the request url was absolute and the page contains a base tag Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParams.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParams.java 2018-01-01 19:03:26 UTC (rev 15056) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParams.java 2018-01-02 19:14:46 UTC (rev 15057) @@ -18,6 +18,7 @@ import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF; import java.util.AbstractMap; +import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -33,6 +34,7 @@ import net.sourceforge.htmlunit.corejs.javascript.Context; import net.sourceforge.htmlunit.corejs.javascript.NativeArray; import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime; +import net.sourceforge.htmlunit.corejs.javascript.Scriptable; import net.sourceforge.htmlunit.corejs.javascript.TopLevel; import net.sourceforge.htmlunit.corejs.javascript.Undefined; @@ -46,6 +48,9 @@ @JsxClass({CHROME, FF}) public class URLSearchParams extends SimpleScriptable { + private static final String ITERATOR_NAME = "URLSearchParamsIterator"; + private static com.gargoylesoftware.htmlunit.javascript.host.Iterator ITERATOR_PROTOTYPE_; + private final List<Entry<String, String>> params_ = new LinkedList<>(); /** @@ -88,7 +93,7 @@ private Entry<String, String> splitQueryParameter(final String singleParam) { final int idx = singleParam.indexOf('='); - if (idx > 0) { + if (idx > -1) { final String key = singleParam.substring(0, idx); String value = null; if (idx < singleParam.length()) { @@ -217,6 +222,69 @@ } /** + * 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 SimpleScriptable object = + new com.gargoylesoftware.htmlunit.javascript.host.Iterator(ITERATOR_NAME, params_.iterator()); + object.setParentScope(getParentScope()); + setIteratorPrototype(object); + return object; + } + + /** + * 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<String> keys = new ArrayList<>(params_.size()); + for (Entry<String, String> entry : params_) { + keys.add(entry.getKey()); + } + + final SimpleScriptable object = + new com.gargoylesoftware.htmlunit.javascript.host.Iterator(ITERATOR_NAME, keys.iterator()); + object.setParentScope(getParentScope()); + setIteratorPrototype(object); + return object; + } + + /** + * 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<String> values = new ArrayList<>(params_.size()); + for (Entry<String, String> entry : params_) { + values.add(entry.getValue()); + } + + final SimpleScriptable object = + new com.gargoylesoftware.htmlunit.javascript.host.Iterator(ITERATOR_NAME, values.iterator()); + object.setParentScope(getParentScope()); + setIteratorPrototype(object); + return object; + } + + private static void setIteratorPrototype(final Scriptable scriptable) { + if (ITERATOR_PROTOTYPE_ == null) { + ITERATOR_PROTOTYPE_ = new com.gargoylesoftware.htmlunit.javascript.host.Iterator(ITERATOR_NAME, null); + } + scriptable.setPrototype(ITERATOR_PROTOTYPE_); + } + + /** * Calls for instance for implicit conversion to string. * @see com.gargoylesoftware.htmlunit.javascript.SimpleScriptable#getDefaultValue(java.lang.Class) * @param hint the type hint Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParamsTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParamsTest.java 2018-01-01 19:03:26 UTC (rev 15056) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/URLSearchParamsTest.java 2018-01-02 19:14:46 UTC (rev 15057) @@ -14,6 +14,7 @@ */ package com.gargoylesoftware.htmlunit.javascript.host; +import static com.gargoylesoftware.htmlunit.BrowserRunner.TestedBrowser.CHROME; import static com.gargoylesoftware.htmlunit.BrowserRunner.TestedBrowser.FF45; import org.junit.Test; @@ -251,4 +252,133 @@ + "</html>"; loadPageWithAlerts2(html); } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = {"function keys() { [native code] }", "[object Iterator]", + "key1", "key2", "key1", "", "true"}, + FF = {"function keys() {\n [native code]\n}", "[object URLSearchParamsIterator]", + "key1", "key2", "key1", "", "true"}, + IE = {}) + @NotYetImplemented(CHROME) + public void keys() throws Exception { + final String html = + "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (self.URLSearchParams) {\n" + + " var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n" + + + " alert(param.keys);\n" + + " var iter = param.keys();\n" + + " alert(iter);\n" + + + " var entry = iter.next().value;\n" + + " alert(entry);\n" + + " entry = iter.next().value;\n" + + " alert(entry);\n" + + " entry = iter.next().value;\n" + + " alert(entry);\n" + + " entry = iter.next().value;\n" + + " alert(entry);\n" + + + " alert(iter.next().done);\n" + + " }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='test()'>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = {"function values() { [native code] }", "[object Iterator]", + "val1", "", "val3", "val4", "true"}, + FF = {"function values() {\n [native code]\n}", "[object URLSearchParamsIterator]", + "val1", "", "val3", "val4", "true"}, + IE = {}) + @NotYetImplemented(CHROME) + public void values() throws Exception { + final String html = + "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (self.URLSearchParams) {\n" + + " var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n" + + + " alert(param.values);\n" + + " var iter = param.values();\n" + + " alert(iter);\n" + + + " var entry = iter.next().value;\n" + + " alert(entry);\n" + + " entry = iter.next().value;\n" + + " alert(entry);\n" + + " entry = iter.next().value;\n" + + " alert(entry);\n" + + " entry = iter.next().value;\n" + + " alert(entry);\n" + + + " alert(iter.next().done);\n" + + " }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='test()'>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html, 666666); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = {"function entries() { [native code] }", "[object Iterator]", + "key1-val1", "key2-", "key1-val3", "-val4", "true"}, + FF = {"function entries() {\n [native code]\n}", "[object URLSearchParamsIterator]", + "key1-val1", "key2-", "key1-val3", "-val4", "true"}, + IE = {}) + @NotYetImplemented(CHROME) + public void entries() throws Exception { + final String html = + "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (self.URLSearchParams) {\n" + + " var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n" + + + " alert(param.entries);\n" + + " var iter = param.entries();\n" + + " alert(iter);\n" + + + " var entry = iter.next().value;\n" + + " alert(entry[0] + '-' + entry[1]);\n" + + " entry = iter.next().value;\n" + + " alert(entry[0] + '-' + entry[1]);\n" + + " entry = iter.next().value;\n" + + " alert(entry[0] + '-' + entry[1]);\n" + + " entry = iter.next().value;\n" + + " alert(entry[0] + '-' + entry[1]);\n" + + + " alert(iter.next().done);\n" + + " }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='test()'>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } } |