diff --git a/jetty-websocket/jetty-websocket-api/src/main/java/org/eclipse/jetty/websocket/api/FrameCallback.java b/jetty-websocket/jetty-websocket-api/src/main/java/org/eclipse/jetty/websocket/api/FrameCallback.java deleted file mode 100644 index 1aaf5501e17..00000000000 --- a/jetty-websocket/jetty-websocket-api/src/main/java/org/eclipse/jetty/websocket/api/FrameCallback.java +++ /dev/null @@ -1,53 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket.api; - -public interface FrameCallback -{ - /** - *

- * Callback invoked when the frame fails. - *

- * - * @param cause the reason for the frame failure - */ - void fail(Throwable cause); - - /** - *

- * Callback invoked when the frame read/write completes. - *

- * - * @see #fail(Throwable) - */ - void succeed(); - - class Adapter implements FrameCallback - { - @Override - public void fail(Throwable cause) - { - } - - @Override - public void succeed() - { - } - } -} diff --git a/jetty-websocket/jetty-websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java b/jetty-websocket/jetty-websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java deleted file mode 100644 index 27d7e1e83c8..00000000000 --- a/jetty-websocket/jetty-websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java +++ /dev/null @@ -1,493 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket.api.util; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Provide some consistent Http header value and Extension configuration parameter quoting support. - *

- * While QuotedStringTokenizer exists in jetty-util, and works great with http header values, using it in websocket-api is undesired. - *

- * It was decided to keep this implementation separate for the above reasons. - */ -public class QuoteUtil -{ - private static class DeQuotingStringIterator implements Iterator - { - private enum State - { - START, - TOKEN, - QUOTE_SINGLE, - QUOTE_DOUBLE - } - - private final String input; - private final String delims; - private StringBuilder token; - private boolean hasToken = false; - private int i = 0; - - public DeQuotingStringIterator(String input, String delims) - { - this.input = input; - this.delims = delims; - int len = input.length(); - token = new StringBuilder(len > 1024?512:len / 2); - } - - private void appendToken(char c) - { - if (hasToken) - { - token.append(c); - } - else - { - if (Character.isWhitespace(c)) - { - return; // skip whitespace at start of token. - } - else - { - token.append(c); - hasToken = true; - } - } - } - - @Override - public boolean hasNext() - { - // already found a token - if (hasToken) - { - return true; - } - - State state = State.START; - boolean escape = false; - int inputLen = input.length(); - - while (i < inputLen) - { - char c = input.charAt(i++); - - switch (state) - { - case START: - { - if (c == '\'') - { - state = State.QUOTE_SINGLE; - appendToken(c); - } - else if (c == '\"') - { - state = State.QUOTE_DOUBLE; - appendToken(c); - } - else - { - appendToken(c); - state = State.TOKEN; - } - break; - } - case TOKEN: - { - if (delims.indexOf(c) >= 0) - { - // System.out.printf("hasNext/t: %b [%s]%n",hasToken,token); - return hasToken; - } - else if (c == '\'') - { - state = State.QUOTE_SINGLE; - } - else if (c == '\"') - { - state = State.QUOTE_DOUBLE; - } - appendToken(c); - break; - } - case QUOTE_SINGLE: - { - if (escape) - { - escape = false; - appendToken(c); - } - else if (c == '\'') - { - appendToken(c); - state = State.TOKEN; - } - else if (c == '\\') - { - escape = true; - } - else - { - appendToken(c); - } - break; - } - case QUOTE_DOUBLE: - { - if (escape) - { - escape = false; - appendToken(c); - } - else if (c == '\"') - { - appendToken(c); - state = State.TOKEN; - } - else if (c == '\\') - { - escape = true; - } - else - { - appendToken(c); - } - break; - } - } - // System.out.printf("%s <%s> : [%s]%n",state,c,token); - } - // System.out.printf("hasNext/e: %b [%s]%n",hasToken,token); - return hasToken; - } - - @Override - public String next() - { - if (!hasNext()) - { - throw new NoSuchElementException(); - } - String ret = token.toString(); - token.setLength(0); - hasToken = false; - return QuoteUtil.dequote(ret.trim()); - } - - @Override - public void remove() - { - throw new UnsupportedOperationException("Remove not supported with this iterator"); - } - } - - /** - * ABNF from RFC 2616, RFC 822, and RFC 6455 specified characters requiring quoting. - */ - public static final String ABNF_REQUIRED_QUOTING = "\"'\\\n\r\t\f\b%+ ;="; - - private static final char UNICODE_TAG = 0xFFFF; - private static final char[] escapes = new char[32]; - - static - { - Arrays.fill(escapes, UNICODE_TAG); - // non-unicode - escapes['\b'] = 'b'; - escapes['\t'] = 't'; - escapes['\n'] = 'n'; - escapes['\f'] = 'f'; - escapes['\r'] = 'r'; - } - - private static int dehex(byte b) - { - if ((b >= '0') && (b <= '9')) - { - return (byte)(b - '0'); - } - if ((b >= 'a') && (b <= 'f')) - { - return (byte)((b - 'a') + 10); - } - if ((b >= 'A') && (b <= 'F')) - { - return (byte)((b - 'A') + 10); - } - throw new IllegalArgumentException("!hex:" + Integer.toHexString(0xff & b)); - } - - /** - * Remove quotes from a string, only if the input string start with and end with the same quote character. - * - * @param str the string to remove surrounding quotes from - * @return the de-quoted string - */ - public static String dequote(String str) - { - char start = str.charAt(0); - if ((start == '\'') || (start == '\"')) - { - // possibly quoted - char end = str.charAt(str.length() - 1); - if (start == end) - { - // dequote - return str.substring(1, str.length() - 1); - } - } - return str; - } - - public static void escape(StringBuilder buf, String str) - { - for (char c : str.toCharArray()) - { - if (c >= 32) - { - // non special character - if ((c == '"') || (c == '\\')) - { - buf.append('\\'); - } - buf.append(c); - } - else - { - // special characters, requiring escaping - char escaped = escapes[c]; - - // is this a unicode escape? - if (escaped == UNICODE_TAG) - { - buf.append("\\u00"); - if (c < 0x10) - { - buf.append('0'); - } - buf.append(Integer.toString(c, 16)); // hex - } - else - { - // normal escape - buf.append('\\').append(escaped); - } - } - } - } - - /** - * Simple quote of a string, escaping where needed. - * - * @param buf the StringBuilder to append to - * @param str the string to quote - */ - public static void quote(StringBuilder buf, String str) - { - buf.append('"'); - escape(buf, str); - buf.append('"'); - } - - /** - * Append into buf the provided string, adding quotes if needed. - *

- * Quoting is determined if any of the characters in the {@code delim} are found in the input {@code str}. - * - * @param buf the buffer to append to - * @param str the string to possibly quote - * @param delim the delimiter characters that will trigger automatic quoting - */ - public static void quoteIfNeeded(StringBuilder buf, String str, String delim) - { - if (str == null) - { - return; - } - // check for delimiters in input string - int len = str.length(); - if (len == 0) - { - return; - } - int ch; - for (int i = 0; i < len; i++) - { - ch = str.codePointAt(i); - if (delim.indexOf(ch) >= 0) - { - // found a delimiter codepoint. we need to quote it. - quote(buf, str); - return; - } - } - - // no special delimiters used, no quote needed. - buf.append(str); - } - - /** - * Create an iterator of the input string, breaking apart the string at the provided delimiters, removing quotes and triming the parts of the string as - * needed. - * - * @param str the input string to split apart - * @param delims the delimiter characters to split the string on - * @return the iterator of the parts of the string, trimmed, with quotes around the string part removed, and unescaped - */ - public static Iterator splitAt(String str, String delims) - { - return new DeQuotingStringIterator(str.trim(), delims); - } - - public static String unescape(String str) - { - if (str == null) - { - // nothing there - return null; - } - - int len = str.length(); - if (len <= 1) - { - // impossible to be escaped - return str; - } - - StringBuilder ret = new StringBuilder(len - 2); - boolean escaped = false; - char c; - for (int i = 0; i < len; i++) - { - c = str.charAt(i); - if (escaped) - { - escaped = false; - switch (c) - { - case 'n': - ret.append('\n'); - break; - case 'r': - ret.append('\r'); - break; - case 't': - ret.append('\t'); - break; - case 'f': - ret.append('\f'); - break; - case 'b': - ret.append('\b'); - break; - case '\\': - ret.append('\\'); - break; - case '/': - ret.append('/'); - break; - case '"': - ret.append('"'); - break; - case 'u': - ret.append( - (char)((dehex((byte)str.charAt(i++)) << 24) + (dehex((byte)str.charAt(i++)) << 16) + (dehex((byte)str.charAt(i++)) << 8) + (dehex( - (byte)str - .charAt(i++))))); - break; - default: - ret.append(c); - } - } - else if (c == '\\') - { - escaped = true; - } - else - { - ret.append(c); - } - } - return ret.toString(); - } - - public static String join(Object[] objs, String delim) - { - if (objs == null) - { - return ""; - } - StringBuilder ret = new StringBuilder(); - int len = objs.length; - for (int i = 0; i < len; i++) - { - if (i > 0) - { - ret.append(delim); - } - if (objs[i] instanceof String) - { - ret.append('"').append(objs[i]).append('"'); - } - else - { - ret.append(objs[i]); - } - } - return ret.toString(); - } - - public static String join(Collection objs, String delim) - { - if (objs == null) - { - return ""; - } - StringBuilder ret = new StringBuilder(); - boolean needDelim = false; - for (Object obj : objs) - { - if (needDelim) - { - ret.append(delim); - } - if (obj instanceof String) - { - ret.append('"').append(obj).append('"'); - } - else - { - ret.append(obj); - } - needDelim = true; - } - return ret.toString(); - } -} diff --git a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/util/QuoteUtilTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/util/QuoteUtilTest.java deleted file mode 100644 index ad7a73efe56..00000000000 --- a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/util/QuoteUtilTest.java +++ /dev/null @@ -1,157 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket.tests.util; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -import org.eclipse.jetty.websocket.api.util.QuoteUtil; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * Test QuoteUtil - */ -public class QuoteUtilTest -{ - private void assertSplitAt(Iterator iter, String... expectedParts) - { - int len = expectedParts.length; - for (int i = 0; i < len; i++) - { - String expected = expectedParts[i]; - assertThat("Split[" + i + "].hasNext()", iter.hasNext(), is(true)); - assertThat("Split[" + i + "].next()", iter.next(), is(expected)); - } - } - - @Test - public void testSplitAt_PreserveQuoting() - { - Iterator iter = QuoteUtil.splitAt("permessage-compress; method=\"foo, bar\"", ";"); - assertSplitAt(iter, "permessage-compress", "method=\"foo, bar\""); - } - - @Test - public void testSplitAt_PreserveQuotingWithNestedDelim() - { - Iterator iter = QuoteUtil.splitAt("permessage-compress; method=\"foo; x=10\"", ";"); - assertSplitAt(iter, "permessage-compress", "method=\"foo; x=10\""); - } - - @Test - public void testSplitAtAllWhitespace() - { - Iterator iter = QuoteUtil.splitAt(" ", "="); - assertThat("Has Next", iter.hasNext(), is(false)); - assertThrows(NoSuchElementException.class, () -> iter.next()); - } - - @Test - public void testSplitAtEmpty() - { - Iterator iter = QuoteUtil.splitAt("", "="); - assertThat("Has Next", iter.hasNext(), is(false)); - assertThrows(NoSuchElementException.class, () -> iter.next()); - } - - @Test - public void testSplitAtHelloWorld() - { - Iterator iter = QuoteUtil.splitAt("Hello World", " ="); - assertSplitAt(iter, "Hello", "World"); - } - - @Test - public void testSplitAtKeyValue_Message() - { - Iterator iter = QuoteUtil.splitAt("method=\"foo, bar\"", "="); - assertSplitAt(iter, "method", "foo, bar"); - } - - @Test - public void testSplitAtQuotedDelim() - { - // test that split ignores delimiters that occur within a quoted - // part of the sequence. - Iterator iter = QuoteUtil.splitAt("A,\"B,C\",D", ","); - assertSplitAt(iter, "A", "B,C", "D"); - } - - @Test - public void testSplitAtSimple() - { - Iterator iter = QuoteUtil.splitAt("Hi", "="); - assertSplitAt(iter, "Hi"); - } - - @Test - public void testSplitKeyValue_Quoted() - { - Iterator iter = QuoteUtil.splitAt("Key = \"Value\"", "="); - assertSplitAt(iter, "Key", "Value"); - } - - @Test - public void testSplitKeyValue_QuotedValueList() - { - Iterator iter = QuoteUtil.splitAt("Fruit = \"Apple, Banana, Cherry\"", "="); - assertSplitAt(iter, "Fruit", "Apple, Banana, Cherry"); - } - - @Test - public void testSplitKeyValue_QuotedWithDelim() - { - Iterator iter = QuoteUtil.splitAt("Key = \"Option=Value\"", "="); - assertSplitAt(iter, "Key", "Option=Value"); - } - - @Test - public void testSplitKeyValue_Simple() - { - Iterator iter = QuoteUtil.splitAt("Key=Value", "="); - assertSplitAt(iter, "Key", "Value"); - } - - @Test - public void testSplitKeyValue_WithWhitespace() - { - Iterator iter = QuoteUtil.splitAt("Key = Value", "="); - assertSplitAt(iter, "Key", "Value"); - } - - @Test - public void testQuoteIfNeeded() - { - StringBuilder buf = new StringBuilder(); - QuoteUtil.quoteIfNeeded(buf, "key", ","); - assertThat("key", buf.toString(), is("key")); - } - - @Test - public void testQuoteIfNeeded_null() - { - StringBuilder buf = new StringBuilder(); - QuoteUtil.quoteIfNeeded(buf, null, ";="); - assertThat("", buf.toString(), is("")); - } -} diff --git a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/util/QuoteUtil_QuoteTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/util/QuoteUtil_QuoteTest.java deleted file mode 100644 index 41cb797fc6d..00000000000 --- a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/util/QuoteUtil_QuoteTest.java +++ /dev/null @@ -1,73 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket.tests.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; - -import org.eclipse.jetty.websocket.api.util.QuoteUtil; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * Test QuoteUtil.quote(), and QuoteUtil.dequote() - */ -public class QuoteUtil_QuoteTest -{ - public static Stream data() - { - // The various quoting of a String - List data = new ArrayList<>(); - - data.add(new Object[] { "Hi", "\"Hi\"" }); - data.add(new Object[] { "Hello World", "\"Hello World\"" }); - data.add(new Object[] { "9.0.0", "\"9.0.0\"" }); - data.add(new Object[] { "Something \"Special\"", - "\"Something \\\"Special\\\"\"" }); - data.add(new Object[] { "A Few\n\"Good\"\tMen", - "\"A Few\\n\\\"Good\\\"\\tMen\"" }); - - return data.stream().map(Arguments::of); - } - - @ParameterizedTest - @MethodSource("data") - public void testDequoting(final String unquoted, final String quoted) - { - String actual = QuoteUtil.dequote(quoted); - actual = QuoteUtil.unescape(actual); - assertThat(actual, is(unquoted)); - } - - @ParameterizedTest - @MethodSource("data") - public void testQuoting(final String unquoted, final String quoted) - { - StringBuilder buf = new StringBuilder(); - QuoteUtil.quote(buf, unquoted); - - String actual = buf.toString(); - assertThat(actual, is(quoted)); - } -}