init
This commit is contained in:
112
test/org/apache/tomcat/util/TestIntrospectionUtils.java
Normal file
112
test/org/apache/tomcat/util/TestIntrospectionUtils.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
|
||||
public class TestIntrospectionUtils {
|
||||
|
||||
// Test for all the classes and interfaces in StandardContext's type hierarchy
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext01() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.catalina.core.StandardContext"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext02() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.catalina.util.LifecycleMBeanBase"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext03() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.catalina.util.LifecycleBase"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext04() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "java.lang.Object"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext05() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.catalina.Lifecycle"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext06() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.catalina.JmxEnabled"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext07() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "javax.management.MBeanRegistration"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext08() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.catalina.Container"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext09() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "org.apache.tomcat.ContextBind"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext10() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "javax.management.NotificationEmitter"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext11() {
|
||||
Assert.assertTrue(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "javax.management.NotificationBroadcaster"));
|
||||
}
|
||||
|
||||
// And one to check that non-matches return false
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsInstanceStandardContext12() {
|
||||
Assert.assertFalse(IntrospectionUtils.isInstance(
|
||||
StandardContext.class, "com.example.Other"));
|
||||
}
|
||||
}
|
||||
76
test/org/apache/tomcat/util/bcel/TesterPerformance.java
Normal file
76
test/org/apache/tomcat/util/bcel/TesterPerformance.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.bcel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.Jar;
|
||||
import org.apache.tomcat.util.bcel.classfile.ClassParser;
|
||||
import org.apache.tomcat.util.scan.JarFactory;
|
||||
|
||||
public class TesterPerformance {
|
||||
|
||||
private static final String JAR_LOCATION = "/tmp/jira-libs";
|
||||
|
||||
@Test
|
||||
public void testClassParserPerformance() throws IOException {
|
||||
File libDir = new File(JAR_LOCATION);
|
||||
String[] libs = libDir.list();
|
||||
|
||||
Assert.assertNotNull(libs);
|
||||
|
||||
Set<URL> jarURLs = new HashSet<>();
|
||||
|
||||
for (String lib : libs) {
|
||||
if (!lib.toLowerCase(Locale.ENGLISH).endsWith(".jar")) {
|
||||
continue;
|
||||
}
|
||||
jarURLs.add(new URL("jar:" + new File (libDir, lib).toURI().toURL().toExternalForm() + "!/"));
|
||||
}
|
||||
|
||||
long duration = 0;
|
||||
|
||||
for (URL jarURL : jarURLs) {
|
||||
try (Jar jar = JarFactory.newInstance(jarURL)) {
|
||||
jar.nextEntry();
|
||||
String jarEntryName = jar.getEntryName();
|
||||
while (jarEntryName != null) {
|
||||
if (jarEntryName.endsWith(".class")) {
|
||||
InputStream is = jar.getEntryInputStream();
|
||||
long start = System.nanoTime();
|
||||
ClassParser cp = new ClassParser(is);
|
||||
cp.parse();
|
||||
duration += System.nanoTime() - start;
|
||||
}
|
||||
jar.nextEntry();
|
||||
jarEntryName = jar.getEntryName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("ClassParser performance test took: " + duration + " ns");
|
||||
}
|
||||
}
|
||||
65
test/org/apache/tomcat/util/buf/TestAscii.java
Normal file
65
test/org/apache/tomcat/util/buf/TestAscii.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestAscii {
|
||||
|
||||
@Test
|
||||
public void testParseLong1() {
|
||||
String value = "9223372036854775807"; // Long.MAX_VALUE
|
||||
byte[] bytes = value.getBytes();
|
||||
long result = Ascii.parseLong(bytes, 0, bytes.length);
|
||||
Assert.assertEquals(value, String.valueOf(result));
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseLong2() {
|
||||
byte[] bytes = "9223372036854775808".getBytes(); // Long.MAX_VALUE + 1
|
||||
long result = Ascii.parseLong(bytes, 0, bytes.length);
|
||||
Assert.fail("NumberFormatException expected, got: " + result);
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseLong3() {
|
||||
byte[] bytes = "9223372036854775810".getBytes(); // Long.MAX_VALUE + 3
|
||||
long result = Ascii.parseLong(bytes, 0, bytes.length);
|
||||
Assert.fail("NumberFormatException expected, got: " + result);
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseLong4() {
|
||||
BigInteger x = BigInteger.valueOf(5000000000L).shiftLeft(32);
|
||||
byte[] bytes = String.valueOf(x).getBytes();
|
||||
long result = Ascii.parseLong(bytes, 0, bytes.length);
|
||||
Assert.fail("NumberFormatException expected, got: " + result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLong5() {
|
||||
String value = "9223372036854775806"; // Long.MAX_VALUE - 1
|
||||
byte[] bytes = value.getBytes();
|
||||
long result = Ascii.parseLong(bytes, 0, bytes.length);
|
||||
Assert.assertEquals(value, String.valueOf(result));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
143
test/org/apache/tomcat/util/buf/TestB2CConverter.java
Normal file
143
test/org/apache/tomcat/util/buf/TestB2CConverter.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestB2CConverter {
|
||||
|
||||
private static final byte[] UTF16_MESSAGE =
|
||||
new byte[] {-2, -1, 0, 65, 0, 66, 0, 67};
|
||||
|
||||
private static final byte[] UTF8_INVALID = new byte[] {-8, -69, -73, -77};
|
||||
|
||||
private static final byte[] UTF8_PARTIAL = new byte[] {-50};
|
||||
|
||||
@Test
|
||||
public void testSingleMessage() throws Exception {
|
||||
testMessages(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoMessage() throws Exception {
|
||||
testMessages(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyMessage() throws Exception {
|
||||
testMessages(10);
|
||||
}
|
||||
|
||||
private void testMessages(int msgCount) throws Exception {
|
||||
B2CConverter conv = new B2CConverter(StandardCharsets.UTF_16);
|
||||
|
||||
ByteChunk bc = new ByteChunk();
|
||||
CharChunk cc = new CharChunk(32);
|
||||
|
||||
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
bc.append(UTF16_MESSAGE, 0, UTF16_MESSAGE.length);
|
||||
conv.convert(bc, cc, true);
|
||||
Assert.assertEquals("ABC", cc.toString());
|
||||
bc.recycle();
|
||||
cc.recycle();
|
||||
conv.recycle();
|
||||
}
|
||||
|
||||
System.out.println(cc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeftoverSize() {
|
||||
float maxLeftover = 0;
|
||||
String charsetName = "UNSET";
|
||||
for (Charset charset : Charset.availableCharsets().values()) {
|
||||
float leftover;
|
||||
if (charset.name().toLowerCase(Locale.ENGLISH).startsWith("x-")) {
|
||||
// Non-standard charset that browsers won't be using
|
||||
// Likely something used internally by the JRE
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
leftover = charset.newEncoder().maxBytesPerChar();
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Skip it
|
||||
continue;
|
||||
}
|
||||
if (leftover > maxLeftover) {
|
||||
maxLeftover = leftover;
|
||||
charsetName = charset.name();
|
||||
}
|
||||
}
|
||||
Assert.assertTrue("Limit needs to be at least " + maxLeftover +
|
||||
" (used in charset '" + charsetName + "')",
|
||||
maxLeftover <= B2CConverter.LEFTOVER_SIZE);
|
||||
}
|
||||
|
||||
@Test(expected=MalformedInputException.class)
|
||||
public void testBug54602a() throws Exception {
|
||||
// Check invalid input is rejected straight away
|
||||
B2CConverter conv = new B2CConverter(StandardCharsets.UTF_8);
|
||||
ByteChunk bc = new ByteChunk();
|
||||
CharChunk cc = new CharChunk();
|
||||
|
||||
bc.append(UTF8_INVALID, 0, UTF8_INVALID.length);
|
||||
cc.allocate(bc.getLength(), -1);
|
||||
|
||||
conv.convert(bc, cc, false);
|
||||
}
|
||||
|
||||
@Test(expected=MalformedInputException.class)
|
||||
public void testBug54602b() throws Exception {
|
||||
// Check partial input is rejected
|
||||
B2CConverter conv = new B2CConverter(StandardCharsets.UTF_8);
|
||||
ByteChunk bc = new ByteChunk();
|
||||
CharChunk cc = new CharChunk();
|
||||
|
||||
bc.append(UTF8_PARTIAL, 0, UTF8_PARTIAL.length);
|
||||
cc.allocate(bc.getLength(), -1);
|
||||
|
||||
conv.convert(bc, cc, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug54602c() throws Exception {
|
||||
// Check partial input is rejected once it is known to be all available
|
||||
B2CConverter conv = new B2CConverter(StandardCharsets.UTF_8);
|
||||
ByteChunk bc = new ByteChunk();
|
||||
CharChunk cc = new CharChunk();
|
||||
|
||||
bc.append(UTF8_PARTIAL, 0, UTF8_PARTIAL.length);
|
||||
cc.allocate(bc.getLength(), -1);
|
||||
|
||||
conv.convert(bc, cc, false);
|
||||
|
||||
Exception e = null;
|
||||
try {
|
||||
conv.convert(bc, cc, true);
|
||||
} catch (MalformedInputException mie) {
|
||||
e = mie;
|
||||
}
|
||||
Assert.assertNotNull(e);
|
||||
}
|
||||
}
|
||||
176
test/org/apache/tomcat/util/buf/TestByteChunk.java
Normal file
176
test/org/apache/tomcat/util/buf/TestByteChunk.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.ByteChunk.ByteOutputChannel;
|
||||
|
||||
/**
|
||||
* Test cases for {@link ByteChunk}.
|
||||
*/
|
||||
public class TestByteChunk {
|
||||
|
||||
@Test
|
||||
public void testConvertToBytes() throws UnsupportedEncodingException {
|
||||
String string = "HTTP/1.1 100 \r\n\r\n";
|
||||
byte[] bytes = ByteChunk.convertToBytes(string);
|
||||
byte[] expected = string.getBytes("ISO-8859-1");
|
||||
Assert.assertTrue(Arrays.equals(bytes, expected));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test for {@code findByte} vs. {@code indexOf} methods difference.
|
||||
*
|
||||
* <p>
|
||||
* As discussed in the "Re: r944918" thread on dev@, {@code
|
||||
* ByteChunk.indexOf()} works for 0-127 ASCII chars only, and cannot find
|
||||
* any chars outside of the range. {@code ByteChunk.findByte()} works for
|
||||
* any ISO-8859-1 chars.
|
||||
*/
|
||||
@Test
|
||||
public void testFindByte() throws UnsupportedEncodingException {
|
||||
// 0xa0 = 160 = character
|
||||
byte[] bytes = "Hello\u00a0world".getBytes("ISO-8859-1");
|
||||
final int len = bytes.length;
|
||||
|
||||
// indexOf() does not work outside of 0-127
|
||||
Assert.assertEquals(5, ByteChunk.findByte(bytes, 0, len, (byte) '\u00a0'));
|
||||
Assert.assertEquals(-1, ByteChunk.indexOf(bytes, 0, len, '\u00a0'));
|
||||
|
||||
Assert.assertEquals(0, ByteChunk.findByte(bytes, 0, len, (byte) 'H'));
|
||||
Assert.assertEquals(0, ByteChunk.indexOf(bytes, 0, len, 'H'));
|
||||
|
||||
Assert.assertEquals(len - 1, ByteChunk.findByte(bytes, 0, len, (byte) 'd'));
|
||||
Assert.assertEquals(len - 1, ByteChunk.indexOf(bytes, 0, len, 'd'));
|
||||
|
||||
Assert.assertEquals(-1, ByteChunk.findByte(bytes, 0, len, (byte) 'x'));
|
||||
Assert.assertEquals(-1, ByteChunk.indexOf(bytes, 0, len, 'x'));
|
||||
|
||||
Assert.assertEquals(7, ByteChunk.findByte(bytes, 5, len, (byte) 'o'));
|
||||
Assert.assertEquals(7, ByteChunk.indexOf(bytes, 5, len, 'o'));
|
||||
|
||||
Assert.assertEquals(-1, ByteChunk.findByte(bytes, 2, 5, (byte) 'w'));
|
||||
Assert.assertEquals(-1, ByteChunk.indexOf(bytes, 5, 5, 'w'));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexOf_Char() throws UnsupportedEncodingException {
|
||||
byte[] bytes = "Hello\u00a0world".getBytes("ISO-8859-1");
|
||||
final int len = bytes.length;
|
||||
|
||||
ByteChunk bc = new ByteChunk();
|
||||
bc.setBytes(bytes, 0, len);
|
||||
|
||||
Assert.assertEquals(0, bc.indexOf('H', 0));
|
||||
Assert.assertEquals(6, bc.indexOf('w', 0));
|
||||
|
||||
// Does not work outside of 0-127
|
||||
Assert.assertEquals(-1, bc.indexOf('\u00a0', 0));
|
||||
|
||||
bc.setBytes(bytes, 6, 5);
|
||||
Assert.assertEquals(1, bc.indexOf('o', 0));
|
||||
|
||||
bc.setBytes(bytes, 6, 2);
|
||||
Assert.assertEquals(0, bc.indexOf('w', 0));
|
||||
Assert.assertEquals(-1, bc.indexOf('d', 0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexOf_String() throws UnsupportedEncodingException {
|
||||
byte[] bytes = "Hello\u00a0world".getBytes("ISO-8859-1");
|
||||
final int len = bytes.length;
|
||||
|
||||
ByteChunk bc = new ByteChunk();
|
||||
bc.setBytes(bytes, 0, len);
|
||||
|
||||
Assert.assertEquals(0, bc.indexOf("Hello", 0, "Hello".length(), 0));
|
||||
Assert.assertEquals(2, bc.indexOf("ll", 0, 2, 0));
|
||||
Assert.assertEquals(2, bc.indexOf("Hello", 2, 2, 0));
|
||||
|
||||
Assert.assertEquals(7, bc.indexOf("o", 0, 1, 5));
|
||||
|
||||
// Does not work outside of 0-127
|
||||
Assert.assertEquals(-1, bc.indexOf("\u00a0", 0, 1, 0));
|
||||
|
||||
bc.setBytes(bytes, 6, 5);
|
||||
Assert.assertEquals(1, bc.indexOf("o", 0, 1, 0));
|
||||
|
||||
bc.setBytes(bytes, 6, 2);
|
||||
Assert.assertEquals(0, bc.indexOf("wo", 0, 1, 0));
|
||||
Assert.assertEquals(-1, bc.indexOf("d", 0, 1, 0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindBytes() throws UnsupportedEncodingException {
|
||||
byte[] bytes = "Hello\u00a0world".getBytes("ISO-8859-1");
|
||||
final int len = bytes.length;
|
||||
|
||||
Assert.assertEquals(0, ByteChunk.findBytes(bytes, 0, len, new byte[] { 'H' }));
|
||||
Assert.assertEquals(5, ByteChunk.findBytes(bytes, 0, len, new byte[] {
|
||||
(byte) '\u00a0', 'x' }));
|
||||
Assert.assertEquals(5, ByteChunk.findBytes(bytes, 0, len - 4, new byte[] {
|
||||
'x', (byte) '\u00a0' }));
|
||||
Assert.assertEquals(len - 1, ByteChunk.findBytes(bytes, 2, len, new byte[] {
|
||||
'x', 'd' }));
|
||||
Assert.assertEquals(1, ByteChunk.findBytes(bytes, 0, len, new byte[] { 'o',
|
||||
'e' }));
|
||||
Assert.assertEquals(-1, ByteChunk.findBytes(bytes, 2, 5, new byte[] { 'w' }));
|
||||
}
|
||||
|
||||
|
||||
@Ignore // Requires a 6GB heap (on markt's desktop - YMMV)
|
||||
@Test
|
||||
public void testAppend() throws Exception {
|
||||
ByteChunk bc = new ByteChunk();
|
||||
bc.setByteOutputChannel(new Sink());
|
||||
// Defaults to no limit
|
||||
|
||||
byte data[] = new byte[32 * 1024 * 1024];
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
bc.append(data, 0, data.length);
|
||||
}
|
||||
|
||||
Assert.assertEquals(AbstractChunk.ARRAY_MAX_SIZE, bc.getBuffer().length);
|
||||
}
|
||||
|
||||
|
||||
public class Sink implements ByteOutputChannel {
|
||||
|
||||
@Override
|
||||
public void realWriteBytes(byte[] cbuf, int off, int len) throws IOException {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void realWriteBytes(ByteBuffer from) throws IOException {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
}
|
||||
96
test/org/apache/tomcat/util/buf/TestCharChunk.java
Normal file
96
test/org/apache/tomcat/util/buf/TestCharChunk.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.CharChunk.CharOutputChannel;
|
||||
|
||||
/**
|
||||
* Test cases for {@link CharChunk}.
|
||||
*/
|
||||
public class TestCharChunk {
|
||||
|
||||
@Test
|
||||
public void testEndsWith() {
|
||||
CharChunk cc = new CharChunk();
|
||||
Assert.assertFalse(cc.endsWith("test"));
|
||||
cc.setChars("xxtestxx".toCharArray(), 2, 4);
|
||||
Assert.assertTrue(cc.endsWith(""));
|
||||
Assert.assertTrue(cc.endsWith("t"));
|
||||
Assert.assertTrue(cc.endsWith("st"));
|
||||
Assert.assertTrue(cc.endsWith("test"));
|
||||
Assert.assertFalse(cc.endsWith("x"));
|
||||
Assert.assertFalse(cc.endsWith("xxtest"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexOf_String() {
|
||||
char[] chars = "Hello\u00a0world".toCharArray();
|
||||
final int len = chars.length;
|
||||
|
||||
CharChunk cc = new CharChunk();
|
||||
cc.setChars(chars, 0, len);
|
||||
|
||||
Assert.assertEquals(0, cc.indexOf("Hello", 0, "Hello".length(), 0));
|
||||
Assert.assertEquals(2, cc.indexOf("ll", 0, 2, 0));
|
||||
Assert.assertEquals(2, cc.indexOf("Hello", 2, 2, 0));
|
||||
|
||||
Assert.assertEquals(7, cc.indexOf("o", 0, 1, 5));
|
||||
|
||||
// Does work outside of 0-127 (unlike ByteChunk)
|
||||
Assert.assertEquals(5, cc.indexOf("\u00a0", 0, 1, 0));
|
||||
|
||||
cc.setChars(chars, 6, 5);
|
||||
Assert.assertEquals(1, cc.indexOf("o", 0, 1, 0));
|
||||
|
||||
cc.setChars(chars, 6, 2);
|
||||
Assert.assertEquals(0, cc.indexOf("wo", 0, 1, 0));
|
||||
Assert.assertEquals(-1, cc.indexOf("d", 0, 1, 0));
|
||||
}
|
||||
|
||||
|
||||
@Ignore // Requires an 11GB heap (on markt's desktop - YMMV)
|
||||
@Test
|
||||
public void testAppend() throws Exception {
|
||||
CharChunk cc = new CharChunk();
|
||||
cc.setCharOutputChannel(new Sink());
|
||||
// Defaults to no limit
|
||||
|
||||
char data[] = new char[32 * 1024 * 1024];
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
cc.append(data, 0, data.length);
|
||||
}
|
||||
|
||||
Assert.assertEquals(AbstractChunk.ARRAY_MAX_SIZE, cc.getBuffer().length);
|
||||
}
|
||||
|
||||
|
||||
public class Sink implements CharOutputChannel {
|
||||
|
||||
@Override
|
||||
public void realWriteChars(char[] cbuf, int off, int len) throws IOException {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
}
|
||||
80
test/org/apache/tomcat/util/buf/TestCharsetCache.java
Normal file
80
test/org/apache/tomcat/util/buf/TestCharsetCache.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestCharsetCache {
|
||||
|
||||
@Test
|
||||
public void testAllKnownCharsets() {
|
||||
|
||||
Set<String> known = new HashSet<>();
|
||||
known.addAll(Arrays.asList(CharsetCache.LAZY_CHARSETS));
|
||||
Set<String> initial = new HashSet<>();
|
||||
initial.addAll(Arrays.asList(CharsetCache.INITIAL_CHARSETS));
|
||||
|
||||
List<String> cacheMisses = new ArrayList<>();
|
||||
|
||||
for (Charset charset: Charset.availableCharsets().values()) {
|
||||
String name = charset.name().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
// No need to test the charsets that are pre-loaded
|
||||
if (initial.contains(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!known.contains(name)) {
|
||||
cacheMisses.add(name);
|
||||
}
|
||||
|
||||
for (String alias : charset.aliases()) {
|
||||
alias = alias.toLowerCase(Locale.ENGLISH);
|
||||
if (!known.contains(alias)) {
|
||||
cacheMisses.add(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheMisses.size() != 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Collections.sort(cacheMisses);
|
||||
for (String name : cacheMisses) {
|
||||
if (sb.length() == 0) {
|
||||
sb.append('"');
|
||||
} else {
|
||||
sb.append(", \"");
|
||||
}
|
||||
sb.append(name.toLowerCase(Locale.ENGLISH));
|
||||
sb.append('"');
|
||||
}
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
|
||||
Assert.assertTrue(cacheMisses.size() == 0);
|
||||
}
|
||||
}
|
||||
141
test/org/apache/tomcat/util/buf/TestCharsetCachePerformance.java
Normal file
141
test/org/apache/tomcat/util/buf/TestCharsetCachePerformance.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestCharsetCachePerformance {
|
||||
|
||||
@Test
|
||||
public void testNoCsCache() throws Exception {
|
||||
doTest(new NoCsCache());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFullCsCache() throws Exception {
|
||||
doTest(new FullCsCache());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLazyCsCache() throws Exception {
|
||||
doTest(new LazyCsCache());
|
||||
}
|
||||
|
||||
|
||||
private void doTest(CsCache cache) throws Exception {
|
||||
int threadCount = 10;
|
||||
int iterations = 10000000;
|
||||
String[] lookupNames = new String[] {
|
||||
"ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5" };
|
||||
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i] = new TestCsCacheThread(iterations, cache, lookupNames);
|
||||
}
|
||||
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
long endTime = System.nanoTime();
|
||||
|
||||
System.out.println(cache.getClass().getName() + ": " + (endTime - startTime) + "ns");
|
||||
}
|
||||
|
||||
|
||||
private static interface CsCache {
|
||||
Charset getCharset(String charsetName);
|
||||
}
|
||||
|
||||
|
||||
private static class NoCsCache implements CsCache {
|
||||
|
||||
@Override
|
||||
public Charset getCharset(String charsetName) {
|
||||
return Charset.forName(charsetName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class FullCsCache implements CsCache {
|
||||
|
||||
private static final Map<String,Charset> cache = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Charset charset: Charset.availableCharsets().values()) {
|
||||
cache.put(charset.name().toLowerCase(Locale.ENGLISH), charset);
|
||||
for (String alias : charset.aliases()) {
|
||||
cache.put(alias.toLowerCase(Locale.ENGLISH), charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Charset getCharset(String charsetName) {
|
||||
return cache.get(charsetName.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class LazyCsCache implements CsCache {
|
||||
|
||||
private CharsetCache cache = new CharsetCache();
|
||||
|
||||
@Override
|
||||
public Charset getCharset(String charsetName) {
|
||||
return cache.getCharset(charsetName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TestCsCacheThread extends Thread {
|
||||
|
||||
private final int iterations;
|
||||
private final CsCache cache;
|
||||
private final String[] lookupNames;
|
||||
private final int lookupNamesCount;
|
||||
|
||||
public TestCsCacheThread(int iterations, CsCache cache, String[] lookupNames) {
|
||||
this.iterations = iterations;
|
||||
this.cache = cache;
|
||||
this.lookupNames = lookupNames;
|
||||
this.lookupNamesCount = lookupNames.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
cache.getCharset(lookupNames[i % lookupNamesCount]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
71
test/org/apache/tomcat/util/buf/TestHexUtils.java
Normal file
71
test/org/apache/tomcat/util/buf/TestHexUtils.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test cases for {@link HexUtils}.
|
||||
*/
|
||||
public class TestHexUtils {
|
||||
|
||||
private static final String TEST01_STRING = "Hello World";
|
||||
private static final byte[] TEST01_BYTES = TEST01_STRING.getBytes(StandardCharsets.UTF_8);
|
||||
private static final String TEST02_STRING = "foo";
|
||||
private static final byte[] TEST02_BYTES = TEST02_STRING.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
@Test
|
||||
public void testGetDec() {
|
||||
Assert.assertEquals(0, HexUtils.getDec('0'));
|
||||
Assert.assertEquals(9, HexUtils.getDec('9'));
|
||||
Assert.assertEquals(10, HexUtils.getDec('a'));
|
||||
Assert.assertEquals(15, HexUtils.getDec('f'));
|
||||
Assert.assertEquals(10, HexUtils.getDec('A'));
|
||||
Assert.assertEquals(15, HexUtils.getDec('F'));
|
||||
Assert.assertEquals(-1, HexUtils.getDec(0));
|
||||
Assert.assertEquals(-1, HexUtils.getDec('Z'));
|
||||
Assert.assertEquals(-1, HexUtils.getDec(255));
|
||||
Assert.assertEquals(-1, HexUtils.getDec(-60));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundTrip01() {
|
||||
Assert.assertArrayEquals(TEST01_STRING, TEST01_BYTES,
|
||||
HexUtils.fromHexString(HexUtils.toHexString(TEST01_BYTES)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundTrip02() {
|
||||
Assert.assertArrayEquals(TEST02_STRING, TEST02_BYTES,
|
||||
HexUtils.fromHexString(HexUtils.toHexString(TEST02_BYTES)));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testFromHex01() {
|
||||
HexUtils.fromHexString("Not a hex string");
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testFromHex02() {
|
||||
// Odd number of hex characters
|
||||
HexUtils.fromHexString("aaa");
|
||||
}
|
||||
}
|
||||
69
test/org/apache/tomcat/util/buf/TestMessageBytes.java
Normal file
69
test/org/apache/tomcat/util/buf/TestMessageBytes.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestMessageBytes {
|
||||
|
||||
@Test
|
||||
public void testToStringFromNull() {
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToBytesFromNull() {
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.toBytes();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToCharsFromNull() {
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.toChars();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToStringAfterRecycle() {
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.setString("foo");
|
||||
mb.recycle();
|
||||
mb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToBytesAfterRecycle() {
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.setString("foo");
|
||||
mb.recycle();
|
||||
mb.toBytes();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToCharsAfterRecycle() {
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.setString("foo");
|
||||
mb.recycle();
|
||||
mb.toChars();
|
||||
}
|
||||
}
|
||||
77
test/org/apache/tomcat/util/buf/TestStringUtils.java
Normal file
77
test/org/apache/tomcat/util/buf/TestStringUtils.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/*
|
||||
* None of these tests should throw a NPE.
|
||||
*/
|
||||
public class TestStringUtils {
|
||||
|
||||
@Test
|
||||
public void testNullArray() {
|
||||
Assert.assertEquals("", StringUtils.join((String[]) null));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullArrayCharStringBuilder() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringUtils.join((String[]) null, ',', sb);
|
||||
Assert.assertEquals("", sb.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullCollection() {
|
||||
Assert.assertEquals("", StringUtils.join((Collection<String>) null));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullCollectionChar() {
|
||||
Assert.assertEquals("", StringUtils.join(null, ','));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullIterableCharStringBuilder() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringUtils.join((Iterable<String>) null, ',', sb);
|
||||
Assert.assertEquals("", sb.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullArrayCharFunctionStringBuilder() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringUtils.join((String[]) null, ',', null, sb);
|
||||
Assert.assertEquals("", sb.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullIterableCharFunctionStringBuilder() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringUtils.join((Iterable<String>) null, ',', null, sb);
|
||||
Assert.assertEquals("", sb.toString());
|
||||
}
|
||||
}
|
||||
102
test/org/apache/tomcat/util/buf/TestUDecoder.java
Normal file
102
test/org/apache/tomcat/util/buf/TestUDecoder.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestUDecoder {
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringInvalid() {
|
||||
// %n rather than %nn should throw an IAE according to the Javadoc
|
||||
Exception exception = null;
|
||||
try {
|
||||
UDecoder.URLDecode("%5xxxxx");
|
||||
} catch (Exception e) {
|
||||
exception = e;
|
||||
}
|
||||
Assert.assertTrue(exception instanceof IllegalArgumentException);
|
||||
|
||||
// Edge case trying to trigger ArrayIndexOutOfBoundsException
|
||||
exception = null;
|
||||
try {
|
||||
UDecoder.URLDecode("%5");
|
||||
} catch (Exception e) {
|
||||
exception = e;
|
||||
}
|
||||
Assert.assertTrue(exception instanceof IllegalArgumentException);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringValidIso88591Start() {
|
||||
String result = UDecoder.URLDecode("%41xxxx", StandardCharsets.ISO_8859_1);
|
||||
Assert.assertEquals("Axxxx", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringValidIso88591Middle() {
|
||||
String result = UDecoder.URLDecode("xx%41xx", StandardCharsets.ISO_8859_1);
|
||||
Assert.assertEquals("xxAxx", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringValidIso88591End() {
|
||||
String result = UDecoder.URLDecode("xxxx%41", StandardCharsets.ISO_8859_1);
|
||||
Assert.assertEquals("xxxxA", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringValidUtf8Start() {
|
||||
String result = UDecoder.URLDecode("%c3%aaxxxx", StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("\u00eaxxxx", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringValidUtf8Middle() {
|
||||
String result = UDecoder.URLDecode("xx%c3%aaxx", StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("xx\u00eaxx", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringValidUtf8End() {
|
||||
String result = UDecoder.URLDecode("xxxx%c3%aa", StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("xxxx\u00ea", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringNonAsciiValidNone() {
|
||||
String result = UDecoder.URLDecode("\u00eaxxxx", StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("\u00eaxxxx", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testURLDecodeStringNonAsciiValidUtf8() {
|
||||
String result = UDecoder.URLDecode("\u00ea%c3%aa", StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("\u00ea\u00ea", result);
|
||||
}
|
||||
}
|
||||
46
test/org/apache/tomcat/util/buf/TestUEncoder.java
Normal file
46
test/org/apache/tomcat/util/buf/TestUEncoder.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.UEncoder.SafeCharsSet;
|
||||
|
||||
/**
|
||||
* Test cases for {@link UEncoder}.
|
||||
*/
|
||||
public class TestUEncoder {
|
||||
|
||||
@Test
|
||||
public void testEncodeURLWithSlashInit() throws IOException {
|
||||
UEncoder urlEncoder = new UEncoder(SafeCharsSet.WITH_SLASH);
|
||||
|
||||
String s = "a+b/c/d+e.class";
|
||||
Assert.assertTrue(urlEncoder.encodeURL(s, 0, s.length()).equals(
|
||||
"a%2bb/c/d%2be.class"));
|
||||
Assert.assertTrue(urlEncoder.encodeURL(s, 2, s.length() - 2).equals(
|
||||
"b/c/d%2be.cla"));
|
||||
|
||||
s = new String(new char[] { 0xD801, 0xDC01 });
|
||||
Assert.assertTrue(urlEncoder.encodeURL(s, 0, s.length())
|
||||
.equals("%f0%90%90%81"));
|
||||
}
|
||||
}
|
||||
24
test/org/apache/tomcat/util/buf/TestUriUtil24.java
Normal file
24
test/org/apache/tomcat/util/buf/TestUriUtil24.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
public class TestUriUtil24 extends TesterUriUtilBase {
|
||||
|
||||
public TestUriUtil24() {
|
||||
super("$");
|
||||
}
|
||||
}
|
||||
24
test/org/apache/tomcat/util/buf/TestUriUtil26.java
Normal file
24
test/org/apache/tomcat/util/buf/TestUriUtil26.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
public class TestUriUtil26 extends TesterUriUtilBase {
|
||||
|
||||
public TestUriUtil26() {
|
||||
super("&");
|
||||
}
|
||||
}
|
||||
24
test/org/apache/tomcat/util/buf/TestUriUtil2A.java
Normal file
24
test/org/apache/tomcat/util/buf/TestUriUtil2A.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
public class TestUriUtil2A extends TesterUriUtilBase {
|
||||
|
||||
public TestUriUtil2A() {
|
||||
super("*");
|
||||
}
|
||||
}
|
||||
24
test/org/apache/tomcat/util/buf/TestUriUtil40.java
Normal file
24
test/org/apache/tomcat/util/buf/TestUriUtil40.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
public class TestUriUtil40 extends TesterUriUtilBase {
|
||||
|
||||
public TestUriUtil40() {
|
||||
super("@");
|
||||
}
|
||||
}
|
||||
678
test/org/apache/tomcat/util/buf/TestUtf8.java
Normal file
678
test/org/apache/tomcat/util/buf/TestUtf8.java
Normal file
@@ -0,0 +1,678 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* These tests have been written with reference to
|
||||
* <a href="http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf">unicode 6.2,
|
||||
* chapter 3, section 3.9</a>.
|
||||
*/
|
||||
public class TestUtf8 {
|
||||
|
||||
// Indicates that at invalid sequence is detected one character later than
|
||||
// the earliest possible moment
|
||||
private static final int ERROR_POS_PLUS1 = 1;
|
||||
// Indicates that at invalid sequence is detected two characters later than
|
||||
// the earliest possible moment
|
||||
private static final int ERROR_POS_PLUS2 = 2;
|
||||
// Indicates that at invalid sequence is detected four characters later
|
||||
// than the earliest possible moment
|
||||
private static final int ERROR_POS_PLUS4 = 4;
|
||||
// Indicates that the trailing valid byte is included in replacement of the
|
||||
// previous error
|
||||
private static final int REPLACE_SWALLOWS_TRAILER = 8;
|
||||
// Indicates that one replacement character is missing
|
||||
private static final int REPLACE_MISSING1 = 16;
|
||||
// Indicates that two replacement characters are missing
|
||||
private static final int REPLACE_MISSING2 = 32;
|
||||
// Indicates that three replacement characters are missing
|
||||
private static final int REPLACE_MISSING4 = 64;
|
||||
|
||||
public static final List<Utf8TestCase> TEST_CASES;
|
||||
|
||||
private static int workAroundCount = 0;
|
||||
|
||||
static {
|
||||
// All known issues have been fixed in Java 8
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8039751
|
||||
// Base assumption in Java 7
|
||||
int javaVersion = 7;
|
||||
try {
|
||||
Class.forName("java.util.stream.Collector");
|
||||
javaVersion = 8;
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
Utf8TestCase testCase = null;
|
||||
ArrayList<Utf8TestCase> testCases = new ArrayList<>();
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Zero length input",
|
||||
new int[] {},
|
||||
-1,
|
||||
""));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid one byte sequence",
|
||||
new int[] {0x41},
|
||||
-1,
|
||||
"A"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid two byte sequence",
|
||||
new int[] {0xC2, 0xA9},
|
||||
-1,
|
||||
"\u00A9"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid three byte sequence",
|
||||
new int[] {0xE0, 0xA4, 0x87},
|
||||
-1,
|
||||
"\u0907"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid four byte sequence",
|
||||
new int[] {0xF0, 0x90, 0x90, 0x80},
|
||||
-1,
|
||||
"\uD801\uDC00"));
|
||||
// Java 7 JVM decoder does not report error until all 4 bytes are
|
||||
// available
|
||||
testCase = new Utf8TestCase(
|
||||
"Invalid code point - out of range",
|
||||
new int[] {0x41, 0xF4, 0x90, 0x80, 0x80, 0x41},
|
||||
2,
|
||||
"A\uFFFD\uFFFD\uFFFD\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
// Java 7 JVM decoder does not report error until all 2 bytes are available
|
||||
testCase = new Utf8TestCase(
|
||||
"Valid sequence padded from one byte to two",
|
||||
new int[] {0x41, 0xC0, 0xC1, 0x41},
|
||||
1,
|
||||
"A\uFFFD\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
// Java 7 JVM decoder does not report error until all 3 bytes are available
|
||||
testCase = new Utf8TestCase(
|
||||
"Valid sequence padded from one byte to three",
|
||||
new int[] {0x41, 0xE0, 0x80, 0xC1, 0x41},
|
||||
2,
|
||||
"A\uFFFD\uFFFD\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
// Java 7 JVM decoder does not report error until all 4 bytes are
|
||||
// available
|
||||
testCase = new Utf8TestCase(
|
||||
"Valid sequence padded from one byte to four",
|
||||
new int[] {0x41, 0xF0, 0x80, 0x80, 0xC1, 0x41},
|
||||
2,
|
||||
"A\uFFFD\uFFFD\uFFFD\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Invalid one byte 1111 1111",
|
||||
new int[] {0x41, 0xFF, 0x41},
|
||||
1,
|
||||
"A\uFFFDA"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Invalid one byte 1111 0000",
|
||||
new int[] {0x41, 0xF0, 0x41},
|
||||
2,
|
||||
"A\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(REPLACE_SWALLOWS_TRAILER);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Invalid one byte 1110 0000",
|
||||
new int[] {0x41, 0xE0, 0x41},
|
||||
2,
|
||||
"A\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(REPLACE_SWALLOWS_TRAILER);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Invalid one byte 1100 0000",
|
||||
new int[] {0x41, 0xC0, 0x41},
|
||||
1,
|
||||
"A\uFFFDA");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Invalid one byte 1000 000",
|
||||
new int[] {0x41, 0x80, 0x41},
|
||||
1,
|
||||
"A\uFFFDA"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Invalid sequence from unicode 6.2 spec, table 3-8",
|
||||
new int[] {0x61, 0xF1, 0x80, 0x80, 0xE1, 0x80, 0xC2, 0x62, 0x80,
|
||||
0x63, 0x80, 0xBF, 0x64},
|
||||
4,
|
||||
"a\uFFFD\uFFFD\uFFFDb\uFFFDc\uFFFD\uFFFDd"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid 4-byte sequence truncated to 3 bytes",
|
||||
new int[] {0x61, 0xF0, 0x90, 0x90},
|
||||
3,
|
||||
"a\uFFFD"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid 4-byte sequence truncated to 2 bytes",
|
||||
new int[] {0x61, 0xF0, 0x90},
|
||||
2,
|
||||
"a\uFFFD"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid 4-byte sequence truncated to 1 byte",
|
||||
new int[] {0x61, 0xF0},
|
||||
1,
|
||||
"a\uFFFD"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Valid 4-byte sequence truncated to 3 bytes with trailer",
|
||||
new int[] {0x61, 0xF0, 0x90, 0x90, 0x61},
|
||||
4,
|
||||
"a\uFFFDa"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Valid 4-byte sequence truncated to 2 bytes with trailer",
|
||||
new int[] {0x61, 0xF0, 0x90, 0x61},
|
||||
3,
|
||||
"a\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(REPLACE_SWALLOWS_TRAILER);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Valid 4-byte sequence truncated to 1 byte with trailer",
|
||||
new int[] {0x61, 0xF0, 0x61},
|
||||
2,
|
||||
"a\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(REPLACE_SWALLOWS_TRAILER);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"U+0000 zero-padded to two bytes",
|
||||
new int[] {0x61, 0xC0, 0x80, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"U+007F zero-padded to two bytes",
|
||||
new int[] {0x61, 0xC1, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Two bytes, all 1's",
|
||||
new int[] {0x61, 0xFF, 0xFF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFDa"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Two bytes, 1110 first byte first nibble",
|
||||
new int[] {0x61, 0xE0, 0x80, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Two bytes, 101x first byte first nibble",
|
||||
new int[] {0x61, 0xA0, 0x80, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFDa"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Two bytes, invalid second byte",
|
||||
new int[] {0x61, 0xC2, 0x00, 0x61},
|
||||
2,
|
||||
"a\uFFFD\u0000a"));
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Two bytes, invalid second byte",
|
||||
new int[] {0x61, 0xC2, 0xC0, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFDa"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Three bytes, U+0000 zero-padded",
|
||||
new int[] {0x61, 0xE0, 0x80, 0x80, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Three bytes, U+007F zero-padded",
|
||||
new int[] {0x61, 0xE0, 0x81, 0xBF, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Three bytes, U+07FF zero-padded",
|
||||
new int[] {0x61, 0xE0, 0x9F, 0xBF, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Three bytes, all 1's",
|
||||
new int[] {0x61, 0xFF, 0xFF, 0xFF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFDa"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Three bytes, invalid first byte",
|
||||
new int[] {0x61, 0xF8, 0x80, 0x80, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(REPLACE_MISSING2).addForJvm(
|
||||
REPLACE_SWALLOWS_TRAILER);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Three bytes, invalid second byte",
|
||||
new int[] {0x61, 0xE0, 0xC0, 0x80, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Three bytes, invalid third byte",
|
||||
new int[] {0x61, 0xE1, 0x80, 0xC0, 0x61},
|
||||
3,
|
||||
"a\uFFFD\uFFFDa"));
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, U+0000 zero-padded",
|
||||
new int[] {0x61, 0xF0, 0x80, 0x80, 0x80, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, U+007F zero-padded",
|
||||
new int[] {0x61, 0xF0, 0x80, 0x81, 0xBF, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, U+07FF zero-padded",
|
||||
new int[] {0x61, 0xF0, 0x80, 0x9F, 0xBF, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, U+FFFF zero-padded",
|
||||
new int[] {0x61, 0xF0, 0x8F, 0xBF, 0xBF, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Four bytes, all 1's",
|
||||
new int[] {0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, invalid first byte",
|
||||
new int[] {0x61, 0xF8, 0x80, 0x80, 0x80, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(
|
||||
REPLACE_MISSING2).addForJvm(REPLACE_MISSING1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, invalid second byte",
|
||||
new int[] {0x61, 0xF1, 0xC0, 0x80, 0x80, 0x61},
|
||||
2,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS2);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Four bytes, invalid third byte",
|
||||
new int[] {0x61, 0xF1, 0x80, 0xC0, 0x80, 0x61},
|
||||
3,
|
||||
"a\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCases.add(new Utf8TestCase(
|
||||
"Four bytes, invalid fourth byte",
|
||||
new int[] {0x61, 0xF1, 0x80, 0x80, 0xC0, 0x61},
|
||||
4,
|
||||
"a\uFFFD\uFFFDa"));
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Five bytes, U+0000 zero padded",
|
||||
new int[] {0x61, 0xF8, 0x80, 0x80, 0x80, 0x80, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Five bytes, U+007F zero padded",
|
||||
new int[] {0x61, 0xF8, 0x80, 0x80, 0x81, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Five bytes, U+07FF zero padded",
|
||||
new int[] {0x61, 0xF8, 0x80, 0x80, 0x9F, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Five bytes, U+FFFF zero padded",
|
||||
new int[] {0x61, 0xF8, 0x80, 0x8F, 0xBF, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Six bytes, U+0000 zero padded",
|
||||
new int[] {0x61, 0xFC, 0x80, 0x80, 0x80, 0x80, 0x80, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(
|
||||
ERROR_POS_PLUS1).addForJvm(REPLACE_MISSING4).addForJvm(
|
||||
REPLACE_MISSING1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Six bytes, U+007F zero padded",
|
||||
new int[] {0x61, 0xFC, 0x80, 0x80, 0x80, 0x81, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(
|
||||
ERROR_POS_PLUS1).addForJvm(REPLACE_MISSING4).addForJvm(
|
||||
REPLACE_MISSING1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Six bytes, U+07FF zero padded",
|
||||
new int[] {0x61, 0xFC, 0x80, 0x80, 0x80, 0x9F, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(
|
||||
ERROR_POS_PLUS1).addForJvm(REPLACE_MISSING4).addForJvm(
|
||||
REPLACE_MISSING1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Six bytes, U+FFFF zero padded",
|
||||
new int[] {0x61, 0xFC, 0x80, 0x80, 0x8F, 0xBF, 0xBF, 0x61},
|
||||
1,
|
||||
"a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS4).addForJvm(
|
||||
ERROR_POS_PLUS1).addForJvm(REPLACE_MISSING4).addForJvm(
|
||||
REPLACE_MISSING1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
testCase = new Utf8TestCase(
|
||||
"Original test case - derived from Autobahn?",
|
||||
new int[] {0xCE, 0xBA, 0xE1, 0xDB, 0xB9, 0xCF, 0x83, 0xCE,
|
||||
0xBC, 0xCE, 0xB5, 0xED, 0x80, 0x65, 0x64, 0x69,
|
||||
0x74, 0x65, 0x64},
|
||||
3,
|
||||
"\u03BA\uFFFD\u06F9\u03C3\u03BC\u03B5\uFFFDedited");
|
||||
if (javaVersion < 8) {
|
||||
testCase.addForJvm(ERROR_POS_PLUS1);
|
||||
}
|
||||
testCases.add(testCase);
|
||||
|
||||
TEST_CASES = Collections.unmodifiableList(testCases);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHarmonyDecoder() {
|
||||
CharsetDecoder decoder = new Utf8Decoder();
|
||||
for (Utf8TestCase testCase : TEST_CASES) {
|
||||
doTest(decoder, testCase, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testJvmDecoder() {
|
||||
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
|
||||
int testCount = 0;
|
||||
try {
|
||||
for (Utf8TestCase testCase : TEST_CASES) {
|
||||
doTest(decoder, testCase, testCase.flagsJvm);
|
||||
testCount++;
|
||||
}
|
||||
} finally {
|
||||
System.err.println("Workarounds added to " + workAroundCount +
|
||||
" tests to account for known JVM bugs");
|
||||
if (testCount < TEST_CASES.size()) {
|
||||
System.err.println("Executed " + testCount + " of " +
|
||||
TEST_CASES.size() + " UTF-8 tests before " +
|
||||
"encountering a failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doTest(CharsetDecoder decoder, Utf8TestCase testCase,
|
||||
int flags) {
|
||||
|
||||
int len = testCase.input.length;
|
||||
ByteBuffer bb = ByteBuffer.allocate(len);
|
||||
CharBuffer cb = CharBuffer.allocate(len);
|
||||
|
||||
// Configure decoder to fail on an error
|
||||
decoder.reset();
|
||||
decoder.onMalformedInput(CodingErrorAction.REPORT);
|
||||
decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
|
||||
// Add each byte one at a time. The decoder should fail as soon as
|
||||
// an invalid sequence has been provided
|
||||
for (int i = 0; i < len; i++) {
|
||||
bb.put((byte) testCase.input[i]);
|
||||
bb.flip();
|
||||
CoderResult cr = decoder.decode(bb, cb, false);
|
||||
if (cr.isError()) {
|
||||
int expected = testCase.invalidIndex;
|
||||
if ((flags & ERROR_POS_PLUS1) != 0) {
|
||||
expected += 1;
|
||||
}
|
||||
if ((flags & ERROR_POS_PLUS2) != 0) {
|
||||
expected += 2;
|
||||
}
|
||||
if ((flags & ERROR_POS_PLUS4) != 0) {
|
||||
expected += 4;
|
||||
}
|
||||
Assert.assertEquals(testCase.description, expected, i);
|
||||
break;
|
||||
}
|
||||
bb.compact();
|
||||
}
|
||||
|
||||
// Configure decoder to replace on an error
|
||||
decoder.reset();
|
||||
decoder.onMalformedInput(CodingErrorAction.REPLACE);
|
||||
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
|
||||
// Add each byte one at a time.
|
||||
bb.clear();
|
||||
cb.clear();
|
||||
for (int i = 0; i < len; i++) {
|
||||
bb.put((byte) testCase.input[i]);
|
||||
bb.flip();
|
||||
CoderResult cr = decoder.decode(bb, cb, false);
|
||||
if (cr.isError()) {
|
||||
Assert.fail(testCase.description);
|
||||
}
|
||||
bb.compact();
|
||||
}
|
||||
// For incomplete sequences at the end of the input need to tell
|
||||
// the decoder the input has ended
|
||||
bb.flip();
|
||||
CoderResult cr = decoder.decode(bb, cb, true);
|
||||
if (cr.isError()) {
|
||||
Assert.fail(testCase.description);
|
||||
}
|
||||
cb.flip();
|
||||
|
||||
String expected = testCase.outputReplaced;
|
||||
if ((flags & REPLACE_SWALLOWS_TRAILER) != 0) {
|
||||
expected = expected.substring(0, expected.length() - 1);
|
||||
}
|
||||
|
||||
if ((flags & REPLACE_MISSING1) != 0) {
|
||||
expected = expected.substring(0, 1) +
|
||||
expected.substring(2, expected.length());
|
||||
}
|
||||
|
||||
if ((flags & REPLACE_MISSING2) != 0) {
|
||||
expected = expected.substring(0, 1) +
|
||||
expected.substring(3, expected.length());
|
||||
}
|
||||
|
||||
if ((flags & REPLACE_MISSING4) != 0) {
|
||||
expected = expected.substring(0, 1) +
|
||||
expected.substring(5, expected.length());
|
||||
}
|
||||
|
||||
Assert.assertEquals(testCase.description, expected, cb.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates a single UTF-8 test case
|
||||
*/
|
||||
public static class Utf8TestCase {
|
||||
public final String description;
|
||||
public final int[] input;
|
||||
public final int invalidIndex;
|
||||
public final String outputReplaced;
|
||||
public int flagsJvm = 0;
|
||||
|
||||
public Utf8TestCase(String description, int[] input, int invalidIndex,
|
||||
String outputReplaced) {
|
||||
this.description = description;
|
||||
this.input = input;
|
||||
this.invalidIndex = invalidIndex;
|
||||
this.outputReplaced = outputReplaced;
|
||||
|
||||
}
|
||||
|
||||
public Utf8TestCase addForJvm(int flag) {
|
||||
if (this.flagsJvm == 0) {
|
||||
TestUtf8.workAroundCount++;
|
||||
}
|
||||
this.flagsJvm = this.flagsJvm | flag;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
test/org/apache/tomcat/util/buf/TesterUriUtilBase.java
Normal file
136
test/org/apache/tomcat/util/buf/TesterUriUtilBase.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.buf;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
|
||||
|
||||
public abstract class TesterUriUtilBase {
|
||||
|
||||
private final String separator;
|
||||
|
||||
protected TesterUriUtilBase(String separator) {
|
||||
this.separator = separator;
|
||||
TomcatURLStreamHandlerFactory.register();
|
||||
System.setProperty("org.apache.tomcat.util.buf.UriUtil.WAR_SEPARATOR", separator);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBuildJarUrl01() throws MalformedURLException {
|
||||
File jarFile = new File("/patha/pathb!/pathc");
|
||||
String result = UriUtil.buildJarUrl(jarFile).toString();
|
||||
|
||||
int index = result.indexOf("!/");
|
||||
Assert.assertEquals(result, result.length() - 2, index);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBuildJarUrl02() throws MalformedURLException {
|
||||
File jarFile = new File("/patha/pathb*/pathc");
|
||||
String result = UriUtil.buildJarUrl(jarFile).toString();
|
||||
|
||||
int index = result.indexOf("!/");
|
||||
Assert.assertEquals(result, result.length() - 2, index);
|
||||
|
||||
index = result.indexOf("*/");
|
||||
Assert.assertEquals(result, -1, index);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBuildJarUrl03() throws MalformedURLException {
|
||||
File jarFile = new File("/patha/pathb^/pathc");
|
||||
String result = UriUtil.buildJarUrl(jarFile).toString();
|
||||
|
||||
int index = result.indexOf("!/");
|
||||
Assert.assertEquals(result, result.length() - 2, index);
|
||||
|
||||
index = result.indexOf("^/");
|
||||
Assert.assertEquals(result, -1, index);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBuildJarUrl04() throws MalformedURLException {
|
||||
File jarFile = new File("/patha/pathb" + separator + "/pathc");
|
||||
String result = UriUtil.buildJarUrl(jarFile).toString();
|
||||
|
||||
int index = result.indexOf("!/");
|
||||
Assert.assertEquals(result, result.length() - 2, index);
|
||||
|
||||
index = result.indexOf(separator + "/");
|
||||
Assert.assertEquals(result, -1, index);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWarToJar01() throws MalformedURLException {
|
||||
doTestWarToJar("^");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWarToJar02() throws MalformedURLException {
|
||||
doTestWarToJar("*");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWarToJar03() throws MalformedURLException {
|
||||
doTestWarToJar(separator);
|
||||
}
|
||||
|
||||
|
||||
private void doTestWarToJar(String separator) throws MalformedURLException {
|
||||
URL warUrl = new URL("war:file:/external/path" + separator + "/internal/path");
|
||||
URL jarUrl = UriUtil.warToJar(warUrl);
|
||||
Assert.assertEquals("jar:file:/external/path!/internal/path", jarUrl.toString());
|
||||
}
|
||||
|
||||
|
||||
// @Test /* Uncomment to test performance for different implementations. */
|
||||
public void performanceTestBuildJarUrl() throws MalformedURLException {
|
||||
File jarFile = new File("/patha/pathb^/pathc");
|
||||
|
||||
URL url = null;
|
||||
|
||||
int count = 1000000;
|
||||
|
||||
// Warm up
|
||||
for (int i = 0; i < count / 10; i++) {
|
||||
url = UriUtil.buildJarUrl(jarFile);
|
||||
}
|
||||
|
||||
// Test
|
||||
long start = System.nanoTime();
|
||||
for (int i = 0; i < count / 10; i++) {
|
||||
url = UriUtil.buildJarUrl(jarFile);
|
||||
}
|
||||
long duration = System.nanoTime() - start;
|
||||
|
||||
System.out.println("[" + count + "] iterations took [" +
|
||||
duration + "] ns for [" + url + "]");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.collections;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestCaseInsensitiveKeyMap {
|
||||
|
||||
@Test
|
||||
public void testPut() {
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
Object o = map.put("A", o2);
|
||||
|
||||
Assert.assertEquals(o1, o);
|
||||
|
||||
Assert.assertEquals(o2, map.get("a"));
|
||||
Assert.assertEquals(o2, map.get("A"));
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testPutNullKey() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put(null, o1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGet() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Assert.assertEquals(o1, map.get("a"));
|
||||
Assert.assertEquals(o1, map.get("A"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetNullKey() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Assert.assertNull(map.get(null));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContainsKey() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Assert.assertTrue(map.containsKey("a"));
|
||||
Assert.assertTrue(map.containsKey("A"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContainsKeyNonString() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Assert.assertFalse(map.containsKey(o1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContainsKeyNull() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Assert.assertFalse(map.containsKey(null));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContainsValue() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Assert.assertTrue(map.containsValue(o1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRemove() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
Assert.assertFalse(map.isEmpty());
|
||||
map.remove("A");
|
||||
Assert.assertTrue(map.isEmpty());
|
||||
|
||||
map.put("A", o1);
|
||||
Assert.assertFalse(map.isEmpty());
|
||||
map.remove("a");
|
||||
Assert.assertTrue(map.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
map.put(Integer.toString(i), o1);
|
||||
}
|
||||
Assert.assertEquals(10, map.size());
|
||||
map.clear();
|
||||
Assert.assertEquals(0, map.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPutAll() {
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
|
||||
Map<String,Object> source = new HashMap<>();
|
||||
source.put("a", o1);
|
||||
source.put("A", o2);
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.putAll(source);
|
||||
|
||||
Assert.assertEquals(1, map.size());
|
||||
Assert.assertTrue(map.containsValue(o1) != map.containsValue(o2));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testKeySetContains() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Set<String> keys = map.keySet();
|
||||
|
||||
Assert.assertTrue(keys.contains("a"));
|
||||
Assert.assertTrue(keys.contains("A"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testKeySetRemove() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Iterator<String> iter = map.keySet().iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
iter.next();
|
||||
iter.remove();
|
||||
Assert.assertTrue(map.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEntrySetRemove() {
|
||||
Object o1 = new Object();
|
||||
|
||||
CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
|
||||
map.put("a", o1);
|
||||
|
||||
Iterator<Entry<String,Object>> iter = map.entrySet().iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Entry<String,Object> entry = iter.next();
|
||||
Assert.assertEquals("a", entry.getKey());
|
||||
Assert.assertEquals(o1, entry.getValue());
|
||||
iter.remove();
|
||||
Assert.assertTrue(map.isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.collections;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestSynchronizedQueue {
|
||||
|
||||
public void testPollEmpty() {
|
||||
SynchronizedQueue<Object> queue = new SynchronizedQueue<>();
|
||||
Assert.assertNull(queue.poll());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOfferPollOrder() {
|
||||
SynchronizedQueue<Object> queue = new SynchronizedQueue<>();
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
queue.offer(o1);
|
||||
queue.offer(o2);
|
||||
queue.offer(o3);
|
||||
queue.offer(o4);
|
||||
|
||||
Assert.assertSame(queue.poll(), o1);
|
||||
Assert.assertSame(queue.poll(), o2);
|
||||
Assert.assertSame(queue.poll(), o3);
|
||||
Assert.assertSame(queue.poll(), o4);
|
||||
|
||||
Assert.assertNull(queue.poll());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandOfferPollOrder() {
|
||||
SynchronizedQueue<Object> queue = new SynchronizedQueue<>();
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
for (int i = 0; i < 300; i++) {
|
||||
queue.offer(o1);
|
||||
queue.offer(o2);
|
||||
queue.offer(o3);
|
||||
queue.offer(o4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 300; i++) {
|
||||
Assert.assertSame(queue.poll(), o1);
|
||||
Assert.assertSame(queue.poll(), o2);
|
||||
Assert.assertSame(queue.poll(), o3);
|
||||
Assert.assertSame(queue.poll(), o4);
|
||||
}
|
||||
|
||||
Assert.assertNull(queue.poll());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandOfferPollOrder2() {
|
||||
SynchronizedQueue<Object> queue = new SynchronizedQueue<>();
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
queue.offer(o1);
|
||||
queue.offer(o2);
|
||||
queue.offer(o3);
|
||||
queue.offer(o4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
Assert.assertSame(queue.poll(), o1);
|
||||
Assert.assertSame(queue.poll(), o2);
|
||||
Assert.assertSame(queue.poll(), o3);
|
||||
Assert.assertSame(queue.poll(), o4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 200; i++) {
|
||||
queue.offer(o1);
|
||||
queue.offer(o2);
|
||||
queue.offer(o3);
|
||||
queue.offer(o4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 250; i++) {
|
||||
Assert.assertSame(queue.poll(), o1);
|
||||
Assert.assertSame(queue.poll(), o2);
|
||||
Assert.assertSame(queue.poll(), o3);
|
||||
Assert.assertSame(queue.poll(), o4);
|
||||
}
|
||||
|
||||
|
||||
Assert.assertNull(queue.poll());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.collections;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestSynchronizedStack {
|
||||
|
||||
@Test
|
||||
public void testPopEmpty() {
|
||||
SynchronizedStack<Object> stack = new SynchronizedStack<>();
|
||||
Assert.assertNull(stack.pop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushPopOrder() {
|
||||
SynchronizedStack<Object> stack = new SynchronizedStack<>();
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
stack.push(o1);
|
||||
stack.push(o2);
|
||||
stack.push(o3);
|
||||
stack.push(o4);
|
||||
|
||||
Assert.assertSame(stack.pop(), o4);
|
||||
Assert.assertSame(stack.pop(), o3);
|
||||
Assert.assertSame(stack.pop(), o2);
|
||||
Assert.assertSame(stack.pop(), o1);
|
||||
|
||||
Assert.assertNull(stack.pop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandPushPopOrder() {
|
||||
SynchronizedStack<Object> stack = new SynchronizedStack<>();
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
for (int i = 0; i < 300; i++) {
|
||||
stack.push(o1);
|
||||
stack.push(o2);
|
||||
stack.push(o3);
|
||||
stack.push(o4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 300; i++) {
|
||||
Assert.assertSame(stack.pop(), o4);
|
||||
Assert.assertSame(stack.pop(), o3);
|
||||
Assert.assertSame(stack.pop(), o2);
|
||||
Assert.assertSame(stack.pop(), o1);
|
||||
}
|
||||
|
||||
Assert.assertNull(stack.pop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLimit() {
|
||||
SynchronizedStack<Object> stack = new SynchronizedStack<>(2,2);
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
stack.push(o1);
|
||||
stack.push(o2);
|
||||
stack.push(o3);
|
||||
stack.push(o4);
|
||||
|
||||
Assert.assertSame(stack.pop(), o2);
|
||||
Assert.assertSame(stack.pop(), o1);
|
||||
|
||||
Assert.assertNull(stack.pop());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLimitExpand() {
|
||||
SynchronizedStack<Object> stack = new SynchronizedStack<>(1,3);
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
Object o3 = new Object();
|
||||
Object o4 = new Object();
|
||||
|
||||
stack.push(o1);
|
||||
stack.push(o2);
|
||||
stack.push(o3);
|
||||
stack.push(o4);
|
||||
|
||||
Assert.assertSame(stack.pop(), o3);
|
||||
Assert.assertSame(stack.pop(), o2);
|
||||
Assert.assertSame(stack.pop(), o1);
|
||||
|
||||
Assert.assertNull(stack.pop());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.collections;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TesterPerformanceSynchronizedQueue {
|
||||
|
||||
private static final int THREAD_COUNT = 4;
|
||||
private static final int ITERATIONS = 1000000;
|
||||
|
||||
private static final SynchronizedQueue<Object> S_QUEUE =
|
||||
new SynchronizedQueue<>();
|
||||
|
||||
private static final Queue<Object> QUEUE = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@Test
|
||||
public void testSynchronizedQueue() throws InterruptedException {
|
||||
Thread[] threads = new Thread[THREAD_COUNT];
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i] = new StackThread();
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
System.out.println("SynchronizedQueue: " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
public static class StackThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for(int i = 0; i < ITERATIONS; i++) {
|
||||
Object obj = S_QUEUE.poll();
|
||||
if (obj == null) {
|
||||
obj = new Object();
|
||||
}
|
||||
S_QUEUE.offer(obj);
|
||||
}
|
||||
super.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentQueue() throws InterruptedException {
|
||||
Thread[] threads = new Thread[THREAD_COUNT];
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i] = new QueueThread();
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
System.out.println("ConcurrentLinkedQueue: " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
public static class QueueThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for(int i = 0; i < ITERATIONS; i++) {
|
||||
Object obj = QUEUE.poll();
|
||||
if (obj == null) {
|
||||
obj = new Object();
|
||||
}
|
||||
QUEUE.offer(obj);
|
||||
}
|
||||
super.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.collections;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TesterPerformanceSynchronizedStack {
|
||||
|
||||
private static final int THREAD_COUNT = 4;
|
||||
private static final int ITERATIONS = 1000000;
|
||||
|
||||
private static final SynchronizedStack<Object> STACK =
|
||||
new SynchronizedStack<>();
|
||||
|
||||
private static final Queue<Object> QUEUE = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@Test
|
||||
public void testSynchronizedStack() throws InterruptedException {
|
||||
Thread[] threads = new Thread[THREAD_COUNT];
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i] = new StackThread();
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
System.out.println("SynchronizedStack: " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
public static class StackThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for(int i = 0; i < ITERATIONS; i++) {
|
||||
Object obj = STACK.pop();
|
||||
if (obj == null) {
|
||||
obj = new Object();
|
||||
}
|
||||
STACK.push(obj);
|
||||
}
|
||||
super.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentQueue() throws InterruptedException {
|
||||
Thread[] threads = new Thread[THREAD_COUNT];
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i] = new QueueThread();
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
System.out.println("ConcurrentLinkedQueue: " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
public static class QueueThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for(int i = 0; i < ITERATIONS; i++) {
|
||||
Object obj = QUEUE.poll();
|
||||
if (obj == null) {
|
||||
obj = new Object();
|
||||
}
|
||||
QUEUE.offer(obj);
|
||||
}
|
||||
super.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
125
test/org/apache/tomcat/util/descriptor/TestLocalResolver.java
Normal file
125
test/org/apache/tomcat/util/descriptor/TestLocalResolver.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class TestLocalResolver {
|
||||
|
||||
private final Map<String, String> publicIds = new HashMap<>();
|
||||
private final Map<String, String> systemIds = new HashMap<>();
|
||||
|
||||
private LocalResolver resolver = new LocalResolver(publicIds, systemIds, true);
|
||||
private String WEB_22_LOCAL;
|
||||
private String WEB_31_LOCAL;
|
||||
private String WEBCOMMON_31_LOCAL;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
WEB_22_LOCAL = urlFor("resources/web-app_2_2.dtd");
|
||||
WEB_31_LOCAL = urlFor("resources/web-app_3_1.xsd");
|
||||
WEBCOMMON_31_LOCAL = urlFor("resources/web-common_3_1.xsd");
|
||||
publicIds.put(XmlIdentifiers.WEB_22_PUBLIC, WEB_22_LOCAL);
|
||||
systemIds.put(XmlIdentifiers.WEB_31_XSD, WEB_31_LOCAL);
|
||||
systemIds.put(WEBCOMMON_31_LOCAL, WEBCOMMON_31_LOCAL);
|
||||
}
|
||||
|
||||
public String urlFor(String id) {
|
||||
return ServletContext.class.getResource(id).toExternalForm();
|
||||
}
|
||||
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void unknownNullId() throws IOException, SAXException {
|
||||
Assert.assertNull(resolver.resolveEntity(null, null));
|
||||
}
|
||||
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void unknownPublicId() throws IOException, SAXException {
|
||||
Assert.assertNull(resolver.resolveEntity("unknown", null));
|
||||
}
|
||||
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void unknownSystemId() throws IOException, SAXException {
|
||||
InputSource source = resolver.resolveEntity(null, "unknown");
|
||||
Assert.assertEquals(null, source.getPublicId());
|
||||
Assert.assertEquals("unknown", source.getSystemId());
|
||||
}
|
||||
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void unknownRelativeSystemId()
|
||||
throws IOException, SAXException {
|
||||
InputSource source = resolver.resolveEntity(
|
||||
null, null, "http://example.com/home.html", "unknown");
|
||||
Assert.assertEquals(null, source.getPublicId());
|
||||
Assert.assertEquals("http://example.com/unknown", source.getSystemId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicIdIsResolved() throws IOException, SAXException {
|
||||
InputSource source = resolver.resolveEntity(
|
||||
XmlIdentifiers.WEB_22_PUBLIC, XmlIdentifiers.WEB_22_SYSTEM);
|
||||
Assert.assertEquals(XmlIdentifiers.WEB_22_PUBLIC, source.getPublicId());
|
||||
Assert.assertEquals(WEB_22_LOCAL, source.getSystemId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemIdIsIgnoredWhenPublicIdIsResolved()
|
||||
throws IOException, SAXException {
|
||||
InputSource source = resolver.resolveEntity(
|
||||
XmlIdentifiers.WEB_22_PUBLIC, "unknown");
|
||||
Assert.assertEquals(XmlIdentifiers.WEB_22_PUBLIC, source.getPublicId());
|
||||
Assert.assertEquals(WEB_22_LOCAL, source.getSystemId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemIdIsResolved() throws IOException, SAXException {
|
||||
InputSource source =
|
||||
resolver.resolveEntity(null, XmlIdentifiers.WEB_31_XSD);
|
||||
Assert.assertEquals(null, source.getPublicId());
|
||||
Assert.assertEquals(WEB_31_LOCAL, source.getSystemId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void relativeSystemIdIsResolvedAgainstBaseURI()
|
||||
throws IOException, SAXException {
|
||||
InputSource source = resolver.resolveEntity(
|
||||
null, null, WEB_31_LOCAL, "web-common_3_1.xsd");
|
||||
Assert.assertEquals(null, source.getPublicId());
|
||||
Assert.assertEquals(WEBCOMMON_31_LOCAL, source.getSystemId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void absoluteSystemIdOverridesBaseURI()
|
||||
throws IOException, SAXException {
|
||||
InputSource source = resolver.resolveEntity(null, null,
|
||||
"http://example.com/home.html", XmlIdentifiers.WEB_31_XSD);
|
||||
Assert.assertEquals(null, source.getPublicId());
|
||||
Assert.assertEquals(WEB_31_LOCAL, source.getSystemId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.tld;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
public class TestImplicitTldParser {
|
||||
private TldParser parser;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
parser = new TldParser(true, true, new ImplicitTldRuleSet(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitTldGood() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/implicit-good.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("2.1", xml.getJspVersion());
|
||||
Assert.assertEquals("Ignored", xml.getShortName());
|
||||
}
|
||||
|
||||
@Test(expected=SAXParseException.class)
|
||||
public void testImplicitTldBad() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/implicit-bad.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("2.1", xml.getJspVersion());
|
||||
Assert.assertEquals("Ignored", xml.getShortName());
|
||||
}
|
||||
|
||||
private TaglibXml parse(String pathname) throws IOException, SAXException {
|
||||
File file = new File(pathname);
|
||||
TldResourcePath path = new TldResourcePath(file.toURI().toURL(), null);
|
||||
return parser.parse(path);
|
||||
}
|
||||
|
||||
}
|
||||
173
test/org/apache/tomcat/util/descriptor/tld/TestTldParser.java
Normal file
173
test/org/apache/tomcat/util/descriptor/tld/TestTldParser.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.tld;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.jsp.tagext.FunctionInfo;
|
||||
import javax.servlet.jsp.tagext.TagAttributeInfo;
|
||||
import javax.servlet.jsp.tagext.TagVariableInfo;
|
||||
import javax.servlet.jsp.tagext.VariableInfo;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class TestTldParser {
|
||||
private TldParser parser;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
parser = new TldParser(true, true, new TldRuleSet(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTld() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/test.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("2.1", xml.getJspVersion());
|
||||
Assert.assertEquals("test", xml.getShortName());
|
||||
Assert.assertEquals("http://tomcat.apache.org/TldTests", xml.getUri());
|
||||
Assert.assertEquals(1, xml.getFunctions().size());
|
||||
|
||||
ValidatorXml validator = xml.getValidator();
|
||||
Assert.assertEquals("com.example.Validator", validator.getValidatorClass());
|
||||
Assert.assertEquals(1, validator.getInitParams().size());
|
||||
Assert.assertEquals("value", validator.getInitParams().get("name"));
|
||||
|
||||
Assert.assertEquals(1, xml.getTags().size());
|
||||
TagXml tag = xml.getTags().get(0);
|
||||
Assert.assertEquals("org.apache.jasper.compiler.TestValidator$Echo", tag.getTagClass());
|
||||
Assert.assertEquals("empty", tag.getBodyContent());
|
||||
Assert.assertTrue(tag.hasDynamicAttributes());
|
||||
|
||||
Assert.assertEquals(1, tag.getVariables().size());
|
||||
TagVariableInfo variableInfo = tag.getVariables().get(0);
|
||||
Assert.assertEquals("var", variableInfo.getNameGiven());
|
||||
Assert.assertEquals("java.lang.Object", variableInfo.getClassName());
|
||||
Assert.assertTrue(variableInfo.getDeclare());
|
||||
Assert.assertEquals(VariableInfo.AT_END, variableInfo.getScope());
|
||||
|
||||
Assert.assertEquals(4, tag.getAttributes().size());
|
||||
TagAttributeInfo attributeInfo = tag.getAttributes().get(0);
|
||||
Assert.assertEquals("Echo Tag", tag.getInfo());
|
||||
Assert.assertEquals("Echo", tag.getDisplayName());
|
||||
Assert.assertEquals("small", tag.getSmallIcon());
|
||||
Assert.assertEquals("large", tag.getLargeIcon());
|
||||
Assert.assertEquals("echo", attributeInfo.getName());
|
||||
Assert.assertTrue(attributeInfo.isRequired());
|
||||
Assert.assertTrue(attributeInfo.canBeRequestTime());
|
||||
|
||||
attributeInfo = tag.getAttributes().get(1);
|
||||
Assert.assertEquals("fragment", attributeInfo.getName());
|
||||
Assert.assertTrue(attributeInfo.isFragment());
|
||||
Assert.assertTrue(attributeInfo.canBeRequestTime());
|
||||
Assert.assertEquals("javax.servlet.jsp.tagext.JspFragment", attributeInfo.getTypeName());
|
||||
|
||||
attributeInfo = tag.getAttributes().get(2);
|
||||
Assert.assertEquals("deferredValue", attributeInfo.getName());
|
||||
Assert.assertEquals("javax.el.ValueExpression", attributeInfo.getTypeName());
|
||||
Assert.assertEquals("java.util.Date", attributeInfo.getExpectedTypeName());
|
||||
|
||||
attributeInfo = tag.getAttributes().get(3);
|
||||
Assert.assertEquals("deferredMethod", attributeInfo.getName());
|
||||
Assert.assertEquals("javax.el.MethodExpression", attributeInfo.getTypeName());
|
||||
Assert.assertEquals("java.util.Date getDate()", attributeInfo.getMethodSignature());
|
||||
|
||||
Assert.assertEquals(1, xml.getTagFiles().size());
|
||||
TagFileXml tagFile = xml.getTagFiles().get(0);
|
||||
Assert.assertEquals("Echo", tag.getDisplayName());
|
||||
Assert.assertEquals("small", tag.getSmallIcon());
|
||||
Assert.assertEquals("large", tag.getLargeIcon());
|
||||
Assert.assertEquals("Echo2", tagFile.getName());
|
||||
Assert.assertEquals("/echo.tag", tagFile.getPath());
|
||||
|
||||
Assert.assertEquals(1, xml.getFunctions().size());
|
||||
FunctionInfo fn = xml.getFunctions().get(0);
|
||||
Assert.assertEquals("trim", fn.getName());
|
||||
Assert.assertEquals("org.apache.el.TesterFunctions", fn.getFunctionClass());
|
||||
Assert.assertEquals("java.lang.String trim(java.lang.String)", fn.getFunctionSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTld21() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/tags21.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("2.1", xml.getJspVersion());
|
||||
Assert.assertEquals("Tags21", xml.getShortName());
|
||||
Assert.assertEquals("http://tomcat.apache.org/tags21", xml.getUri());
|
||||
verifyTags(xml.getTags());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTld20() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/tags20.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("2.0", xml.getJspVersion());
|
||||
Assert.assertEquals("Tags20", xml.getShortName());
|
||||
Assert.assertEquals("http://tomcat.apache.org/tags20", xml.getUri());
|
||||
verifyTags(xml.getTags());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTld12() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/tags12.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("1.2", xml.getJspVersion());
|
||||
Assert.assertEquals("Tags12", xml.getShortName());
|
||||
Assert.assertEquals("http://tomcat.apache.org/tags12", xml.getUri());
|
||||
verifyTags(xml.getTags());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTld11() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/tags11.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
Assert.assertEquals("1.1", xml.getJspVersion());
|
||||
Assert.assertEquals("Tags11", xml.getShortName());
|
||||
Assert.assertEquals("http://tomcat.apache.org/tags11", xml.getUri());
|
||||
verifyTags(xml.getTags());
|
||||
}
|
||||
|
||||
private void verifyTags(List<TagXml> tags) {
|
||||
Assert.assertEquals(1, tags.size());
|
||||
TagXml tag = tags.get(0);
|
||||
Assert.assertEquals("Echo", tag.getName());
|
||||
Assert.assertEquals("org.apache.jasper.compiler.TestValidator$Echo", tag.getTagClass());
|
||||
Assert.assertEquals("empty", tag.getBodyContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListener() throws Exception {
|
||||
TaglibXml xml = parse("test/tld/listener.tld");
|
||||
Assert.assertEquals("1.0", xml.getTlibVersion());
|
||||
List<String> listeners = xml.getListeners();
|
||||
Assert.assertEquals(1, listeners.size());
|
||||
Assert.assertEquals("org.apache.catalina.core.TesterTldListener", listeners.get(0));
|
||||
}
|
||||
|
||||
private TaglibXml parse(String pathname) throws IOException, SAXException {
|
||||
File file = new File(pathname);
|
||||
TldResourcePath path = new TldResourcePath(file.toURI().toURL(), null);
|
||||
return parser.parse(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link FilterDef}.
|
||||
*/
|
||||
public class TestFilterDef {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetFilterNameNull() {
|
||||
new FilterDef().setFilterName(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetFilterNameEmptyString() {
|
||||
new FilterDef().setFilterName("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFilterName() {
|
||||
FilterDef filterDef = new FilterDef();
|
||||
filterDef.setFilterName("test");
|
||||
Assert.assertEquals("'test' is expected as filter name",
|
||||
"test", filterDef.getFilterName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.descriptor.JspConfigDescriptor;
|
||||
import javax.servlet.descriptor.JspPropertyGroupDescriptor;
|
||||
import javax.servlet.descriptor.TaglibDescriptor;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestJspConfigDescriptorImpl {
|
||||
|
||||
@Test
|
||||
public void testTaglibsAreIsolate() {
|
||||
List<TaglibDescriptor> taglibs = new ArrayList<>();
|
||||
taglibs.add(new TaglibDescriptorImpl("location", "uri"));
|
||||
List<JspPropertyGroupDescriptor> propertyGroups = Collections.emptyList();
|
||||
JspConfigDescriptor descriptor = new JspConfigDescriptorImpl(propertyGroups, taglibs);
|
||||
descriptor.getTaglibs().clear();
|
||||
Assert.assertEquals(taglibs, descriptor.getTaglibs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyGroupsAreIsolate() {
|
||||
List<TaglibDescriptor> taglibs = Collections.emptyList();
|
||||
List<JspPropertyGroupDescriptor> propertyGroups = new ArrayList<>();
|
||||
propertyGroups.add(new JspPropertyGroupDescriptorImpl(new JspPropertyGroup()));
|
||||
JspConfigDescriptor descriptor = new JspConfigDescriptorImpl(propertyGroups, taglibs);
|
||||
descriptor.getJspPropertyGroups().clear();
|
||||
Assert.assertEquals(propertyGroups, descriptor.getJspPropertyGroups());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestJspPropertyGroup {
|
||||
|
||||
private JspPropertyGroup group = new JspPropertyGroup();
|
||||
|
||||
@Test
|
||||
public void testBug55262() {
|
||||
group.addIncludePrelude("/prelude");
|
||||
group.addIncludePrelude("/prelude");
|
||||
group.addIncludeCoda("/coda");
|
||||
group.addIncludeCoda("/coda");
|
||||
Assert.assertEquals(2, group.getIncludePreludes().size());
|
||||
Assert.assertEquals(2, group.getIncludeCodas().size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestJspPropertyGroupDescriptorImpl {
|
||||
|
||||
@Test
|
||||
public void testPreludesAreIsolated() {
|
||||
JspPropertyGroup jpg = new JspPropertyGroup();
|
||||
jpg.addIncludePrelude("prelude");
|
||||
JspPropertyGroupDescriptorImpl descriptor = new JspPropertyGroupDescriptorImpl(jpg);
|
||||
descriptor.getIncludePreludes().clear();
|
||||
Assert.assertEquals(1, descriptor.getIncludePreludes().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCodasAreIsolated() {
|
||||
JspPropertyGroup jpg = new JspPropertyGroup();
|
||||
jpg.addIncludeCoda("coda");
|
||||
JspPropertyGroupDescriptorImpl descriptor = new JspPropertyGroupDescriptorImpl(jpg);
|
||||
descriptor.getIncludeCodas().clear();
|
||||
Assert.assertEquals(1, descriptor.getIncludeCodas().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUrlPatternsAreIsolated() {
|
||||
JspPropertyGroup jpg = new JspPropertyGroup();
|
||||
jpg.addUrlPatternDecoded("pattern");
|
||||
JspPropertyGroupDescriptorImpl descriptor = new JspPropertyGroupDescriptorImpl(jpg);
|
||||
descriptor.getUrlPatterns().clear();
|
||||
Assert.assertEquals(1, descriptor.getUrlPatterns().size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.HttpConstraintElement;
|
||||
import javax.servlet.HttpMethodConstraintElement;
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
import javax.servlet.annotation.ServletSecurity;
|
||||
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public class TestSecurityConstraint {
|
||||
|
||||
private static final String URL_PATTERN = "/test";
|
||||
private static final String ROLE1 = "R1";
|
||||
|
||||
private static final Log DUMMY_LOG = LogFactory.getLog("DUMMY");
|
||||
|
||||
private static final SecurityConstraint GET_ONLY;
|
||||
private static final SecurityConstraint POST_ONLY;
|
||||
|
||||
private static final SecurityConstraint GET_OMIT;
|
||||
private static final SecurityConstraint POST_OMIT;
|
||||
|
||||
static {
|
||||
// Configure the constraints to use in the tests
|
||||
GET_ONLY = new SecurityConstraint();
|
||||
GET_ONLY.addAuthRole(ROLE1);
|
||||
SecurityCollection scGetOnly = new SecurityCollection();
|
||||
scGetOnly.addMethod("GET");
|
||||
scGetOnly.addPatternDecoded(URL_PATTERN);
|
||||
scGetOnly.setName("GET-ONLY");
|
||||
GET_ONLY.addCollection(scGetOnly);
|
||||
|
||||
POST_ONLY = new SecurityConstraint();
|
||||
POST_ONLY.addAuthRole(ROLE1);
|
||||
SecurityCollection scPostOnly = new SecurityCollection();
|
||||
scPostOnly.addMethod("POST");
|
||||
scPostOnly.addPatternDecoded(URL_PATTERN);
|
||||
scPostOnly.setName("POST_ONLY");
|
||||
POST_ONLY.addCollection(scPostOnly);
|
||||
|
||||
GET_OMIT = new SecurityConstraint();
|
||||
GET_OMIT.addAuthRole(ROLE1);
|
||||
SecurityCollection scGetOmit = new SecurityCollection();
|
||||
scGetOmit.addOmittedMethod("GET");
|
||||
scGetOmit.addPatternDecoded(URL_PATTERN);
|
||||
scGetOmit.setName("GET_OMIT");
|
||||
GET_OMIT.addCollection(scGetOmit);
|
||||
|
||||
POST_OMIT = new SecurityConstraint();
|
||||
POST_OMIT.addAuthRole(ROLE1);
|
||||
SecurityCollection scPostOmit = new SecurityCollection();
|
||||
scPostOmit.addOmittedMethod("POST");
|
||||
scPostOmit.addPatternDecoded(URL_PATTERN);
|
||||
scPostOmit.setName("POST_OMIT");
|
||||
POST_OMIT.addCollection(scPostOmit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the examples in SRV.13.4 as the basis for these tests
|
||||
*/
|
||||
@Test
|
||||
public void testCreateConstraints() {
|
||||
|
||||
ServletSecurityElement element;
|
||||
SecurityConstraint[] result;
|
||||
Set<HttpMethodConstraintElement> hmces = new HashSet<>();
|
||||
|
||||
// Example 13-1
|
||||
// @ServletSecurity
|
||||
element = new ServletSecurityElement();
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(0, result.length);
|
||||
|
||||
// Example 13-2
|
||||
// @ServletSecurity(
|
||||
// @HttpConstraint(
|
||||
// transportGuarantee = TransportGuarantee.CONFIDENTIAL))
|
||||
element = new ServletSecurityElement(
|
||||
new HttpConstraintElement(
|
||||
ServletSecurity.TransportGuarantee.CONFIDENTIAL));
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(1, result.length);
|
||||
Assert.assertFalse(result[0].getAuthConstraint());
|
||||
Assert.assertTrue(result[0].findCollections()[0].findPattern(URL_PATTERN));
|
||||
Assert.assertEquals(0, result[0].findCollections()[0].findMethods().length);
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.CONFIDENTIAL.name(),
|
||||
result[0].getUserConstraint());
|
||||
|
||||
// Example 13-3
|
||||
// @ServletSecurity(@HttpConstraint(EmptyRoleSemantic.DENY))
|
||||
element = new ServletSecurityElement(
|
||||
new HttpConstraintElement(EmptyRoleSemantic.DENY));
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(1, result.length);
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
Assert.assertTrue(result[0].findCollections()[0].findPattern(URL_PATTERN));
|
||||
Assert.assertEquals(0, result[0].findCollections()[0].findMethods().length);
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
|
||||
result[0].getUserConstraint());
|
||||
|
||||
// Example 13-4
|
||||
// @ServletSecurity(@HttpConstraint(rolesAllowed = "R1"))
|
||||
element = new ServletSecurityElement(new HttpConstraintElement(
|
||||
ServletSecurity.TransportGuarantee.NONE, ROLE1));
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(1, result.length);
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
Assert.assertEquals(1, result[0].findAuthRoles().length);
|
||||
Assert.assertTrue(result[0].findAuthRole(ROLE1));
|
||||
Assert.assertTrue(result[0].findCollections()[0].findPattern(URL_PATTERN));
|
||||
Assert.assertEquals(0, result[0].findCollections()[0].findMethods().length);
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
|
||||
result[0].getUserConstraint());
|
||||
|
||||
// Example 13-5
|
||||
// @ServletSecurity((httpMethodConstraints = {
|
||||
// @HttpMethodConstraint(value = "GET", rolesAllowed = "R1"),
|
||||
// @HttpMethodConstraint(value = "POST", rolesAllowed = "R1",
|
||||
// transportGuarantee = TransportGuarantee.CONFIDENTIAL)
|
||||
// })
|
||||
hmces.clear();
|
||||
hmces.add(new HttpMethodConstraintElement("GET",
|
||||
new HttpConstraintElement(
|
||||
ServletSecurity.TransportGuarantee.NONE, ROLE1)));
|
||||
hmces.add(new HttpMethodConstraintElement("POST",
|
||||
new HttpConstraintElement(
|
||||
ServletSecurity.TransportGuarantee.CONFIDENTIAL,
|
||||
ROLE1)));
|
||||
element = new ServletSecurityElement(hmces);
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(2, result.length);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assert.assertTrue(result[i].getAuthConstraint());
|
||||
Assert.assertEquals(1, result[i].findAuthRoles().length);
|
||||
Assert.assertTrue(result[i].findAuthRole(ROLE1));
|
||||
Assert.assertTrue(result[i].findCollections()[0].findPattern(URL_PATTERN));
|
||||
Assert.assertEquals(1, result[i].findCollections()[0].findMethods().length);
|
||||
String method = result[i].findCollections()[0].findMethods()[0];
|
||||
if ("GET".equals(method)) {
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
|
||||
result[i].getUserConstraint());
|
||||
} else if ("POST".equals(method)) {
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.CONFIDENTIAL.name(),
|
||||
result[i].getUserConstraint());
|
||||
} else {
|
||||
Assert.fail("Unexpected method :[" + method + "]");
|
||||
}
|
||||
}
|
||||
|
||||
// Example 13-6
|
||||
// @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"),
|
||||
// httpMethodConstraints = @HttpMethodConstraint("GET"))
|
||||
hmces.clear();
|
||||
hmces.add(new HttpMethodConstraintElement("GET"));
|
||||
element = new ServletSecurityElement(
|
||||
new HttpConstraintElement(
|
||||
ServletSecurity.TransportGuarantee.NONE,
|
||||
ROLE1),
|
||||
hmces);
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(2, result.length);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assert.assertTrue(result[i].findCollections()[0].findPattern(URL_PATTERN));
|
||||
if (result[i].findCollections()[0].findMethods().length == 1) {
|
||||
Assert.assertEquals("GET",
|
||||
result[i].findCollections()[0].findMethods()[0]);
|
||||
Assert.assertFalse(result[i].getAuthConstraint());
|
||||
} else if (result[i].findCollections()[0].findOmittedMethods().length == 1) {
|
||||
Assert.assertEquals("GET",
|
||||
result[i].findCollections()[0].findOmittedMethods()[0]);
|
||||
Assert.assertTrue(result[i].getAuthConstraint());
|
||||
Assert.assertEquals(1, result[i].findAuthRoles().length);
|
||||
Assert.assertEquals(ROLE1, result[i].findAuthRoles()[0]);
|
||||
} else {
|
||||
Assert.fail("Unexpected number of methods defined");
|
||||
}
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
|
||||
result[i].getUserConstraint());
|
||||
}
|
||||
|
||||
// Example 13-7
|
||||
// @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"),
|
||||
// httpMethodConstraints = @HttpMethodConstraint(value="TRACE",
|
||||
// emptyRoleSemantic = EmptyRoleSemantic.DENY))
|
||||
hmces.clear();
|
||||
hmces.add(new HttpMethodConstraintElement("TRACE",
|
||||
new HttpConstraintElement(EmptyRoleSemantic.DENY)));
|
||||
element = new ServletSecurityElement(
|
||||
new HttpConstraintElement(
|
||||
ServletSecurity.TransportGuarantee.NONE,
|
||||
ROLE1),
|
||||
hmces);
|
||||
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
|
||||
|
||||
Assert.assertEquals(2, result.length);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assert.assertTrue(result[i].findCollections()[0].findPattern(URL_PATTERN));
|
||||
if (result[i].findCollections()[0].findMethods().length == 1) {
|
||||
Assert.assertEquals("TRACE",
|
||||
result[i].findCollections()[0].findMethods()[0]);
|
||||
Assert.assertTrue(result[i].getAuthConstraint());
|
||||
Assert.assertEquals(0, result[i].findAuthRoles().length);
|
||||
} else if (result[i].findCollections()[0].findOmittedMethods().length == 1) {
|
||||
Assert.assertEquals("TRACE",
|
||||
result[i].findCollections()[0].findOmittedMethods()[0]);
|
||||
Assert.assertTrue(result[i].getAuthConstraint());
|
||||
Assert.assertEquals(1, result[i].findAuthRoles().length);
|
||||
Assert.assertEquals(ROLE1, result[i].findAuthRoles()[0]);
|
||||
} else {
|
||||
Assert.fail("Unexpected number of methods defined");
|
||||
}
|
||||
Assert.assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
|
||||
result[i].getUserConstraint());
|
||||
}
|
||||
|
||||
// Example 13-8 is the same as 13-4
|
||||
// Example 13-9 is the same as 13-7
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods01() {
|
||||
// No new constraints if denyUncoveredHttpMethods is false
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_ONLY}, false, DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods02() {
|
||||
// No new constraints if denyUncoveredHttpMethods is false
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_OMIT}, false, DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods03() {
|
||||
// No new constraints if denyUncoveredHttpMethods is false
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {POST_ONLY}, false, DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods04() {
|
||||
// No new constraints if denyUncoveredHttpMethods is false
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {POST_OMIT}, false, DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods05() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_ONLY}, true, DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list GET as an omitted method
|
||||
Assert.assertEquals(0, sc.findMethods().length);
|
||||
Assert.assertEquals(1, sc.findOmittedMethods().length);
|
||||
Assert.assertEquals("GET", sc.findOmittedMethods()[0]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods06() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {POST_ONLY}, true, DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list POST as an omitted method
|
||||
Assert.assertEquals(0, sc.findMethods().length);
|
||||
Assert.assertEquals(1, sc.findOmittedMethods().length);
|
||||
Assert.assertEquals("POST", sc.findOmittedMethods()[0]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods07() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_OMIT}, true, DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list GET as an method
|
||||
Assert.assertEquals(0, sc.findOmittedMethods().length);
|
||||
Assert.assertEquals(1, sc.findMethods().length);
|
||||
Assert.assertEquals("GET", sc.findMethods()[0]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods08() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {POST_OMIT}, true, DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list POST as an method
|
||||
Assert.assertEquals(0, sc.findOmittedMethods().length);
|
||||
Assert.assertEquals(1, sc.findMethods().length);
|
||||
Assert.assertEquals("POST", sc.findMethods()[0]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods09() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_ONLY, GET_OMIT}, true,
|
||||
DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods10() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {POST_ONLY, POST_OMIT}, true,
|
||||
DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods11() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_ONLY, POST_ONLY}, true,
|
||||
DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list GET and POST as omitted methods
|
||||
Assert.assertEquals(0, sc.findMethods().length);
|
||||
Assert.assertEquals(2, sc.findOmittedMethods().length);
|
||||
HashSet<String> omittedMethods = new HashSet<>();
|
||||
for (String omittedMethod : sc.findOmittedMethods()) {
|
||||
omittedMethods.add(omittedMethod);
|
||||
}
|
||||
Assert.assertTrue(omittedMethods.remove("GET"));
|
||||
Assert.assertTrue(omittedMethods.remove("POST"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods12() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_OMIT, POST_OMIT}, true,
|
||||
DUMMY_LOG);
|
||||
Assert.assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods13() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_ONLY, POST_OMIT}, true,
|
||||
DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list POST as a method
|
||||
Assert.assertEquals(1, sc.findMethods().length);
|
||||
Assert.assertEquals(0, sc.findOmittedMethods().length);
|
||||
Assert.assertEquals("POST", sc.findMethods()[0]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindUncoveredHttpMethods14() {
|
||||
SecurityConstraint[] result =
|
||||
SecurityConstraint.findUncoveredHttpMethods(
|
||||
new SecurityConstraint[] {GET_OMIT, POST_ONLY}, true,
|
||||
DUMMY_LOG);
|
||||
Assert.assertEquals(1, result.length);
|
||||
// Should be a deny constraint
|
||||
Assert.assertTrue(result[0].getAuthConstraint());
|
||||
// Should have a single collection
|
||||
Assert.assertEquals(1, result[0].findCollections().length);
|
||||
SecurityCollection sc = result[0].findCollections()[0];
|
||||
// Should list GET as a method
|
||||
Assert.assertEquals(1, sc.findMethods().length);
|
||||
Assert.assertEquals(0, sc.findOmittedMethods().length);
|
||||
Assert.assertEquals("GET", sc.findMethods()[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link ServletDef}
|
||||
*/
|
||||
public class TestServletDef {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetServletNameNull() {
|
||||
new ServletDef().setServletName(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetServletNameEmptyString() {
|
||||
new ServletDef().setServletName("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetServletName() {
|
||||
ServletDef servletDef = new ServletDef();
|
||||
servletDef.setServletName("test");
|
||||
Assert.assertEquals("'test' is expected as servlet name",
|
||||
"test", servletDef.getServletName());
|
||||
}
|
||||
|
||||
}
|
||||
155
test/org/apache/tomcat/util/descriptor/web/TestWebRuleSet.java
Normal file
155
test/org/apache/tomcat/util/descriptor/web/TestWebRuleSet.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
|
||||
public class TestWebRuleSet {
|
||||
|
||||
private Digester fragmentDigester = new Digester();
|
||||
private WebRuleSet fragmentRuleSet = new WebRuleSet(true);
|
||||
|
||||
private Digester webDigester = new Digester();
|
||||
private WebRuleSet webRuleSet = new WebRuleSet(false);
|
||||
|
||||
public TestWebRuleSet() {
|
||||
fragmentDigester.addRuleSet(fragmentRuleSet);
|
||||
webDigester.addRuleSet(webRuleSet);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingleNameInWebFragmentXml() throws Exception {
|
||||
|
||||
WebXml webXml = new WebXml();
|
||||
|
||||
parse(webXml, "web-fragment-1name.xml", true, true);
|
||||
Assert.assertEquals("name1", webXml.getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleNameInWebFragmentXml() throws Exception {
|
||||
parse(new WebXml(), "web-fragment-2name.xml", true, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingleOrderingInWebFragmentXml() throws Exception {
|
||||
|
||||
WebXml webXml = new WebXml();
|
||||
|
||||
parse(webXml, "web-fragment-1ordering.xml", true, true);
|
||||
Assert.assertEquals(1, webXml.getBeforeOrdering().size());
|
||||
Assert.assertTrue(webXml.getBeforeOrdering().contains("bar"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleOrderingInWebFragmentXml() throws Exception {
|
||||
parse(new WebXml(), "web-fragment-2ordering.xml", true, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingleOrderingInWebXml() throws Exception {
|
||||
|
||||
WebXml webXml = new WebXml();
|
||||
|
||||
parse(webXml, "web-1ordering.xml", false, true);
|
||||
Assert.assertEquals(1, webXml.getAbsoluteOrdering().size());
|
||||
Assert.assertTrue(webXml.getAbsoluteOrdering().contains("bar"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleOrderingInWebXml() throws Exception {
|
||||
parse(new WebXml(), "web-2ordering.xml", false, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRecycle() throws Exception {
|
||||
// Name
|
||||
parse(new WebXml(), "web-fragment-2name.xml", true, false);
|
||||
parse(new WebXml(), "web-fragment-1name.xml", true, true);
|
||||
parse(new WebXml(), "web-fragment-2name.xml", true, false);
|
||||
parse(new WebXml(), "web-fragment-1name.xml", true, true);
|
||||
|
||||
// Relative ordering
|
||||
parse(new WebXml(), "web-fragment-2ordering.xml", true, false);
|
||||
parse(new WebXml(), "web-fragment-1ordering.xml", true, true);
|
||||
parse(new WebXml(), "web-fragment-2ordering.xml", true, false);
|
||||
parse(new WebXml(), "web-fragment-1ordering.xml", true, true);
|
||||
|
||||
// Absolute ordering
|
||||
parse(new WebXml(), "web-2ordering.xml", false, false);
|
||||
parse(new WebXml(), "web-1ordering.xml", false, true);
|
||||
parse(new WebXml(), "web-2ordering.xml", false, false);
|
||||
parse(new WebXml(), "web-1ordering.xml", false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleMethodsDefinitions() throws Exception {
|
||||
// post-construct and pre-destroy
|
||||
parse(new WebXml(), "web-1lifecyclecallback.xml", false, true);
|
||||
// conflicting post-construct definitions
|
||||
parse(new WebXml(), "web-2lifecyclecallback.xml", false, false);
|
||||
}
|
||||
|
||||
private synchronized void parse(WebXml webXml, String target,
|
||||
boolean fragment, boolean expected) {
|
||||
|
||||
Digester d;
|
||||
if (fragment) {
|
||||
d = fragmentDigester;
|
||||
fragmentRuleSet.recycle();
|
||||
} else {
|
||||
d = webDigester;
|
||||
webRuleSet.recycle();
|
||||
}
|
||||
|
||||
d.push(webXml);
|
||||
|
||||
File f = new File("test/org/apache/catalina/startup/" + target);
|
||||
|
||||
boolean result = true;
|
||||
|
||||
try (InputStream is = new FileInputStream(f);) {
|
||||
d.parse(is);
|
||||
} catch (Exception e) {
|
||||
if (expected) {
|
||||
// Didn't expect an exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (expected) {
|
||||
Assert.assertTrue(result);
|
||||
} else {
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
473
test/org/apache/tomcat/util/descriptor/web/TestWebXml.java
Normal file
473
test/org/apache/tomcat/util/descriptor/web/TestWebXml.java
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.descriptor.DigesterFactory;
|
||||
import org.apache.tomcat.util.descriptor.XmlErrorHandler;
|
||||
import org.apache.tomcat.util.descriptor.XmlIdentifiers;
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Test case for {@link WebXml}.
|
||||
*/
|
||||
public class TestWebXml {
|
||||
|
||||
@Test
|
||||
public void testParseVersion() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
// Defaults
|
||||
Assert.assertEquals(3, webxml.getMajorVersion());
|
||||
Assert.assertEquals(1, webxml.getMinorVersion());
|
||||
|
||||
// Both get changed
|
||||
webxml.setVersion("2.5");
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(5, webxml.getMinorVersion());
|
||||
|
||||
// unknown input should be ignored
|
||||
webxml.setVersion("0.0");
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(5, webxml.getMinorVersion());
|
||||
|
||||
// null input should be ignored
|
||||
webxml.setVersion(null);
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(5, webxml.getMinorVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsePublicIdVersion22() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
webxml.setPublicId(XmlIdentifiers.WEB_22_PUBLIC);
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(2, webxml.getMinorVersion());
|
||||
Assert.assertEquals("2.2", webxml.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsePublicIdVersion23() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
webxml.setPublicId(XmlIdentifiers.WEB_23_PUBLIC);
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(3, webxml.getMinorVersion());
|
||||
Assert.assertEquals("2.3", webxml.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseVersion24() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
webxml.setVersion("2.4");
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(4, webxml.getMinorVersion());
|
||||
Assert.assertEquals("2.4", webxml.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseVersion25() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
webxml.setVersion("2.5");
|
||||
Assert.assertEquals(2, webxml.getMajorVersion());
|
||||
Assert.assertEquals(5, webxml.getMinorVersion());
|
||||
Assert.assertEquals("2.5", webxml.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseVersion30() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
webxml.setVersion("3.0");
|
||||
Assert.assertEquals(3, webxml.getMajorVersion());
|
||||
Assert.assertEquals(0, webxml.getMinorVersion());
|
||||
Assert.assertEquals("3.0", webxml.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseVersion31() {
|
||||
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
webxml.setVersion("3.1");
|
||||
Assert.assertEquals(3, webxml.getMajorVersion());
|
||||
Assert.assertEquals(1, webxml.getMinorVersion());
|
||||
Assert.assertEquals("3.1", webxml.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateVersion22() throws IOException, SAXException {
|
||||
doTestValidateVersion("2.2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateVersion23() throws IOException, SAXException {
|
||||
doTestValidateVersion("2.3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateVersion24() throws IOException, SAXException {
|
||||
doTestValidateVersion("2.4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateVersion25() throws IOException, SAXException {
|
||||
doTestValidateVersion("2.5");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateVersion30() throws IOException, SAXException {
|
||||
doTestValidateVersion("3.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateVersion31() throws IOException, SAXException {
|
||||
doTestValidateVersion("3.1");
|
||||
}
|
||||
|
||||
private void doTestValidateVersion(String version) throws IOException, SAXException {
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
// Special cases
|
||||
if ("2.2".equals(version)) {
|
||||
webxml.setPublicId(XmlIdentifiers.WEB_22_PUBLIC);
|
||||
} else if ("2.3".equals(version)) {
|
||||
webxml.setPublicId(XmlIdentifiers.WEB_23_PUBLIC);
|
||||
} else {
|
||||
webxml.setVersion(version);
|
||||
}
|
||||
|
||||
// Merged web.xml that is published as MERGED_WEB_XML context attribute
|
||||
// in the simplest case consists of webapp's web.xml file
|
||||
// plus the default conf/web.xml one.
|
||||
Set<WebXml> defaults = new HashSet<>();
|
||||
defaults.add(getDefaultWebXmlFragment());
|
||||
webxml.merge(defaults);
|
||||
|
||||
Digester digester = DigesterFactory.newDigester(true, true, new WebRuleSet(), true);
|
||||
|
||||
XmlErrorHandler handler = new XmlErrorHandler();
|
||||
digester.setErrorHandler(handler);
|
||||
|
||||
InputSource is = new InputSource(new StringReader(webxml.toXml()));
|
||||
WebXml webxmlResult = new WebXml();
|
||||
digester.push(webxmlResult);
|
||||
digester.parse(is);
|
||||
|
||||
Assert.assertEquals(0, handler.getErrors().size());
|
||||
Assert.assertEquals(0, handler.getWarnings().size());
|
||||
|
||||
Assert.assertEquals(version, webxml.getVersion());
|
||||
Assert.assertEquals(version, webxmlResult.getVersion());
|
||||
}
|
||||
|
||||
// A simplified copy of ContextConfig.getDefaultWebXmlFragment().
|
||||
// Assuming that global web.xml exists, host-specific web.xml does not exist.
|
||||
private WebXml getDefaultWebXmlFragment() throws IOException, SAXException {
|
||||
InputSource globalWebXml = new InputSource(new File("conf/web.xml")
|
||||
.getAbsoluteFile().toURI().toString());
|
||||
|
||||
WebXml webXmlDefaultFragment = new WebXml();
|
||||
webXmlDefaultFragment.setOverridable(true);
|
||||
webXmlDefaultFragment.setDistributable(true);
|
||||
webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);
|
||||
|
||||
Digester digester = DigesterFactory.newDigester(true, true, new WebRuleSet(), true);
|
||||
XmlErrorHandler handler = new XmlErrorHandler();
|
||||
digester.setErrorHandler(handler);
|
||||
digester.push(webXmlDefaultFragment);
|
||||
digester.parse(globalWebXml);
|
||||
Assert.assertEquals(0, handler.getErrors().size());
|
||||
Assert.assertEquals(0, handler.getWarnings().size());
|
||||
|
||||
webXmlDefaultFragment.setReplaceWelcomeFiles(true);
|
||||
|
||||
// Assert that web.xml was parsed and is not empty. Default servlet is known to be there.
|
||||
Assert.assertNotNull(webXmlDefaultFragment.getServlets().get("default"));
|
||||
|
||||
// Manually add some version specific features to ensure that these do
|
||||
// not cause problems for the merged web.xml
|
||||
|
||||
// Filters were added in 2.3 so should be excluded in 2.2
|
||||
FilterDef filterDef = new FilterDef();
|
||||
filterDef.setFilterClass("org.apache.tomcat.DummyFilter");
|
||||
filterDef.setFilterName("Dummy");
|
||||
webXmlDefaultFragment.addFilter(filterDef);
|
||||
|
||||
FilterMap filterMap = new FilterMap();
|
||||
filterMap.setFilterName("Dummy");
|
||||
filterMap.addURLPatternDecoded("/*");
|
||||
webXmlDefaultFragment.addFilterMapping(filterMap);
|
||||
|
||||
// Listeners were added in 2.3 so should be excluded in 2.2
|
||||
webXmlDefaultFragment.addListener("org.apache.tomcat.DummyListener");
|
||||
|
||||
// resource-env-ref was added in 2.3 so should be excluded in 2.2
|
||||
ContextResourceEnvRef resourceEnvRef = new ContextResourceEnvRef();
|
||||
resourceEnvRef.setName("dummy");
|
||||
resourceEnvRef.setType("dummy");
|
||||
|
||||
webXmlDefaultFragment.addResourceEnvRef(resourceEnvRef);
|
||||
|
||||
// ejb-local-ref was added in 2.3 so should be excluded in 2.2
|
||||
ContextLocalEjb ejbLocalRef = new ContextLocalEjb();
|
||||
ejbLocalRef.setName("dummy");
|
||||
ejbLocalRef.setType("Session");
|
||||
ejbLocalRef.setLocal("dummy");
|
||||
ejbLocalRef.setHome("dummy");
|
||||
webXmlDefaultFragment.addEjbLocalRef(ejbLocalRef);
|
||||
|
||||
// Servlet/run-as was added in 2.3 so should be excluded in 2.2
|
||||
ServletDef servletDef = new ServletDef();
|
||||
servletDef.setServletName("Dummy");
|
||||
servletDef.setServletClass("org.apache.tomcat.DummyServlet");
|
||||
servletDef.setRunAs("dummy");
|
||||
webXmlDefaultFragment.addServlet(servletDef);
|
||||
|
||||
webXmlDefaultFragment.addServletMapping("/dummy", "Dummy");
|
||||
|
||||
// resource-ref/res-sharing-scope was added in 2.3 so should be excluded
|
||||
// in 2.2
|
||||
ContextResource contextResource = new ContextResource();
|
||||
contextResource.setName("dummy");
|
||||
contextResource.setType("dummy");
|
||||
contextResource.setAuth("Container");
|
||||
contextResource.setScope("Shareable");
|
||||
webXmlDefaultFragment.addResourceRef(contextResource);
|
||||
|
||||
// security-constraint/display-name was added in 2.3 so should be
|
||||
// excluded in 2.2
|
||||
SecurityConstraint sc = new SecurityConstraint();
|
||||
sc.setDisplayName("dummy");
|
||||
SecurityCollection collection = new SecurityCollection();
|
||||
collection.setName("dummy");
|
||||
collection.addPatternDecoded("/*");
|
||||
collection.addMethod("DELETE");
|
||||
sc.addCollection(collection);
|
||||
webXmlDefaultFragment.addSecurityConstraint(sc);
|
||||
|
||||
// service-ref was added in 2.4 so should be excluded in 2.3 and earlier
|
||||
ContextService serviceRef = new ContextService();
|
||||
serviceRef.setName("dummy");
|
||||
serviceRef.setInterface("dummy");
|
||||
webXmlDefaultFragment.addServiceRef(serviceRef);
|
||||
|
||||
// message-destination-ref was added in 2.4 so should be excluded in 2.3
|
||||
// and earlier
|
||||
MessageDestinationRef mdRef = new MessageDestinationRef();
|
||||
mdRef.setName("dummy");
|
||||
mdRef.setType("dummy");
|
||||
mdRef.setUsage("Consumes");
|
||||
webXmlDefaultFragment.addMessageDestinationRef(mdRef);
|
||||
|
||||
// message-destination was added in 2.4 so should be excluded in 2.3
|
||||
// and earlier
|
||||
MessageDestination md = new MessageDestination();
|
||||
md.setName("dummy");
|
||||
webXmlDefaultFragment.addMessageDestination(md);
|
||||
|
||||
// local-encoding-mapping-list was added in 2.4 so should be excluded in
|
||||
// 2.3 and earlier
|
||||
webXmlDefaultFragment.addLocaleEncodingMapping("en", "UTF-8");
|
||||
|
||||
// jsp-config was added in Servlet 2.4
|
||||
webXmlDefaultFragment.addTaglib("dummy", "dummy");
|
||||
|
||||
// filter-mapping/dispatcher added in Servlet 2.4
|
||||
filterMap.setDispatcher("REQUEST");
|
||||
|
||||
// listener-[description|display-name|icon] added in Servlet 2.4
|
||||
// None of these are supported in WebXml
|
||||
|
||||
// filter-mapping/dispatcher/ASYNC added in Servlet 3.0
|
||||
filterMap.setDispatcher("ASYNC");
|
||||
|
||||
// error-page with just location allowed in Servlet 3.0+
|
||||
ErrorPage errorPage = new ErrorPage();
|
||||
errorPage.setLocation("/dummy");
|
||||
webXmlDefaultFragment.addErrorPage(errorPage);
|
||||
|
||||
// async-supported added to Servlet and Filter in 3.0
|
||||
filterDef.setAsyncSupported("false");
|
||||
servletDef.setAsyncSupported("false");
|
||||
|
||||
// session-cookie-config added in 3.0
|
||||
SessionConfig sessionConfig = new SessionConfig();
|
||||
sessionConfig.setCookieDomain("dummy");
|
||||
webXmlDefaultFragment.setSessionConfig(sessionConfig);
|
||||
|
||||
// http-method-omission added in Servlet 3.0
|
||||
// Let this trigger a validation error as dropping it silently could
|
||||
// be a security concern
|
||||
|
||||
// multi-part-config added in Servlet 3.0
|
||||
MultipartDef multiPart = new MultipartDef();
|
||||
servletDef.setMultipartDef(multiPart);
|
||||
|
||||
// deny-uncovered-http-methods added in Servlet 3.1
|
||||
webXmlDefaultFragment.setDenyUncoveredHttpMethods(true);
|
||||
|
||||
return webXmlDefaultFragment;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleMethodsWebXml() {
|
||||
WebXml webxml = new WebXml();
|
||||
webxml.addPostConstructMethods("a", "a");
|
||||
webxml.addPreDestroyMethods("b", "b");
|
||||
|
||||
WebXml fragment = new WebXml();
|
||||
fragment.addPostConstructMethods("c", "c");
|
||||
fragment.addPreDestroyMethods("d", "d");
|
||||
|
||||
Set<WebXml> fragments = new HashSet<>();
|
||||
fragments.add(fragment);
|
||||
|
||||
webxml.merge(fragments);
|
||||
|
||||
Map<String, String> postConstructMethods = webxml.getPostConstructMethods();
|
||||
Map<String, String> preDestroyMethods = webxml.getPreDestroyMethods();
|
||||
Assert.assertEquals(1, postConstructMethods.size());
|
||||
Assert.assertEquals(1, preDestroyMethods.size());
|
||||
|
||||
Assert.assertEquals("a", postConstructMethods.get("a"));
|
||||
Assert.assertEquals("b", preDestroyMethods.get("b"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleMethodsWebFragments() {
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
WebXml fragment1 = new WebXml();
|
||||
fragment1.addPostConstructMethods("a", "a");
|
||||
fragment1.addPreDestroyMethods("b", "b");
|
||||
|
||||
WebXml fragment2 = new WebXml();
|
||||
fragment2.addPostConstructMethods("c", "c");
|
||||
fragment2.addPreDestroyMethods("d", "d");
|
||||
|
||||
Set<WebXml> fragments = new HashSet<>();
|
||||
fragments.add(fragment1);
|
||||
fragments.add(fragment2);
|
||||
|
||||
webxml.merge(fragments);
|
||||
|
||||
Map<String, String> postConstructMethods = webxml.getPostConstructMethods();
|
||||
Map<String, String> preDestroyMethods = webxml.getPreDestroyMethods();
|
||||
Assert.assertEquals(2, postConstructMethods.size());
|
||||
Assert.assertEquals(2, preDestroyMethods.size());
|
||||
|
||||
Assert.assertEquals("a", postConstructMethods.get("a"));
|
||||
Assert.assertEquals("c", postConstructMethods.get("c"));
|
||||
Assert.assertEquals("b", preDestroyMethods.get("b"));
|
||||
Assert.assertEquals("d", preDestroyMethods.get("d"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleMethodsWebFragmentsWithConflicts() {
|
||||
WebXml webxml = new WebXml();
|
||||
|
||||
WebXml fragment1 = new WebXml();
|
||||
fragment1.addPostConstructMethods("a", "a");
|
||||
fragment1.addPreDestroyMethods("b", "a");
|
||||
|
||||
WebXml fragment2 = new WebXml();
|
||||
fragment2.addPostConstructMethods("a", "b");
|
||||
|
||||
Set<WebXml> fragments = new HashSet<>();
|
||||
fragments.add(fragment1);
|
||||
fragments.add(fragment2);
|
||||
|
||||
Assert.assertFalse(webxml.merge(fragments));
|
||||
|
||||
Assert.assertEquals(0, webxml.getPostConstructMethods().size());
|
||||
|
||||
WebXml fragment3 = new WebXml();
|
||||
fragment3.addPreDestroyMethods("b", "b");
|
||||
|
||||
fragments.remove(fragment2);
|
||||
fragments.add(fragment3);
|
||||
|
||||
Assert.assertFalse(webxml.merge(fragments));
|
||||
|
||||
Assert.assertEquals(0, webxml.getPreDestroyMethods().size());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testBug54387a() {
|
||||
// Multiple servlets may not be mapped to the same url-pattern
|
||||
WebXml webxml = new WebXml();
|
||||
webxml.addServletMapping("/foo", "a");
|
||||
webxml.addServletMapping("/foo", "b");
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testBug54387b() {
|
||||
// Multiple servlets may not be mapped to the same url-pattern
|
||||
WebXml webxml = new WebXml();
|
||||
WebXml f1 = new WebXml();
|
||||
WebXml f2 = new WebXml();
|
||||
|
||||
HashSet<WebXml> fragments = new HashSet<>();
|
||||
fragments.add(f1);
|
||||
fragments.add(f2);
|
||||
|
||||
f1.addServletMapping("/foo", "a");
|
||||
f2.addServletMapping("/foo", "b");
|
||||
|
||||
webxml.merge(fragments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug54387c() {
|
||||
// Multiple servlets may not be mapped to the same url-pattern but main
|
||||
// web.xml takes priority
|
||||
WebXml webxml = new WebXml();
|
||||
WebXml f1 = new WebXml();
|
||||
WebXml f2 = new WebXml();
|
||||
|
||||
HashSet<WebXml> fragments = new HashSet<>();
|
||||
fragments.add(f1);
|
||||
fragments.add(f2);
|
||||
|
||||
f1.addServletMapping("/foo", "a");
|
||||
f2.addServletMapping("/foo", "b");
|
||||
webxml.addServletMapping("/foo", "main");
|
||||
|
||||
webxml.merge(fragments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,696 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.descriptor.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link WebXml} fragment ordering.
|
||||
*/
|
||||
public class TestWebXmlOrdering {
|
||||
private WebXml app;
|
||||
private WebXml a;
|
||||
private WebXml b;
|
||||
private WebXml c;
|
||||
private WebXml d;
|
||||
private WebXml e;
|
||||
private WebXml f;
|
||||
private Map<String,WebXml> fragments;
|
||||
private int posA;
|
||||
private int posB;
|
||||
private int posC;
|
||||
private int posD;
|
||||
private int posE;
|
||||
private int posF;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
app = new WebXml();
|
||||
a = new WebXml();
|
||||
a.setName("a");
|
||||
b = new WebXml();
|
||||
b.setName("b");
|
||||
c = new WebXml();
|
||||
c.setName("c");
|
||||
d = new WebXml();
|
||||
d.setName("d");
|
||||
e = new WebXml();
|
||||
e.setName("e");
|
||||
f = new WebXml();
|
||||
f.setName("f");
|
||||
// Control the input order
|
||||
fragments = new LinkedHashMap<>();
|
||||
fragments.put("a",a);
|
||||
fragments.put("b",b);
|
||||
fragments.put("c",c);
|
||||
fragments.put("d",d);
|
||||
fragments.put("e",e);
|
||||
fragments.put("f",f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsAbsolute() {
|
||||
app.addAbsoluteOrdering("c");
|
||||
app.addAbsoluteOrdering("a");
|
||||
app.addAbsoluteOrdering("b");
|
||||
app.addAbsoluteOrdering("e");
|
||||
app.addAbsoluteOrdering("d");
|
||||
|
||||
Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments, null);
|
||||
|
||||
Iterator<WebXml> iter = ordered.iterator();
|
||||
Assert.assertEquals(c,iter.next());
|
||||
Assert.assertEquals(a,iter.next());
|
||||
Assert.assertEquals(b,iter.next());
|
||||
Assert.assertEquals(e,iter.next());
|
||||
Assert.assertEquals(d,iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsAbsolutePartial() {
|
||||
app.addAbsoluteOrdering("c");
|
||||
app.addAbsoluteOrdering("a");
|
||||
|
||||
Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments, null);
|
||||
|
||||
Iterator<WebXml> iter = ordered.iterator();
|
||||
Assert.assertEquals(c,iter.next());
|
||||
Assert.assertEquals(a,iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsAbsoluteOthersStart() {
|
||||
app.addAbsoluteOrdering(WebXml.ORDER_OTHERS);
|
||||
app.addAbsoluteOrdering("b");
|
||||
app.addAbsoluteOrdering("d");
|
||||
|
||||
Set<WebXml> others = new HashSet<>();
|
||||
others.add(a);
|
||||
others.add(c);
|
||||
others.add(e);
|
||||
others.add(f);
|
||||
|
||||
Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments, null);
|
||||
|
||||
Iterator<WebXml> iter = ordered.iterator();
|
||||
while (others.size() > 0) {
|
||||
WebXml o = iter.next();
|
||||
Assert.assertTrue(others.contains(o));
|
||||
others.remove(o);
|
||||
}
|
||||
Assert.assertEquals(b,iter.next());
|
||||
Assert.assertEquals(d,iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsAbsoluteOthersMiddle() {
|
||||
app.addAbsoluteOrdering("b");
|
||||
app.addAbsoluteOrdering(WebXml.ORDER_OTHERS);
|
||||
app.addAbsoluteOrdering("d");
|
||||
|
||||
Set<WebXml> others = new HashSet<>();
|
||||
others.add(a);
|
||||
others.add(c);
|
||||
others.add(e);
|
||||
others.add(f);
|
||||
|
||||
Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments, null);
|
||||
|
||||
Iterator<WebXml> iter = ordered.iterator();
|
||||
Assert.assertEquals(b,iter.next());
|
||||
|
||||
while (others.size() > 0) {
|
||||
WebXml o = iter.next();
|
||||
Assert.assertTrue(others.contains(o));
|
||||
others.remove(o);
|
||||
}
|
||||
Assert.assertEquals(d,iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebFragmentsAbsoluteWrongFragmentName() {
|
||||
app.addAbsoluteOrdering("a");
|
||||
app.addAbsoluteOrdering("z");
|
||||
Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments, null);
|
||||
Assert.assertEquals(1,ordered.size());
|
||||
Assert.assertEquals(fragments.get("a"),ordered.toArray()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsAbsoluteOthersEnd() {
|
||||
app.addAbsoluteOrdering("b");
|
||||
app.addAbsoluteOrdering("d");
|
||||
app.addAbsoluteOrdering(WebXml.ORDER_OTHERS);
|
||||
|
||||
Set<WebXml> others = new HashSet<>();
|
||||
others.add(a);
|
||||
others.add(c);
|
||||
others.add(e);
|
||||
others.add(f);
|
||||
|
||||
Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments, null);
|
||||
|
||||
Iterator<WebXml> iter = ordered.iterator();
|
||||
Assert.assertEquals(b,iter.next());
|
||||
Assert.assertEquals(d,iter.next());
|
||||
|
||||
while (others.size() > 0) {
|
||||
WebXml o = iter.next();
|
||||
Assert.assertTrue(others.contains(o));
|
||||
others.remove(o);
|
||||
}
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
private void doRelativeOrderingTest(RelativeOrderingTestRunner runner) {
|
||||
// Confirm we have all 720 possible input orders
|
||||
// Set<String> orders = new HashSet<>();
|
||||
|
||||
// Test all possible input orders since some bugs were discovered that
|
||||
// depended on input order
|
||||
for (int i = 0; i < 6; i++) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
for (int l = 0; l < 3; l++) {
|
||||
for (int m = 0; m < 2; m++) {
|
||||
setUp();
|
||||
runner.init();
|
||||
ArrayList<WebXml> source = new ArrayList<>();
|
||||
source.addAll(fragments.values());
|
||||
Map<String,WebXml> input =
|
||||
new LinkedHashMap<>();
|
||||
|
||||
WebXml one = source.remove(i);
|
||||
input.put(one.getName(), one);
|
||||
|
||||
WebXml two = source.remove(j);
|
||||
input.put(two.getName(), two);
|
||||
|
||||
WebXml three = source.remove(k);
|
||||
input.put(three.getName(), three);
|
||||
|
||||
WebXml four = source.remove(l);
|
||||
input.put(four.getName(), four);
|
||||
|
||||
WebXml five = source.remove(m);
|
||||
input.put(five.getName(), five);
|
||||
|
||||
WebXml six = source.remove(0);
|
||||
input.put(six.getName(), six);
|
||||
|
||||
/*
|
||||
String order = one.getName() + two.getName() +
|
||||
three.getName() + four.getName() +
|
||||
five.getName() + six.getName();
|
||||
orders.add(order);
|
||||
*/
|
||||
|
||||
Set<WebXml> ordered =
|
||||
WebXml.orderWebFragments(app, input, null);
|
||||
populatePositions(ordered);
|
||||
|
||||
runner.validate(getOrder(ordered));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// System.out.println(orders.size());
|
||||
}
|
||||
|
||||
private String getOrder(Set<WebXml> ordered) {
|
||||
StringBuilder sb = new StringBuilder(ordered.size());
|
||||
for (WebXml webXml : ordered) {
|
||||
sb.append(webXml.getName());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void populatePositions(Set<WebXml> ordered) {
|
||||
List<WebXml> indexed = new ArrayList<>();
|
||||
indexed.addAll(ordered);
|
||||
|
||||
posA = indexed.indexOf(a);
|
||||
posB = indexed.indexOf(b);
|
||||
posC = indexed.indexOf(c);
|
||||
posD = indexed.indexOf(d);
|
||||
posE = indexed.indexOf(e);
|
||||
posF = indexed.indexOf(f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative1() {
|
||||
// First example from servlet spec
|
||||
doRelativeOrderingTest(new RelativeTestRunner1());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative2() {
|
||||
// Second example - use fragment a for no-id fragment
|
||||
doRelativeOrderingTest(new RelativeTestRunner2());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative3() {
|
||||
// Third example from spec with e & f added
|
||||
doRelativeOrderingTest(new RelativeTestRunner3());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative4Bug54068() {
|
||||
// Simple sequence that failed for some inputs
|
||||
doRelativeOrderingTest(new RelativeTestRunner4());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative5Bug54068() {
|
||||
// Simple sequence that failed for some inputs
|
||||
doRelativeOrderingTest(new RelativeTestRunner5());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative6Bug54068() {
|
||||
// Simple sequence that failed for some inputs
|
||||
doRelativeOrderingTest(new RelativeTestRunner6());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative7() {
|
||||
// Reference loop (but not circular dependencies)
|
||||
doRelativeOrderingTest(new RelativeTestRunner7());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative8() {
|
||||
// More complex, trying to break the algorithm
|
||||
doRelativeOrderingTest(new RelativeTestRunner8());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative9() {
|
||||
// Variation on bug 54068
|
||||
doRelativeOrderingTest(new RelativeTestRunner9());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative10() {
|
||||
// Variation on bug 54068
|
||||
doRelativeOrderingTest(new RelativeTestRunner10());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderWebFragmentsRelative11() {
|
||||
// Test references to non-existent fragments
|
||||
doRelativeOrderingTest(new RelativeTestRunner11());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testOrderWebFragmentsrelativeCircular1() {
|
||||
a.addBeforeOrdering("b");
|
||||
b.addBeforeOrdering("a");
|
||||
|
||||
WebXml.orderWebFragments(app, fragments, null);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testOrderWebFragmentsrelativeCircular2() {
|
||||
a.addBeforeOrderingOthers();
|
||||
b.addAfterOrderingOthers();
|
||||
c.addBeforeOrdering("a");
|
||||
c.addAfterOrdering("b");
|
||||
|
||||
WebXml.orderWebFragments(app, fragments, null);
|
||||
}
|
||||
|
||||
private interface RelativeOrderingTestRunner {
|
||||
void init();
|
||||
void validate(String order);
|
||||
}
|
||||
|
||||
private class RelativeTestRunner1 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addAfterOrderingOthers();
|
||||
a.addAfterOrdering("c");
|
||||
b.addBeforeOrderingOthers();
|
||||
c.addAfterOrderingOthers();
|
||||
f.addBeforeOrderingOthers();
|
||||
f.addBeforeOrdering("b");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
//a.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posA > posB);
|
||||
Assert.assertTrue(order, posA > posC);
|
||||
Assert.assertTrue(order, posA > posD);
|
||||
Assert.assertTrue(order, posA > posE);
|
||||
Assert.assertTrue(order, posA > posF);
|
||||
|
||||
// a.addAfterOrdering("c");
|
||||
Assert.assertTrue(order, posA > posC);
|
||||
|
||||
// b.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posB < posC);
|
||||
|
||||
// c.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posC > posB);
|
||||
Assert.assertTrue(order, posC > posD);
|
||||
Assert.assertTrue(order, posC > posE);
|
||||
Assert.assertTrue(order, posC > posF);
|
||||
|
||||
// f.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posF < posA);
|
||||
Assert.assertTrue(order, posF < posB);
|
||||
Assert.assertTrue(order, posF < posC);
|
||||
Assert.assertTrue(order, posF < posD);
|
||||
Assert.assertTrue(order, posF < posE);
|
||||
|
||||
// f.addBeforeOrdering("b");
|
||||
Assert.assertTrue(order, posF < posB);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner2 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addAfterOrderingOthers();
|
||||
a.addBeforeOrdering("c");
|
||||
b.addBeforeOrderingOthers();
|
||||
d.addAfterOrderingOthers();
|
||||
e.addBeforeOrderingOthers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// a.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posA > posB);
|
||||
Assert.assertTrue(order, posA > posE);
|
||||
Assert.assertTrue(order, posA > posF);
|
||||
|
||||
// a.addBeforeOrdering("c");
|
||||
Assert.assertTrue(order, posC > posA);
|
||||
Assert.assertTrue(order, posC > posB);
|
||||
Assert.assertTrue(order, posC > posE);
|
||||
Assert.assertTrue(order, posC > posF);
|
||||
|
||||
// b.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posB < posA);
|
||||
Assert.assertTrue(order, posB < posC);
|
||||
Assert.assertTrue(order, posB < posD);
|
||||
Assert.assertTrue(order, posB < posF);
|
||||
|
||||
// d.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posD > posB);
|
||||
Assert.assertTrue(order, posD > posE);
|
||||
Assert.assertTrue(order, posD > posF);
|
||||
|
||||
// e.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posE < posA);
|
||||
Assert.assertTrue(order, posE < posC);
|
||||
Assert.assertTrue(order, posE < posD);
|
||||
Assert.assertTrue(order, posE < posF);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner3 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addAfterOrdering("b");
|
||||
c.addBeforeOrderingOthers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// a.addAfterOrdering("b");
|
||||
Assert.assertTrue(order, posA > posB);
|
||||
|
||||
// c.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posC < posA);
|
||||
Assert.assertTrue(order, posC < posB);
|
||||
Assert.assertTrue(order, posC < posD);
|
||||
Assert.assertTrue(order, posC < posE);
|
||||
Assert.assertTrue(order, posC < posF);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner4 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
b.addAfterOrdering("a");
|
||||
c.addAfterOrdering("b");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// b.addAfterOrdering("a");
|
||||
Assert.assertTrue(order, posB > posA);
|
||||
|
||||
// c.addAfterOrdering("b");
|
||||
Assert.assertTrue(order, posC > posB);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner5 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
b.addBeforeOrdering("a");
|
||||
c.addBeforeOrdering("b");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// b.addBeforeOrdering("a");
|
||||
Assert.assertTrue(order, posB < posA);
|
||||
|
||||
// c.addBeforeOrdering("b");
|
||||
Assert.assertTrue(order, posC < posB);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner6 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
b.addBeforeOrdering("a");
|
||||
b.addAfterOrdering("c");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// b.addBeforeOrdering("a");
|
||||
Assert.assertTrue(order, posB < posA);
|
||||
|
||||
//b.addAfterOrdering("c");
|
||||
Assert.assertTrue(order, posB > posC);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner7 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
b.addBeforeOrdering("a");
|
||||
c.addBeforeOrdering("b");
|
||||
a.addAfterOrdering("c");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// b.addBeforeOrdering("a");
|
||||
Assert.assertTrue(order, posB < posA);
|
||||
|
||||
// c.addBeforeOrdering("b");
|
||||
Assert.assertTrue(order, posC < posB);
|
||||
|
||||
// a.addAfterOrdering("c");
|
||||
Assert.assertTrue(order, posA > posC);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner8 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addBeforeOrderingOthers();
|
||||
a.addBeforeOrdering("b");
|
||||
b.addBeforeOrderingOthers();
|
||||
c.addAfterOrdering("b");
|
||||
d.addAfterOrdering("c");
|
||||
e.addAfterOrderingOthers();
|
||||
f.addAfterOrderingOthers();
|
||||
f.addAfterOrdering("e");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// a.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posA < posB);
|
||||
Assert.assertTrue(order, posA < posC);
|
||||
Assert.assertTrue(order, posA < posD);
|
||||
Assert.assertTrue(order, posA < posE);
|
||||
Assert.assertTrue(order, posA < posF);
|
||||
|
||||
// a.addBeforeOrdering("b");
|
||||
Assert.assertTrue(order, posA < posB);
|
||||
|
||||
// b.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posB < posC);
|
||||
Assert.assertTrue(order, posB < posD);
|
||||
Assert.assertTrue(order, posB < posE);
|
||||
Assert.assertTrue(order, posB < posF);
|
||||
|
||||
// c.addAfterOrdering("b");
|
||||
Assert.assertTrue(order, posC > posB);
|
||||
|
||||
// d.addAfterOrdering("c");
|
||||
Assert.assertTrue(order, posD > posC);
|
||||
|
||||
// e.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posE > posA);
|
||||
Assert.assertTrue(order, posE > posB);
|
||||
Assert.assertTrue(order, posE > posC);
|
||||
Assert.assertTrue(order, posE > posD);
|
||||
|
||||
// f.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posF > posA);
|
||||
Assert.assertTrue(order, posF > posB);
|
||||
Assert.assertTrue(order, posF > posC);
|
||||
Assert.assertTrue(order, posF > posD);
|
||||
Assert.assertTrue(order, posF > posE);
|
||||
|
||||
// f.addAfterOrdering("e");
|
||||
Assert.assertTrue(order, posF > posE);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner9 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addBeforeOrderingOthers();
|
||||
b.addBeforeOrdering("a");
|
||||
c.addBeforeOrdering("b");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// a.addBeforeOrderingOthers();
|
||||
Assert.assertTrue(order, posA < posD);
|
||||
Assert.assertTrue(order, posA < posE);
|
||||
Assert.assertTrue(order, posA < posF);
|
||||
|
||||
// b.addBeforeOrdering("a");
|
||||
Assert.assertTrue(order, posB < posA);
|
||||
|
||||
// c.addBeforeOrdering("b");
|
||||
Assert.assertTrue(order, posC < posB);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner10 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addAfterOrderingOthers();
|
||||
b.addAfterOrdering("a");
|
||||
c.addAfterOrdering("b");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// a.addAfterOrderingOthers();
|
||||
Assert.assertTrue(order, posA > posD);
|
||||
Assert.assertTrue(order, posA > posE);
|
||||
Assert.assertTrue(order, posA > posF);
|
||||
|
||||
// b.addAfterOrdering("a");
|
||||
Assert.assertTrue(order, posB > posA);
|
||||
|
||||
// c.addAfterOrdering("b");
|
||||
Assert.assertTrue(order, posC > posB);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelativeTestRunner11 implements RelativeOrderingTestRunner {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
a.addAfterOrdering("b");
|
||||
b.addAfterOrdering("z");
|
||||
b.addBeforeOrdering("y");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String order) {
|
||||
// There is some duplication in the tests below - it is easier to
|
||||
// check the tests are complete this way.
|
||||
|
||||
// a.addAfterOrdering("b");
|
||||
Assert.assertTrue(order, posA > posB);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
test/org/apache/tomcat/util/file/TestConfigFileLoader.java
Normal file
63
test/org/apache/tomcat/util/file/TestConfigFileLoader.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.file;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
|
||||
|
||||
public class TestConfigFileLoader {
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
TomcatURLStreamHandlerFactory.getInstance();
|
||||
System.setProperty("catalina.base", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01() throws IOException {
|
||||
doTest("classpath:org/apache/catalina/mbeans-descriptors.xml");
|
||||
}
|
||||
|
||||
@Test(expected=FileNotFoundException.class)
|
||||
public void test02() throws IOException {
|
||||
doTest("classpath:org/apache/catalina/foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test03() throws IOException {
|
||||
doTest("test/webresources/dir1");
|
||||
}
|
||||
|
||||
@Test(expected=FileNotFoundException.class)
|
||||
public void test04() throws IOException {
|
||||
doTest("test/webresources/unknown");
|
||||
}
|
||||
|
||||
private void doTest(String path) throws IOException {
|
||||
try (InputStream is = ConfigFileLoader.getInputStream(path)) {
|
||||
Assert.assertNotNull(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
96
test/org/apache/tomcat/util/http/CookiesBaseTest.java
Normal file
96
test/org/apache/tomcat/util/http/CookiesBaseTest.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
|
||||
/**
|
||||
* Base Test case for {@link LegacyCookieProcessor}. <b>Note</b> because of the
|
||||
* use of <code>static final</code> constants in {@link LegacyCookieProcessor},
|
||||
* each of these tests must be executed in a new JVM instance. The tests have
|
||||
* been place in separate classes to facilitate this when running the unit tests
|
||||
* via Ant.
|
||||
*/
|
||||
public abstract class CookiesBaseTest extends TomcatBaseTest {
|
||||
|
||||
/**
|
||||
* Servlet for cookie naming test.
|
||||
*/
|
||||
public static class CookieServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String cookieName;
|
||||
private final String cookieValue;
|
||||
|
||||
public CookieServlet(String cookieName, String cookieValue) {
|
||||
this.cookieName = cookieName;
|
||||
this.cookieValue = cookieValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse res)
|
||||
throws IOException {
|
||||
try {
|
||||
Cookie cookie = new Cookie(cookieName, cookieValue);
|
||||
res.addCookie(cookie);
|
||||
res.getWriter().write("Cookie name ok");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
res.getWriter().write("Cookie name fail");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void addServlets(Tomcat tomcat) {
|
||||
// No file system docBase required
|
||||
Context ctx = tomcat.addContext("", null);
|
||||
ctx.setCookieProcessor(new LegacyCookieProcessor());
|
||||
|
||||
Tomcat.addServlet(ctx, "invalid", new CookieServlet("na;me", "value"));
|
||||
ctx.addServletMappingDecoded("/invalid", "invalid");
|
||||
Tomcat.addServlet(ctx, "null", new CookieServlet(null, "value"));
|
||||
ctx.addServletMappingDecoded("/null", "null");
|
||||
Tomcat.addServlet(ctx, "blank", new CookieServlet("", "value"));
|
||||
ctx.addServletMappingDecoded("/blank", "blank");
|
||||
Tomcat.addServlet(ctx, "invalidFwd",
|
||||
new CookieServlet("na/me", "value"));
|
||||
ctx.addServletMappingDecoded("/invalidFwd", "invalidFwd");
|
||||
Tomcat.addServlet(ctx, "invalidStrict",
|
||||
new CookieServlet("$name", "value"));
|
||||
ctx.addServletMappingDecoded("/invalidStrict", "invalidStrict");
|
||||
Tomcat.addServlet(ctx, "valid", new CookieServlet("name", "value"));
|
||||
ctx.addServletMappingDecoded("/valid", "valid");
|
||||
Tomcat.addServlet(ctx, "switch", new CookieServlet("name", "val?ue"));
|
||||
ctx.addServletMappingDecoded("/switch", "switch");
|
||||
|
||||
}
|
||||
|
||||
public abstract void testCookiesInstance() throws Exception;
|
||||
|
||||
}
|
||||
84
test/org/apache/tomcat/util/http/TestBug49158.java
Normal file
84
test/org/apache/tomcat/util/http/TestBug49158.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* Test case for {@link LegacyCookieProcessor}. <b>Note</b> because of the use of <code>final
|
||||
* static</code> constants in {@link LegacyCookieProcessor}, each of these tests must be
|
||||
* executed in a new JVM instance. The tests have been place in separate classes
|
||||
* to facilitate this when running the unit tests via Ant.
|
||||
*/
|
||||
public class TestBug49158 extends CookiesBaseTest {
|
||||
public static final String path = "49158";
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testCookiesInstance() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
addServlets(tomcat);
|
||||
tomcat.start();
|
||||
Map<String,List<String>> headers = new HashMap<>();
|
||||
ByteChunk res = new ByteChunk();
|
||||
getUrl("http://localhost:" + getPort() + "/"+path, res, headers);
|
||||
List<String> cookieHeaders = headers.get("Set-Cookie");
|
||||
Assert.assertEquals("There should only be one Set-Cookie header in this test",
|
||||
1, cookieHeaders.size());
|
||||
}
|
||||
|
||||
public static void addServlets(Tomcat tomcat) {
|
||||
// No file system docBase required
|
||||
Context ctx = tomcat.addContext("", null);
|
||||
|
||||
Tomcat.addServlet(ctx, path, new TestBug49158Servlet());
|
||||
ctx.addServletMappingDecoded("/"+path, path);
|
||||
}
|
||||
|
||||
public static class TestBug49158Servlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 2725990508758127399L;
|
||||
|
||||
@Override
|
||||
public void service(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
HttpSession session = req.getSession();
|
||||
session.invalidate();
|
||||
session = req.getSession();
|
||||
session.invalidate();
|
||||
req.getSession();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
344
test/org/apache/tomcat/util/http/TestCookieParsing.java
Normal file
344
test/org/apache/tomcat/util/http/TestCookieParsing.java
Normal file
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.startup.SimpleHttpClient;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
|
||||
|
||||
public class TestCookieParsing extends TomcatBaseTest {
|
||||
|
||||
private static final String[] COOKIES_WITH_EQUALS = new String[] {
|
||||
"name=equals=middle", "name==equalsstart", "name=equalsend=" };
|
||||
private static final String COOKIES_WITH_EQUALS_TRUNC = "name=equalsname=name=equalsend";
|
||||
|
||||
private static final String[] COOKIES_WITH_NAME_ONLY = new String[] {
|
||||
"bob", "bob=" };
|
||||
private static final String COOKIES_WITH_NAME_ONLY_CONCAT = "bob=bob=";
|
||||
|
||||
private static final String[] COOKIES_WITH_SEPS = new String[] {
|
||||
"name=val/ue" };
|
||||
private static final String COOKIES_WITH_SEPS_TRUNC = "name=val";
|
||||
|
||||
private static final String[] COOKIES_WITH_QUOTES = new String[] {
|
||||
"name=\"val\\\"ue\"", "name=\"value\"" };
|
||||
|
||||
private static final String[] COOKIES_V0 = new String[] {
|
||||
"$Version=0;name=\"val ue\"", "$Version=0;name=\"val\tue\""};
|
||||
|
||||
private static final String COOKIES_V0_CONCAT = "name=\"val ue\"name=\"val\tue\"";
|
||||
|
||||
private static final String[] COOKIES_V1 = new String[] {
|
||||
"$Version=1;name=\"val ue\"", "$Version=1;name=\"val\tue\""};
|
||||
|
||||
private static final String COOKIES_V1_CONCAT = "name=\"val ue\"name=\"val\tue\"";
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithEquals() throws Exception {
|
||||
doTestLegacyEquals(true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithoutEquals() throws Exception {
|
||||
doTestLegacyEquals(false);
|
||||
}
|
||||
|
||||
|
||||
private void doTestLegacyEquals(boolean allowEquals) throws Exception {
|
||||
LegacyCookieProcessor legacyCookieProcessor = new LegacyCookieProcessor();
|
||||
legacyCookieProcessor.setAllowEqualsInValue(allowEquals);
|
||||
// Need to allow name only cookies to handle equals at the start of
|
||||
// the value
|
||||
legacyCookieProcessor.setAllowNameOnly(true);
|
||||
|
||||
String expected;
|
||||
if (allowEquals) {
|
||||
expected = concat(COOKIES_WITH_EQUALS);
|
||||
} else {
|
||||
expected = COOKIES_WITH_EQUALS_TRUNC;
|
||||
}
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
legacyCookieProcessor, COOKIES_WITH_EQUALS, expected);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRfc6265Equals() throws Exception {
|
||||
// Always allows equals
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
new Rfc6265CookieProcessor(), COOKIES_WITH_EQUALS, concat(COOKIES_WITH_EQUALS));
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithNameOnly() throws Exception {
|
||||
doTestLegacyNameOnly(true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithoutNameOnly() throws Exception {
|
||||
doTestLegacyNameOnly(false);
|
||||
}
|
||||
|
||||
|
||||
private void doTestLegacyNameOnly(boolean nameOnly) throws Exception {
|
||||
LegacyCookieProcessor legacyCookieProcessor = new LegacyCookieProcessor();
|
||||
legacyCookieProcessor.setAllowNameOnly(nameOnly);
|
||||
|
||||
String expected;
|
||||
if (nameOnly) {
|
||||
expected = COOKIES_WITH_NAME_ONLY_CONCAT;
|
||||
} else {
|
||||
expected = "";
|
||||
}
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
legacyCookieProcessor, COOKIES_WITH_NAME_ONLY, expected);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRfc6265NameOnly() throws Exception {
|
||||
// Always allows equals
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
new Rfc6265CookieProcessor(), COOKIES_WITH_NAME_ONLY,
|
||||
COOKIES_WITH_NAME_ONLY_CONCAT);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRfc6265V0() throws Exception {
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
new Rfc6265CookieProcessor(), COOKIES_V0, COOKIES_V0_CONCAT);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRfc6265V1() throws Exception {
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
new Rfc6265CookieProcessor(), COOKIES_V1, COOKIES_V1_CONCAT);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithSeps() throws Exception {
|
||||
doTestLegacySeps(true, true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithoutSeps() throws Exception {
|
||||
doTestLegacySeps(false, true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithFwdSlash() throws Exception {
|
||||
doTestLegacySeps(true, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyWithoutFwdSlash() throws Exception {
|
||||
doTestLegacySeps(false, false);
|
||||
}
|
||||
|
||||
|
||||
private void doTestLegacySeps(boolean seps, boolean fwdSlash) throws Exception {
|
||||
LegacyCookieProcessor legacyCookieProcessor = new LegacyCookieProcessor();
|
||||
legacyCookieProcessor.setAllowHttpSepsInV0(seps);
|
||||
legacyCookieProcessor.setForwardSlashIsSeparator(fwdSlash);
|
||||
|
||||
String expected;
|
||||
if (!seps && fwdSlash) {
|
||||
expected = COOKIES_WITH_SEPS_TRUNC;
|
||||
} else {
|
||||
expected = concat(COOKIES_WITH_SEPS);
|
||||
}
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
legacyCookieProcessor, COOKIES_WITH_SEPS, expected);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRfc6265Seps() throws Exception {
|
||||
// Always allows equals
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
new Rfc6265CookieProcessor(), COOKIES_WITH_SEPS, concat(COOKIES_WITH_SEPS));
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLegacyPreserveHeader() throws Exception {
|
||||
LegacyCookieProcessor legacyCookieProcessor = new LegacyCookieProcessor();
|
||||
|
||||
String expected;
|
||||
expected = concat(COOKIES_WITH_QUOTES);
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(
|
||||
legacyCookieProcessor, true, COOKIES_WITH_QUOTES, expected);
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRfc6265PreserveHeader() throws Exception {
|
||||
// Always allows equals
|
||||
TestCookieParsingClient client = new TestCookieParsingClient(new Rfc6265CookieProcessor(),
|
||||
true, COOKIES_WITH_QUOTES, concat(COOKIES_WITH_QUOTES));
|
||||
client.doRequest();
|
||||
}
|
||||
|
||||
|
||||
private static String concat(String[] input) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (String s : input) {
|
||||
result.append(s);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
private class TestCookieParsingClient extends SimpleHttpClient {
|
||||
|
||||
private final CookieProcessor cookieProcessor;
|
||||
private final String[] cookies;
|
||||
private final String expected;
|
||||
private final boolean echoHeader;
|
||||
|
||||
|
||||
public TestCookieParsingClient(CookieProcessor cookieProcessor,
|
||||
String[] cookies, String expected) {
|
||||
this(cookieProcessor, false, cookies, expected);
|
||||
}
|
||||
|
||||
public TestCookieParsingClient(CookieProcessor cookieProcessor,
|
||||
boolean echoHeader, String[] cookies, String expected) {
|
||||
this.cookieProcessor = cookieProcessor;
|
||||
this.echoHeader = echoHeader;
|
||||
this.cookies = cookies;
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
|
||||
private void doRequest() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
Context root = tomcat.addContext("", TEMP_DIR);
|
||||
root.setCookieProcessor(cookieProcessor);
|
||||
|
||||
if (echoHeader) {
|
||||
Tomcat.addServlet(root, "Cookies", new EchoCookieHeader());
|
||||
} else {
|
||||
Tomcat.addServlet(root, "Cookies", new EchoCookies());
|
||||
}
|
||||
root.addServletMappingDecoded("/test", "Cookies");
|
||||
|
||||
tomcat.start();
|
||||
// Open connection
|
||||
setPort(tomcat.getConnector().getLocalPort());
|
||||
connect();
|
||||
|
||||
StringBuilder request = new StringBuilder();
|
||||
request.append("GET /test HTTP/1.0");
|
||||
request.append(CRLF);
|
||||
for (String cookie : cookies) {
|
||||
request.append("Cookie: ");
|
||||
request.append(cookie);
|
||||
request.append(CRLF);
|
||||
}
|
||||
request.append(CRLF);
|
||||
setRequest(new String[] {request.toString()});
|
||||
processRequest(true); // blocks until response has been read
|
||||
String response = getResponseBody();
|
||||
|
||||
// Close the connection
|
||||
disconnect();
|
||||
reset();
|
||||
tomcat.stop();
|
||||
|
||||
Assert.assertEquals(expected, response);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isResponseBodyOK() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class EchoCookies extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
Cookie cookies[] = req.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
resp.getWriter().write(cookie.getName() + "=" +
|
||||
cookie.getValue());
|
||||
}
|
||||
}
|
||||
resp.flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class EchoCookieHeader extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
req.getCookies();
|
||||
// Never do this in production code. It triggers an XSS.
|
||||
Enumeration<String> cookieHeaders = req.getHeaders("Cookie");
|
||||
while (cookieHeaders.hasMoreElements()) {
|
||||
String cookieHeader = cookieHeaders.nextElement();
|
||||
resp.getWriter().write(cookieHeader);
|
||||
}
|
||||
resp.flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestCookieProcessorGeneration {
|
||||
|
||||
@Test
|
||||
public void v0SimpleCookie() {
|
||||
doTest(new Cookie("foo", "bar"), "foo=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0NullValue() {
|
||||
doTest(new Cookie("foo", null), "foo=\"\"", "foo=");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0QuotedValue() {
|
||||
doTest(new Cookie("foo", "\"bar\""), "foo=\"bar\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsSemicolon() {
|
||||
doTest(new Cookie("foo", "a;b"), "foo=\"a;b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsComma() {
|
||||
doTest(new Cookie("foo", "a,b"), "foo=\"a,b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsSpace() {
|
||||
doTest(new Cookie("foo", "a b"), "foo=\"a b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsEquals() {
|
||||
Cookie cookie = new Cookie("foo", "a=b");
|
||||
doTestDefaults(cookie, "foo=\"a=b\"; Version=1", "foo=a=b");
|
||||
doTestAllowSeparators(cookie, "foo=a=b", "foo=a=b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsQuote() {
|
||||
Cookie cookie = new Cookie("foo", "a\"b");
|
||||
doTestDefaults(cookie,"foo=\"a\\\"b\"; Version=1", null);
|
||||
doTestAllowSeparators(cookie,"foo=a\"b", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsNonV0Separator() {
|
||||
Cookie cookie = new Cookie("foo", "a()<>@:\\\"/[]?={}b");
|
||||
doTestDefaults(cookie,"foo=\"a()<>@:\\\\\\\"/[]?={}b\"; Version=1", null);
|
||||
doTestAllowSeparators(cookie,"foo=a()<>@:\\\"/[]?={}b", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsBackslash() {
|
||||
Cookie cookie = new Cookie("foo", "a\\b");
|
||||
doTestDefaults(cookie, "foo=\"a\\\\b\"; Version=1", null);
|
||||
doTestAllowSeparators(cookie, "foo=a\\b", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsBackslashAtEnd() {
|
||||
Cookie cookie = new Cookie("foo", "a\\");
|
||||
doTestDefaults(cookie, "foo=\"a\\\\\"; Version=1", null);
|
||||
doTestAllowSeparators(cookie, "foo=a\\", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v0ValueContainsBackslashAndQuote() {
|
||||
Cookie cookie = new Cookie("foo", "a\"b\\c");
|
||||
doTestDefaults(cookie, "foo=\"a\\\"b\\\\c\"; Version=1", null);
|
||||
doTestAllowSeparators(cookie, "foo=a\"b\\c", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1simpleCookie() {
|
||||
Cookie cookie = new Cookie("foo", "bar");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=bar; Version=1", "foo=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1NullValue() {
|
||||
Cookie cookie = new Cookie("foo", null);
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"\"; Version=1", "foo=");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuotedValue() {
|
||||
Cookie cookie = new Cookie("foo", "\"bar\"");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"bar\"; Version=1", "foo=\"bar\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsSemicolon() {
|
||||
Cookie cookie = new Cookie("foo", "a;b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a;b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsComma() {
|
||||
Cookie cookie = new Cookie("foo", "a,b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a,b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsSpace() {
|
||||
Cookie cookie = new Cookie("foo", "a b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsEquals() {
|
||||
Cookie cookie = new Cookie("foo", "a=b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a=b\"; Version=1", "foo=a=b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsQuote() {
|
||||
Cookie cookie = new Cookie("foo", "a\"b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a\\\"b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsNonV0Separator() {
|
||||
Cookie cookie = new Cookie("foo", "a()<>@,;:\\\"/[]?={}b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a()<>@,;:\\\\\\\"/[]?={}b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsBackslash() {
|
||||
Cookie cookie = new Cookie("foo", "a\\b");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a\\\\b\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueContainsBackslashAndQuote() {
|
||||
Cookie cookie = new Cookie("foo", "a\"b\\c");
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, "foo=\"a\\\"b\\\\c\"; Version=1", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1ValueUTF8() {
|
||||
String value = "\u2300";
|
||||
Cookie cookie = new Cookie("foo", value);
|
||||
cookie.setVersion(1);
|
||||
doTest(cookie, (String) null, "foo=" + value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestMaxAgePositive() {
|
||||
doV1TestMaxAge(100, "foo=bar; Version=1; Max-Age=100", "foo=bar; Max-Age=100");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestMaxAgeZero() {
|
||||
doV1TestMaxAge(0, "foo=bar; Version=1; Max-Age=0",
|
||||
"foo=bar; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestMaxAgeNegative() {
|
||||
doV1TestMaxAge(-100, "foo=bar; Version=1", "foo=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainValid01() {
|
||||
doV1TestDomain("example.com", "foo=bar; Version=1; Domain=example.com",
|
||||
"foo=bar; Domain=example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainValid02() {
|
||||
doV1TestDomain("exa-mple.com", "foo=bar; Version=1; Domain=exa-mple.com",
|
||||
"foo=bar; Domain=exa-mple.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid01() {
|
||||
doV1TestDomain("example.com.", "foo=bar; Version=1; Domain=example.com.", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid02() {
|
||||
doV1TestDomain("example.com-", "foo=bar; Version=1; Domain=example.com-", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid03() {
|
||||
doV1TestDomain(".example.com.", "foo=bar; Version=1; Domain=.example.com.", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid04() {
|
||||
doV1TestDomain("-example.com.", "foo=bar; Version=1; Domain=-example.com.", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid05() {
|
||||
doV1TestDomain("example..com.", "foo=bar; Version=1; Domain=example..com.", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid06() {
|
||||
doV1TestDomain("example-.com.", "foo=bar; Version=1; Domain=example-.com.", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestDomainInvalid07() {
|
||||
doV1TestDomain("exam$ple.com.", "foo=bar; Version=1; Domain=exam$ple.com.", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestPathValid() {
|
||||
doV1TestPath("/example", "foo=bar; Version=1; Path=/example",
|
||||
"foo=bar; Path=/example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TestPathInvalid01() {
|
||||
doV1TestPath("exa\tmple", "foo=bar; Version=1; Path=\"exa\tmple\"", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameSiteCookies() {
|
||||
LegacyCookieProcessor legacy = new LegacyCookieProcessor();
|
||||
Rfc6265CookieProcessor rfc6265 = new Rfc6265CookieProcessor();
|
||||
|
||||
Cookie cookie = new Cookie("foo", "bar");
|
||||
|
||||
Assert.assertEquals("foo=bar", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("unset");
|
||||
rfc6265.setSameSiteCookies("unset");
|
||||
|
||||
Assert.assertEquals("foo=bar", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("none");
|
||||
rfc6265.setSameSiteCookies("none");
|
||||
|
||||
Assert.assertEquals("foo=bar; SameSite=None", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; SameSite=None", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("lax");
|
||||
rfc6265.setSameSiteCookies("lax");
|
||||
|
||||
Assert.assertEquals("foo=bar; SameSite=Lax", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; SameSite=Lax", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("strict");
|
||||
rfc6265.setSameSiteCookies("strict");
|
||||
|
||||
Assert.assertEquals("foo=bar; SameSite=Strict", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; SameSite=Strict", rfc6265.generateHeader(cookie));
|
||||
|
||||
cookie.setSecure(true);
|
||||
cookie.setHttpOnly(true);
|
||||
|
||||
legacy.setSameSiteCookies("unset");
|
||||
rfc6265.setSameSiteCookies("unset");
|
||||
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("none");
|
||||
rfc6265.setSameSiteCookies("none");
|
||||
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=None", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=None", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("lax");
|
||||
rfc6265.setSameSiteCookies("lax");
|
||||
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=Lax", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=Lax", rfc6265.generateHeader(cookie));
|
||||
|
||||
legacy.setSameSiteCookies("strict");
|
||||
rfc6265.setSameSiteCookies("strict");
|
||||
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=Strict", legacy.generateHeader(cookie));
|
||||
Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=Strict", rfc6265.generateHeader(cookie));
|
||||
}
|
||||
|
||||
private void doTest(Cookie cookie, String expected) {
|
||||
doTest(cookie, expected, expected);
|
||||
}
|
||||
|
||||
|
||||
private void doTest(Cookie cookie,
|
||||
String expectedLegacy, String expectedRfc6265) {
|
||||
doTestDefaults(cookie, expectedLegacy, expectedRfc6265);
|
||||
doTestAllowSeparators(cookie, expectedLegacy, expectedRfc6265);
|
||||
}
|
||||
|
||||
|
||||
private void doTestDefaults(Cookie cookie,
|
||||
String expectedLegacy, String expectedRfc6265) {
|
||||
CookieProcessor legacy = new LegacyCookieProcessor();
|
||||
CookieProcessor rfc6265 = new Rfc6265CookieProcessor();
|
||||
doTest(cookie, legacy, expectedLegacy, rfc6265, expectedRfc6265);
|
||||
}
|
||||
|
||||
|
||||
private void doTestAllowSeparators(Cookie cookie,
|
||||
String expectedLegacy, String expectedRfc6265) {
|
||||
LegacyCookieProcessor legacy = new LegacyCookieProcessor();
|
||||
legacy.setAllowHttpSepsInV0(true);
|
||||
legacy.setForwardSlashIsSeparator(true);
|
||||
CookieProcessor rfc6265 = new Rfc6265CookieProcessor();
|
||||
doTest(cookie, legacy, expectedLegacy, rfc6265, expectedRfc6265);
|
||||
}
|
||||
|
||||
|
||||
private void doTest(Cookie cookie,
|
||||
CookieProcessor legacy, String expectedLegacy,
|
||||
CookieProcessor rfc6265, String expectedRfc6265) {
|
||||
doTest(cookie, legacy, expectedLegacy);
|
||||
doTest(cookie, rfc6265, expectedRfc6265);
|
||||
}
|
||||
|
||||
|
||||
private void doTest(Cookie cookie, CookieProcessor cookieProcessor, String expected) {
|
||||
if (expected == null) {
|
||||
IllegalArgumentException e = null;
|
||||
try {
|
||||
cookieProcessor.generateHeader(cookie);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
e = iae;
|
||||
}
|
||||
Assert.assertNotNull("Failed to throw IAE", e);
|
||||
} else {
|
||||
if (cookieProcessor instanceof Rfc6265CookieProcessor &&
|
||||
cookie.getMaxAge() > 0) {
|
||||
// Expires attribute will depend on time cookie is generated so
|
||||
// use a modified test
|
||||
Assert.assertTrue(cookieProcessor.generateHeader(cookie).startsWith(expected));
|
||||
} else {
|
||||
Assert.assertEquals(expected, cookieProcessor.generateHeader(cookie));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doV1TestMaxAge(int age, String expectedLegacy, String expectedRfc6265) {
|
||||
LegacyCookieProcessor legacy = new LegacyCookieProcessor();
|
||||
legacy.setAlwaysAddExpires(false);
|
||||
Cookie cookie = new Cookie("foo", "bar");
|
||||
cookie.setVersion(1);
|
||||
cookie.setMaxAge(age);
|
||||
doTest(cookie, legacy, expectedLegacy, new Rfc6265CookieProcessor(), expectedRfc6265);
|
||||
}
|
||||
|
||||
|
||||
private void doV1TestDomain(String domain, String expectedLegacy, String expectedRfc6265) {
|
||||
LegacyCookieProcessor legacy = new LegacyCookieProcessor();
|
||||
legacy.setAlwaysAddExpires(false);
|
||||
Cookie cookie = new Cookie("foo", "bar");
|
||||
cookie.setVersion(1);
|
||||
cookie.setDomain(domain);
|
||||
doTest(cookie, legacy, expectedLegacy, new Rfc6265CookieProcessor(), expectedRfc6265);
|
||||
}
|
||||
|
||||
|
||||
private void doV1TestPath(String path, String expectedLegacy, String expectedRfc6265) {
|
||||
LegacyCookieProcessor legacy = new LegacyCookieProcessor();
|
||||
legacy.setAlwaysAddExpires(false);
|
||||
Cookie cookie = new Cookie("foo", "bar");
|
||||
cookie.setVersion(1);
|
||||
cookie.setPath(path);
|
||||
doTest(cookie, legacy, expectedLegacy, new Rfc6265CookieProcessor(), expectedRfc6265);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
public class TestCookieProcessorGenerationHttp extends TomcatBaseTest {
|
||||
|
||||
@Test
|
||||
public void testUtf8CookieValue() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
// No file system docBase required
|
||||
Context ctx = tomcat.addContext("", null);
|
||||
ctx.setCookieProcessor(new Rfc6265CookieProcessor());
|
||||
Tomcat.addServlet(ctx, "test", new CookieServlet("\u0120"));
|
||||
ctx.addServletMappingDecoded("/test", "test");
|
||||
tomcat.start();
|
||||
|
||||
Map<String,List<String>> headers = new HashMap<>();
|
||||
ByteChunk res = new ByteChunk();
|
||||
getUrl("http://localhost:" + getPort() + "/test", res, headers);
|
||||
List<String> cookieHeaders = headers.get("Set-Cookie");
|
||||
Assert.assertEquals("There should only be one Set-Cookie header in this test",
|
||||
1, cookieHeaders.size());
|
||||
// Client is assuming header is ISO-8859-1 encoding which it isn't. Turn
|
||||
// the header value back into the received bytes (this isn't guaranteed
|
||||
// to work with all values but it will for this test value)
|
||||
byte[] headerBytes = cookieHeaders.get(0).getBytes(StandardCharsets.ISO_8859_1);
|
||||
// Now convert those bytes to a String using UTF-8
|
||||
String utf8Header = new String(headerBytes, StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("Test=\u0120", utf8Header);
|
||||
}
|
||||
|
||||
|
||||
private static class CookieServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String cookieValue;
|
||||
|
||||
public CookieServlet(String cookieValue) {
|
||||
this.cookieValue = cookieValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
Cookie cookie = new Cookie("Test", cookieValue);
|
||||
resp.addCookie(cookie);
|
||||
resp.setContentType("text/plain");
|
||||
resp.getWriter().print("OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
530
test/org/apache/tomcat/util/http/TestCookies.java
Normal file
530
test/org/apache/tomcat/util/http/TestCookies.java
Normal file
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
|
||||
public class TestCookies {
|
||||
private final Cookie FOO = new Cookie("foo", "bar");
|
||||
private final Cookie FOO_EMPTY = new Cookie("foo", "");
|
||||
private final Cookie FOO_CONTROL = new Cookie("foo", "b\u00e1r");
|
||||
private final Cookie BAR = new Cookie("bar", "rab");
|
||||
private final Cookie BAR_EMPTY = new Cookie("bar", "");
|
||||
private final Cookie A = new Cookie("a", "b");
|
||||
private final Cookie HASH_EMPTY = new Cookie("#", "");
|
||||
private final Cookie $PORT = new Cookie("$Port", "8080");
|
||||
|
||||
@Test
|
||||
public void testBasicCookieOld() {
|
||||
doTestBasicCookie(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicCookieRfc6265() {
|
||||
doTestBasicCookie(true);
|
||||
}
|
||||
|
||||
private void doTestBasicCookie(boolean useRfc6265) {
|
||||
test(useRfc6265, "foo=bar; a=b", FOO, A);
|
||||
test(useRfc6265, "foo=bar;a=b", FOO, A);
|
||||
test(useRfc6265, "foo=bar;a=b;", FOO, A);
|
||||
test(useRfc6265, "foo=bar;a=b; ", FOO, A);
|
||||
test(useRfc6265, "foo=bar;a=b; ;", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameOnlyAreDroppedOld() {
|
||||
test(false, "foo=;a=b; ;", A);
|
||||
test(false, "foo;a=b; ;", A);
|
||||
test(false, "foo;a=b;bar", A);
|
||||
test(false, "foo;a=b;bar;", A);
|
||||
test(false, "foo;a=b;bar ", A);
|
||||
test(false, "foo;a=b;bar ;", A);
|
||||
|
||||
// Bug 49000
|
||||
Cookie fred = new Cookie("fred", "1");
|
||||
Cookie jim = new Cookie("jim", "2");
|
||||
Cookie george = new Cookie("george", "3");
|
||||
test(false, "fred=1; jim=2; bob", fred, jim);
|
||||
test(false, "fred=1; jim=2; bob; george=3", fred, jim, george);
|
||||
test(false, "fred=1; jim=2; bob=; george=3", fred, jim, george);
|
||||
test(false, "fred=1; jim=2; bob=", fred, jim);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameOnlyAreDroppedRfc6265() {
|
||||
// Name only cookies are not dropped in RFC6265
|
||||
test(true, "foo=;a=b; ;", FOO_EMPTY, A);
|
||||
test(true, "foo;a=b; ;", FOO_EMPTY, A);
|
||||
test(true, "foo;a=b;bar", FOO_EMPTY, A, BAR_EMPTY);
|
||||
test(true, "foo;a=b;bar;", FOO_EMPTY, A, BAR_EMPTY);
|
||||
test(true, "foo;a=b;bar ", FOO_EMPTY, A, BAR_EMPTY);
|
||||
test(true, "foo;a=b;bar ;", FOO_EMPTY, A, BAR_EMPTY);
|
||||
|
||||
// Bug 49000
|
||||
Cookie fred = new Cookie("fred", "1");
|
||||
Cookie jim = new Cookie("jim", "2");
|
||||
Cookie bobEmpty = new Cookie("bob", "");
|
||||
Cookie george = new Cookie("george", "3");
|
||||
test(true, "fred=1; jim=2; bob", fred, jim, bobEmpty);
|
||||
test(true, "fred=1; jim=2; bob; george=3", fred, jim, bobEmpty, george);
|
||||
test(true, "fred=1; jim=2; bob=; george=3", fred, jim, bobEmpty, george);
|
||||
test(true, "fred=1; jim=2; bob=", fred, jim, bobEmpty);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedValueOld() {
|
||||
doTestQuotedValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedValueRfc6265() {
|
||||
doTestQuotedValue(true);
|
||||
}
|
||||
|
||||
private void doTestQuotedValue(boolean useRfc6265) {
|
||||
test(useRfc6265, "foo=bar;a=\"b\"", FOO, A);
|
||||
test(useRfc6265, "foo=bar;a=\"b\";", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPairsOld() {
|
||||
test(false, "foo;a=b; ;bar", A);
|
||||
test(false, "foo;a=b;;bar", A);
|
||||
test(false, "foo;a=b; ;;bar=rab", A, BAR);
|
||||
test(false, "foo;a=b;; ;bar=rab", A, BAR);
|
||||
test(false, "foo;a=b;;#;bar=rab", A, BAR);
|
||||
test(false, "foo;a=b;;\\;bar=rab", A, BAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPairsRfc6265() {
|
||||
test(true, "foo;a=b; ;bar", FOO_EMPTY, A, BAR_EMPTY);
|
||||
test(true, "foo;a=b;;bar", FOO_EMPTY, A, BAR_EMPTY);
|
||||
test(true, "foo;a=b; ;;bar=rab", FOO_EMPTY, A, BAR);
|
||||
test(true, "foo;a=b;; ;bar=rab", FOO_EMPTY, A, BAR);
|
||||
test(true, "foo;a=b;;#;bar=rab", FOO_EMPTY, A, HASH_EMPTY, BAR);
|
||||
test(true, "foo;a=b;;\\;bar=rab", FOO_EMPTY, A, BAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSeparatorsInValueOld() {
|
||||
doTestSeparatorsInValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSeparatorsInValueRfc6265() {
|
||||
doTestSeparatorsInValue(true);
|
||||
}
|
||||
|
||||
private void doTestSeparatorsInValue(boolean useRfc6265) {
|
||||
test(useRfc6265, "a=()<>@:\\\"/[]?={}\t; foo=bar", FOO);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void v1TokenValueOld() {
|
||||
doV1TokenValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1TokenValueRfc6265() {
|
||||
doV1TokenValue(true);
|
||||
}
|
||||
|
||||
private void doV1TokenValue(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1; foo=bar;a=b", FOO, A);
|
||||
test(useRfc6265, "$Version=1;foo=bar;a=b; ; ", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1NameOnlyIsDroppedOld() {
|
||||
doV1NameOnlyIsDropped(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1NameOnlyIsDroppedRfc6265() {
|
||||
doV1NameOnlyIsDropped(true);
|
||||
}
|
||||
|
||||
private void doV1NameOnlyIsDropped(boolean useRfc6265) {
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=;a=b; ; ", A);
|
||||
test(useRfc6265, "$Version=1;foo= ;a=b; ; ", A);
|
||||
test(useRfc6265, "$Version=1;foo;a=b; ; ", A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuotedValueOld() {
|
||||
doV1QuotedValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuotedValueRfc6265() {
|
||||
doV1QuotedValue(true);
|
||||
}
|
||||
|
||||
private void doV1QuotedValue(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
// presumes quotes are removed
|
||||
test(useRfc6265, "$Version=1;foo=\"bar\";a=b; ; ", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1DQuoteInValueOld() {
|
||||
FOO.setValue("b");
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(false, "$Version=1;foo=\"b\"ar\";a=b", FOO, A); // Incorrectly escaped.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1DQuoteInValueRfc6265() {
|
||||
A.setVersion(1);
|
||||
test(true, "$Version=1;foo=\"b\"ar\";a=b", A); // Incorrectly escaped.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuoteInValueOld() {
|
||||
doV1QuoteInValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuoteInValueRfc6265() {
|
||||
doV1QuoteInValue(true);
|
||||
}
|
||||
|
||||
private void doV1QuoteInValue(boolean useRfc6265) {
|
||||
FOO.setValue("b'ar");
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=b'ar;a=b", FOO, A);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void v1QuoteInQuotedValueOld() {
|
||||
doV1QuoteInQuotedValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuoteInQuotedValueRfc6265() {
|
||||
doV1QuoteInQuotedValue(true);
|
||||
}
|
||||
|
||||
private void doV1QuoteInQuotedValue(boolean useRfc6265) {
|
||||
FOO.setValue("b'ar");
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=\"b'ar\";a=b", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1EscapedDQuoteInValueOld() {
|
||||
doV1EscapedDQuoteInValue(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1EscapedDQuoteInValueRfc6265() {
|
||||
doV1EscapedDQuoteInValue(true);
|
||||
}
|
||||
|
||||
private void doV1EscapedDQuoteInValue(boolean useRfc6265) {
|
||||
FOO.setValue("b\"ar");
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=\"b\\\"ar\";a=b", FOO, A); // correctly escaped.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuotedValueEndsInBackslashOld() {
|
||||
doV1QuotedValueEndsInBackslash(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1QuotedValueEndsInBackslashRfc6265() {
|
||||
doV1QuotedValueEndsInBackslash(true);
|
||||
}
|
||||
|
||||
private void doV1QuotedValueEndsInBackslash(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=bar;a=\"b\\\"", FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1MismatchedQuotesOld() {
|
||||
doV1MismatchedQuotes(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1MismatchedQuotesRfc6265() {
|
||||
doV1MismatchedQuotes(true);
|
||||
}
|
||||
|
||||
private void doV1MismatchedQuotes(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=bar;a=\"b\\", FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1SingleQuotesAreValidTokenCharactersOld() {
|
||||
doV1SingleQuotesAreValidTokenCharacters(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1SingleQuotesAreValidTokenCharactersRfc6265() {
|
||||
doV1SingleQuotesAreValidTokenCharacters(true);
|
||||
}
|
||||
|
||||
private void doV1SingleQuotesAreValidTokenCharacters(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
FOO.setValue("'bar'");
|
||||
test(useRfc6265, "$Version=1; foo='bar'", FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1DomainIsParsedOld() {
|
||||
doV1DomainIsParsed(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1DomainIsParsedRfc6265() {
|
||||
doV1DomainIsParsed(true);
|
||||
}
|
||||
|
||||
private void doV1DomainIsParsed(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
FOO.setDomain("apache.org");
|
||||
A.setVersion(1);
|
||||
A.setDomain("yahoo.com");
|
||||
test(useRfc6265, "$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1DomainOnlyAffectsPrecedingCookieOld() {
|
||||
doV1DomainOnlyAffectsPrecedingCookie(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1DomainOnlyAffectsPrecedingCookieRfc6265() {
|
||||
doV1DomainOnlyAffectsPrecedingCookie(true);
|
||||
}
|
||||
|
||||
private void doV1DomainOnlyAffectsPrecedingCookie(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
FOO.setDomain("apache.org");
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=\"bar\";$Domain=apache.org;a=b", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1PortIsIgnoredOld() {
|
||||
FOO.setVersion(1);
|
||||
FOO.setDomain("apache.org");
|
||||
A.setVersion(1);
|
||||
test(false, "$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1PortIsIgnoredRfc6265() {
|
||||
FOO.setVersion(1);
|
||||
FOO.setDomain("apache.org");
|
||||
$PORT.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(true, "$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b", FOO, $PORT, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1PathAffectsPrecedingCookieOld() {
|
||||
doV1PathAffectsPrecedingCookie(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1PathAffectsPrecedingCookieRfc6265() {
|
||||
doV1PathAffectsPrecedingCookie(true);
|
||||
}
|
||||
|
||||
private void doV1PathAffectsPrecedingCookie(boolean useRfc6265) {
|
||||
FOO.setVersion(1);
|
||||
FOO.setPath("/examples");
|
||||
A.setVersion(1);
|
||||
test(useRfc6265, "$Version=1;foo=\"bar\";$Path=/examples;a=b; ; ", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rfc2109Version0Old() {
|
||||
// rfc2109 semantically does not allow $Version to be 0 but it is valid syntax
|
||||
test(false, "$Version=0;foo=bar", FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rfc2109Version0Rfc6265() {
|
||||
// RFC6265 will parse explicit version 0 using RFC2109
|
||||
test(true, "$Version=0;foo=bar", FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallow8bitInName() {
|
||||
// Bug 55917
|
||||
test(true, "f\u00f6o=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallowControlInName() {
|
||||
// Bug 55917
|
||||
test(true, "f\010o=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallow8BitControlInName() {
|
||||
// Bug 55917
|
||||
test(true, "f\210o=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allow8BitInV0Value() {
|
||||
// Bug 55917
|
||||
test(true, "foo=b\u00e1r", FOO_CONTROL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallow8bitInV1UnquotedValue() {
|
||||
// Bug 55917
|
||||
test(true, "$Version=1; foo=b\u00e1r");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allow8bitInV1QuotedValue() {
|
||||
// Bug 55917
|
||||
FOO_CONTROL.setVersion(1);
|
||||
test(true, "$Version=1; foo=\"b\u00e1r\"", FOO_CONTROL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallowControlInV0Value() {
|
||||
// Bug 55917
|
||||
test(true, "foo=b\010r");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallowControlInV1UnquotedValue() {
|
||||
// Bug 55917
|
||||
test(true, "$Version=1; foo=b\010r");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallowControlInV1QuotedValue() {
|
||||
// Bug 55917 / Bug 55918
|
||||
test(true, "$Version=1; foo=\"b\010r\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallow8BitControlInV1UnquotedValue() {
|
||||
// Bug 55917
|
||||
test(true, "$Version=1; foo=b\210r");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonInV0() {
|
||||
// Bug 55921
|
||||
test(true, "{\"a\":true, \"b\":false};a=b", A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonInV1() {
|
||||
// Bug 55921
|
||||
A.setVersion(1);
|
||||
test(true, "$Version=1;{\"a\":true, \"b\":false};a=b", A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipSemicolonOrComma() {
|
||||
// V1 cookies can also use commas to separate cookies
|
||||
FOO.setVersion(1);
|
||||
A.setVersion(1);
|
||||
test(true, "$Version=1;x\tx=yyy,foo=bar;a=b", FOO, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug60788Rfc6265() {
|
||||
doTestBug60788(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug60788Rfc2109() {
|
||||
doTestBug60788(false);
|
||||
}
|
||||
|
||||
private void doTestBug60788(boolean useRfc6265) {
|
||||
Cookie expected = new Cookie("userId", "foo");
|
||||
expected.setVersion(1);
|
||||
if (useRfc6265) {
|
||||
expected.setDomain("\"www.example.org\"");
|
||||
expected.setPath("\"/\"");
|
||||
} else {
|
||||
// The legacy processor removes the quotes for domain and path
|
||||
expected.setDomain("www.example.org");
|
||||
expected.setPath("/");
|
||||
}
|
||||
|
||||
test(useRfc6265, "$Version=\"1\"; userId=\"foo\";$Path=\"/\";$Domain=\"www.example.org\"",
|
||||
expected);
|
||||
}
|
||||
|
||||
|
||||
private void test(boolean useRfc6265, String header, Cookie... expected) {
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
ServerCookies serverCookies = new ServerCookies(4);
|
||||
CookieProcessor cookieProcessor;
|
||||
|
||||
if (useRfc6265) {
|
||||
cookieProcessor = new Rfc6265CookieProcessor();
|
||||
} else {
|
||||
cookieProcessor = new LegacyCookieProcessor();
|
||||
}
|
||||
MessageBytes cookieHeaderValue = mimeHeaders.addValue("Cookie");
|
||||
byte[] bytes = header.getBytes(StandardCharsets.UTF_8);
|
||||
cookieHeaderValue.setBytes(bytes, 0, bytes.length);
|
||||
cookieProcessor.parseCookieHeader(mimeHeaders, serverCookies);
|
||||
Assert.assertEquals(expected.length, serverCookies.getCookieCount());
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
Cookie cookie = expected[i];
|
||||
ServerCookie actual = serverCookies.getCookie(i);
|
||||
Assert.assertEquals(cookie.getVersion(), actual.getVersion());
|
||||
Assert.assertEquals(cookie.getName(), actual.getName().toString());
|
||||
actual.getValue().getByteChunk().setCharset(StandardCharsets.UTF_8);
|
||||
Assert.assertEquals(cookie.getValue(),
|
||||
org.apache.tomcat.util.http.parser.Cookie.unescapeCookieValueRfc2109(
|
||||
actual.getValue().toString()));
|
||||
if (cookie.getVersion() == 1) {
|
||||
Assert.assertEquals(cookie.getDomain(), actual.getDomain().toString());
|
||||
Assert.assertEquals(cookie.getPath(), actual.getPath().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* Test case for {@link LegacyCookieProcessor}. <b>Note</b> because of the use
|
||||
* of <code>final static</code> constants in the cookie processing code, each of
|
||||
* these tests must be executed in a new JVM instance. The tests have been place
|
||||
* in separate classes to facilitate this when running the unit tests via Ant.
|
||||
*/
|
||||
public class TestCookiesDefaultSysProps extends CookiesBaseTest {
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testCookiesInstance() throws Exception {
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
addServlets(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
ByteChunk res = getUrl("http://localhost:" + getPort() + "/invalid");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/null");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/blank");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/valid");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
|
||||
// Need to read response headers to test version switching
|
||||
Map<String,List<String>> headers = new HashMap<>();
|
||||
getUrl("http://localhost:" + getPort() + "/switch", res, headers);
|
||||
List<String> cookieHeaders = headers.get("Set-Cookie");
|
||||
for (String cookieHeader : cookieHeaders) {
|
||||
Assert.assertEquals("name=\"val?ue\"; Version=1", cookieHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* Test case for {@link LegacyCookieProcessor}. <b>Note</b> because of the use
|
||||
* of <code>final static</code> constants in the cookie processing code, each of
|
||||
* these tests must be executed in a new JVM instance. The tests have been place
|
||||
* in separate classes to facilitate this when running the unit tests via Ant.
|
||||
*/
|
||||
public class TestCookiesNoFwdStrictSysProps extends CookiesBaseTest {
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testCookiesInstance() throws Exception {
|
||||
|
||||
System.setProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
|
||||
"true");
|
||||
System.setProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR",
|
||||
"false");
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
addServlets(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
ByteChunk res = getUrl("http://localhost:" + getPort() + "/invalid");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/null");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/blank");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/valid");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* Test case for {@link LegacyCookieProcessor}. <b>Note</b> because of the use
|
||||
* of <code>final static</code> constants in the cookie processing code, each of
|
||||
* these tests must be executed in a new JVM instance. The tests have been place
|
||||
* in separate classes to facilitate this when running the unit tests via Ant.
|
||||
*/
|
||||
public class TestCookiesNoStrictNamingSysProps extends CookiesBaseTest {
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testCookiesInstance() throws Exception {
|
||||
|
||||
System.setProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
|
||||
"true");
|
||||
System.setProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING",
|
||||
"false");
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
addServlets(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
ByteChunk res = getUrl("http://localhost:" + getPort() + "/invalid");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/null");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/blank");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/valid");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* Test case for {@link LegacyCookieProcessor}. <b>Note</b> because of the use
|
||||
* of <code>final static</code> constants in the cookie processing code, each of
|
||||
* these tests must be executed in a new JVM instance. The tests have been place
|
||||
* in separate classes to facilitate this when running the unit tests via Ant.
|
||||
*/
|
||||
public class TestCookiesStrictSysProps extends CookiesBaseTest {
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testCookiesInstance() throws Exception {
|
||||
|
||||
System.setProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
|
||||
"true");
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
addServlets(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
ByteChunk res = getUrl("http://localhost:" + getPort() + "/invalid");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/null");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/blank");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
|
||||
Assert.assertEquals("Cookie name fail", res.toString());
|
||||
res = getUrl("http://localhost:" + getPort() + "/valid");
|
||||
Assert.assertEquals("Cookie name ok", res.toString());
|
||||
|
||||
// Need to read response headers to test version switching
|
||||
Map<String,List<String>> headers = new HashMap<>();
|
||||
getUrl("http://localhost:" + getPort() + "/switch", res, headers);
|
||||
List<String> cookieHeaders = headers.get("Set-Cookie");
|
||||
for (String cookieHeader : cookieHeaders) {
|
||||
Assert.assertEquals("name=\"val?ue\"; Version=1", cookieHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class TestHeaderUtiltoPrintableString {
|
||||
|
||||
@Parameterized.Parameters(name = "{index}: expected[{1}]")
|
||||
public static Collection<Object[]> parameters() {
|
||||
List<Object[]> parameterSets = new ArrayList<>();
|
||||
|
||||
parameterSets.add(new String[] { "", "" });
|
||||
|
||||
parameterSets.add(new String[] { "abcd", "abcd" });
|
||||
|
||||
parameterSets.add(new String[] { "\u0000abcd", "0x00abcd" });
|
||||
parameterSets.add(new String[] { "ab\u0000cd", "ab0x00cd" });
|
||||
parameterSets.add(new String[] { "abcd\u0000", "abcd0x00" });
|
||||
|
||||
parameterSets.add(new String[] { "\tabcd", "0x09abcd" });
|
||||
parameterSets.add(new String[] { "ab\tcd", "ab0x09cd" });
|
||||
parameterSets.add(new String[] { "abcd\t", "abcd0x09" });
|
||||
|
||||
parameterSets.add(new String[] { " abcd", " abcd" });
|
||||
parameterSets.add(new String[] { "ab cd", "ab cd" });
|
||||
parameterSets.add(new String[] { "abcd ", "abcd " });
|
||||
|
||||
parameterSets.add(new String[] { "~abcd", "~abcd" });
|
||||
parameterSets.add(new String[] { "ab~cd", "ab~cd" });
|
||||
parameterSets.add(new String[] { "abcd~", "abcd~" });
|
||||
|
||||
parameterSets.add(new String[] { "\u007fabcd", "0x7fabcd" });
|
||||
parameterSets.add(new String[] { "ab\u007fcd", "ab0x7fcd" });
|
||||
parameterSets.add(new String[] { "abcd\u007f", "abcd0x7f" });
|
||||
|
||||
parameterSets.add(new String[] { "\u00a3abcd", "0xa3abcd" });
|
||||
parameterSets.add(new String[] { "ab\u00a3cd", "ab0xa3cd" });
|
||||
parameterSets.add(new String[] { "abcd\u00a3", "abcd0xa3" });
|
||||
|
||||
return parameterSets;
|
||||
}
|
||||
|
||||
|
||||
@Parameter(0)
|
||||
public String input;
|
||||
@Parameter(1)
|
||||
public String expected;
|
||||
|
||||
|
||||
@Test
|
||||
public void doTest() {
|
||||
byte[] bytes = input.getBytes(StandardCharsets.ISO_8859_1);
|
||||
|
||||
String result = HeaderUtil.toPrintableString(bytes, 0, bytes.length);
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
|
||||
public class TestLegacyCookieProcessor {
|
||||
|
||||
/*
|
||||
* https://bz.apache.org/bugzilla/show_bug.cgi?id=59925
|
||||
*/
|
||||
@Test
|
||||
public void testV0WithPath() {
|
||||
LegacyCookieProcessor cp = new LegacyCookieProcessor();
|
||||
cp.setAllowHttpSepsInV0(true);
|
||||
cp.setForwardSlashIsSeparator(true);
|
||||
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
ServerCookies serverCookies = new ServerCookies(4);
|
||||
|
||||
MessageBytes cookieHeaderValue = mimeHeaders.addValue("Cookie");
|
||||
byte[] bytes = "$Version=0;cname=cvalue;$Path=/example".getBytes(StandardCharsets.UTF_8);
|
||||
cookieHeaderValue.setBytes(bytes, 0, bytes.length);
|
||||
cp.parseCookieHeader(mimeHeaders, serverCookies);
|
||||
Assert.assertEquals(1, serverCookies.getCookieCount());
|
||||
for (int i = 0; i < 1; i++) {
|
||||
ServerCookie actual = serverCookies.getCookie(i);
|
||||
Assert.assertEquals(0, actual.getVersion());
|
||||
Assert.assertEquals("cname", actual.getName().toString());
|
||||
actual.getValue().getByteChunk().setCharset(StandardCharsets.UTF_8);
|
||||
Assert.assertEquals("cvalue",
|
||||
org.apache.tomcat.util.http.parser.Cookie.unescapeCookieValueRfc2109(
|
||||
actual.getValue().toString()));
|
||||
Assert.assertEquals("/example", actual.getPath().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
64
test/org/apache/tomcat/util/http/TestMimeHeaders.java
Normal file
64
test/org/apache/tomcat/util/http/TestMimeHeaders.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestMimeHeaders {
|
||||
|
||||
public static final String HEADER_NAME_LC_STRING = "test";
|
||||
public static final String HEADER_NAME_UC_STRING = "TEST";
|
||||
public static final String HEADER_NAME_MIXED_STRING = "tEsT";
|
||||
|
||||
@Test
|
||||
public void testSetValueStringIgnoresCase01() {
|
||||
MimeHeaders mh = new MimeHeaders();
|
||||
|
||||
mh.setValue(HEADER_NAME_LC_STRING).setString(HEADER_NAME_LC_STRING);
|
||||
mh.setValue(HEADER_NAME_UC_STRING).setString(HEADER_NAME_UC_STRING);
|
||||
|
||||
Assert.assertEquals(HEADER_NAME_UC_STRING, mh.getValue(HEADER_NAME_UC_STRING).toString());
|
||||
Assert.assertEquals(HEADER_NAME_UC_STRING, mh.getValue(HEADER_NAME_LC_STRING).toString());
|
||||
Assert.assertEquals(HEADER_NAME_UC_STRING, mh.getValue(HEADER_NAME_MIXED_STRING).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValueStringIgnoresCase02() {
|
||||
MimeHeaders mh = new MimeHeaders();
|
||||
|
||||
mh.setValue(HEADER_NAME_UC_STRING).setString(HEADER_NAME_UC_STRING);
|
||||
mh.setValue(HEADER_NAME_LC_STRING).setString(HEADER_NAME_LC_STRING);
|
||||
|
||||
Assert.assertEquals(HEADER_NAME_LC_STRING, mh.getValue(HEADER_NAME_LC_STRING).toString());
|
||||
Assert.assertEquals(HEADER_NAME_LC_STRING, mh.getValue(HEADER_NAME_UC_STRING).toString());
|
||||
Assert.assertEquals(HEADER_NAME_LC_STRING, mh.getValue(HEADER_NAME_MIXED_STRING).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValueStringIgnoresCase03() {
|
||||
MimeHeaders mh = new MimeHeaders();
|
||||
|
||||
mh.setValue(HEADER_NAME_UC_STRING).setString(HEADER_NAME_UC_STRING);
|
||||
mh.setValue(HEADER_NAME_MIXED_STRING).setString(HEADER_NAME_MIXED_STRING);
|
||||
|
||||
Assert.assertEquals(HEADER_NAME_MIXED_STRING, mh.getValue(HEADER_NAME_LC_STRING).toString());
|
||||
Assert.assertEquals(HEADER_NAME_MIXED_STRING, mh.getValue(HEADER_NAME_UC_STRING).toString());
|
||||
Assert.assertEquals(HEADER_NAME_MIXED_STRING, mh.getValue(HEADER_NAME_MIXED_STRING).toString());
|
||||
}
|
||||
|
||||
}
|
||||
182
test/org/apache/tomcat/util/http/TestMimeHeadersIntegration.java
Normal file
182
test/org/apache/tomcat/util/http/TestMimeHeadersIntegration.java
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.SocketException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.startup.SimpleHttpClient;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.catalina.valves.TesterAccessLogValve;
|
||||
|
||||
public class TestMimeHeadersIntegration extends TomcatBaseTest {
|
||||
|
||||
private HeaderCountLogValve alv;
|
||||
|
||||
private void setupHeadersTest(Tomcat tomcat) {
|
||||
Context ctx = tomcat.addContext("", getTemporaryDirectory()
|
||||
.getAbsolutePath());
|
||||
Tomcat.addServlet(ctx, "servlet", new HttpServlet() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
res.setContentType("text/plain; charset=ISO-8859-1");
|
||||
res.getWriter().write("OK");
|
||||
}
|
||||
});
|
||||
ctx.addServletMappingDecoded("/", "servlet");
|
||||
|
||||
alv = new HeaderCountLogValve();
|
||||
tomcat.getHost().getPipeline().addValve(alv);
|
||||
}
|
||||
|
||||
private void runHeadersTest(final boolean successExpected,
|
||||
final Tomcat tomcat, final int count,
|
||||
final int expectedMaxHeaderCount) throws Exception {
|
||||
tomcat.start();
|
||||
|
||||
String header = "A:B" + SimpleHttpClient.CRLF;
|
||||
StringBuilder request = new StringBuilder();
|
||||
request.append("GET / HTTP/1.0" + SimpleHttpClient.CRLF);
|
||||
for (int i = 0; i < count; i++) {
|
||||
request.append(header);
|
||||
}
|
||||
request.append(SimpleHttpClient.CRLF);
|
||||
|
||||
Client client = new Client(tomcat);
|
||||
client.setRequest(new String[] { request.toString() });
|
||||
try {
|
||||
client.connect();
|
||||
client.processRequest();
|
||||
client.disconnect();
|
||||
} catch (SocketException ex) {
|
||||
// Connection was closed by Tomcat
|
||||
if (successExpected) {
|
||||
// unexpected
|
||||
log.error(ex.getMessage(), ex);
|
||||
} else {
|
||||
log.warn(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
if (successExpected) {
|
||||
alv.validateAccessLog(1, 200, 0, 3000);
|
||||
// Response 200
|
||||
Assert.assertTrue("Response line is: " + client.getResponseLine(),
|
||||
client.getResponseLine() != null && client.isResponse200());
|
||||
Assert.assertEquals("OK", client.getResponseBody());
|
||||
} else {
|
||||
alv.validateAccessLog(1, 400, 0, 3000);
|
||||
// Connection aborted or response 400
|
||||
Assert.assertTrue("Response line is: " + client.getResponseLine(),
|
||||
client.getResponseLine() == null || client.isResponse400());
|
||||
}
|
||||
int maxHeaderCount =
|
||||
((Integer) tomcat.getConnector().getProperty("maxHeaderCount")).intValue();
|
||||
Assert.assertEquals(expectedMaxHeaderCount, maxHeaderCount);
|
||||
if (maxHeaderCount > 0) {
|
||||
Assert.assertEquals(maxHeaderCount, alv.arraySize);
|
||||
} else if (maxHeaderCount < 0) {
|
||||
int maxHttpHeaderSize = ((Integer) tomcat.getConnector()
|
||||
.getAttribute("maxHttpHeaderSize")).intValue();
|
||||
int headerCount = Math.min(count,
|
||||
maxHttpHeaderSize / header.length() + 1);
|
||||
int arraySize = 1;
|
||||
while (arraySize < headerCount) {
|
||||
arraySize <<= 1;
|
||||
}
|
||||
Assert.assertEquals(arraySize, alv.arraySize);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderLimits1() throws Exception {
|
||||
// Bumping into maxHttpHeaderSize
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
setupHeadersTest(tomcat);
|
||||
Assert.assertTrue(tomcat.getConnector().setProperty("maxHeaderCount", "-1"));
|
||||
runHeadersTest(false, tomcat, 8 * 1024, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderLimits2() throws Exception {
|
||||
// Can process 100 headers
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
setupHeadersTest(tomcat);
|
||||
runHeadersTest(true, tomcat, 100, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderLimits3() throws Exception {
|
||||
// Cannot process 101 header
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
setupHeadersTest(tomcat);
|
||||
runHeadersTest(false, tomcat, 101, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderLimits4() throws Exception {
|
||||
// Can change maxHeaderCount
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
setupHeadersTest(tomcat);
|
||||
Assert.assertTrue(tomcat.getConnector().setProperty("maxHeaderCount", "-1"));
|
||||
runHeadersTest(true, tomcat, 300, -1);
|
||||
}
|
||||
|
||||
private static final class HeaderCountLogValve extends TesterAccessLogValve {
|
||||
public volatile int arraySize = -1;
|
||||
|
||||
@Override
|
||||
public void log(Request request, Response response, long time) {
|
||||
super.log(request, response, time);
|
||||
try {
|
||||
MimeHeaders mh = request.getCoyoteRequest().getMimeHeaders();
|
||||
Field headersArrayField = MimeHeaders.class
|
||||
.getDeclaredField("headers");
|
||||
headersArrayField.setAccessible(true);
|
||||
arraySize = ((Object[]) headersArrayField.get(mh)).length;
|
||||
} catch (Exception ex) {
|
||||
Assert.assertNull(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Client extends SimpleHttpClient {
|
||||
public Client(Tomcat tomcat) {
|
||||
setPort(tomcat.getConnector().getLocalPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResponseBodyOK() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
318
test/org/apache/tomcat/util/http/TestParameters.java
Normal file
318
test/org/apache/tomcat/util/http/TestParameters.java
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestParameters {
|
||||
|
||||
private static final Parameter SIMPLE =
|
||||
new Parameter("foo1", "bar1");
|
||||
private static final Parameter SIMPLE_MULTIPLE =
|
||||
new Parameter("foo2", "bar1", "bar2", "hello world", "?%@");
|
||||
private static final Parameter NO_VALUE =
|
||||
new Parameter("foo3");
|
||||
private static final Parameter EMPTY_VALUE =
|
||||
new Parameter("foo4", "");
|
||||
private static final Parameter EMPTY =
|
||||
new Parameter("");
|
||||
private static final Parameter UTF8 =
|
||||
new Parameter("\ufb6b\ufb6a\ufb72", "\uffee\uffeb\uffe2");
|
||||
|
||||
@Test
|
||||
public void testProcessParametersByteArrayIntInt() {
|
||||
doTestProcessParametersByteArrayIntInt(-1, SIMPLE);
|
||||
doTestProcessParametersByteArrayIntInt(-1, SIMPLE_MULTIPLE);
|
||||
doTestProcessParametersByteArrayIntInt(-1, NO_VALUE);
|
||||
doTestProcessParametersByteArrayIntInt(-1, EMPTY_VALUE);
|
||||
doTestProcessParametersByteArrayIntInt(-1, EMPTY);
|
||||
doTestProcessParametersByteArrayIntInt(-1, UTF8);
|
||||
doTestProcessParametersByteArrayIntInt(-1,
|
||||
SIMPLE, SIMPLE_MULTIPLE, NO_VALUE, EMPTY_VALUE, EMPTY, UTF8);
|
||||
doTestProcessParametersByteArrayIntInt(-1,
|
||||
SIMPLE_MULTIPLE, NO_VALUE, EMPTY_VALUE, EMPTY, UTF8, SIMPLE);
|
||||
doTestProcessParametersByteArrayIntInt(-1,
|
||||
NO_VALUE, EMPTY_VALUE, EMPTY, UTF8, SIMPLE, SIMPLE_MULTIPLE);
|
||||
doTestProcessParametersByteArrayIntInt(-1,
|
||||
EMPTY_VALUE, EMPTY, UTF8, SIMPLE, SIMPLE_MULTIPLE, NO_VALUE);
|
||||
doTestProcessParametersByteArrayIntInt(-1,
|
||||
EMPTY, UTF8, SIMPLE, SIMPLE_MULTIPLE, NO_VALUE, EMPTY_VALUE);
|
||||
doTestProcessParametersByteArrayIntInt(-1,
|
||||
UTF8, SIMPLE, SIMPLE_MULTIPLE, NO_VALUE, EMPTY_VALUE, EMPTY);
|
||||
|
||||
doTestProcessParametersByteArrayIntInt(1,
|
||||
SIMPLE, NO_VALUE, EMPTY_VALUE, UTF8);
|
||||
doTestProcessParametersByteArrayIntInt(2,
|
||||
SIMPLE, NO_VALUE, EMPTY_VALUE, UTF8);
|
||||
doTestProcessParametersByteArrayIntInt(3,
|
||||
SIMPLE, NO_VALUE, EMPTY_VALUE, UTF8);
|
||||
doTestProcessParametersByteArrayIntInt(4,
|
||||
SIMPLE, NO_VALUE, EMPTY_VALUE, UTF8);
|
||||
}
|
||||
|
||||
// Make sure the inner Parameter class behaves correctly
|
||||
@Test
|
||||
public void testInternal() {
|
||||
Assert.assertEquals("foo1=bar1", SIMPLE.toString());
|
||||
// Note: testing requires that ' ' is encoded as '+',
|
||||
// because that is what browsers will send us.
|
||||
Assert.assertEquals("foo2=bar1&foo2=bar2&foo2=hello+world&foo2=%3F%25%40",
|
||||
SIMPLE_MULTIPLE.toString());
|
||||
Assert.assertEquals("foo3", NO_VALUE.toString());
|
||||
Assert.assertEquals("foo4=", EMPTY_VALUE.toString());
|
||||
}
|
||||
|
||||
private long doTestProcessParametersByteArrayIntInt(int limit,
|
||||
Parameter... parameters) {
|
||||
|
||||
// Build the byte array
|
||||
StringBuilder input = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Parameter parameter : parameters) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
input.append('&');
|
||||
}
|
||||
input.append(parameter.toString());
|
||||
}
|
||||
|
||||
byte[] data = input.toString().getBytes();
|
||||
|
||||
Parameters p = new Parameters();
|
||||
p.setCharset(StandardCharsets.UTF_8);
|
||||
p.setLimit(limit);
|
||||
|
||||
long start = System.nanoTime();
|
||||
p.processParameters(data, 0, data.length);
|
||||
long end = System.nanoTime();
|
||||
|
||||
if (limit == -1) {
|
||||
validateParameters(parameters, p);
|
||||
} else {
|
||||
Parameter[] limitParameters = new Parameter[limit];
|
||||
System.arraycopy(parameters, 0, limitParameters, 0, limit);
|
||||
validateParameters(limitParameters, p);
|
||||
}
|
||||
return end - start;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonExistantParameter() {
|
||||
Parameters p = new Parameters();
|
||||
|
||||
String value = p.getParameter("foo");
|
||||
Assert.assertNull(value);
|
||||
|
||||
Enumeration<String> names = p.getParameterNames();
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
|
||||
String[] values = p.getParameterValues("foo");
|
||||
Assert.assertNull(values);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddParameters() {
|
||||
Parameters p = new Parameters();
|
||||
|
||||
// Empty at this point
|
||||
Enumeration<String> names = p.getParameterNames();
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
String[] values = p.getParameterValues("foo");
|
||||
Assert.assertNull(values);
|
||||
|
||||
// Add a parameter with two values
|
||||
p.addParameter("foo", "value1");
|
||||
p.addParameter("foo", "value2");
|
||||
|
||||
names = p.getParameterNames();
|
||||
Assert.assertTrue(names.hasMoreElements());
|
||||
Assert.assertEquals("foo", names.nextElement());
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
|
||||
values = p.getParameterValues("foo");
|
||||
Assert.assertEquals(2, values.length);
|
||||
Assert.assertEquals("value1", values[0]);
|
||||
Assert.assertEquals("value2", values[1]);
|
||||
|
||||
// Add two more values
|
||||
p.addParameter("foo", "value3");
|
||||
p.addParameter("foo", "value4");
|
||||
|
||||
names = p.getParameterNames();
|
||||
Assert.assertTrue(names.hasMoreElements());
|
||||
Assert.assertEquals("foo", names.nextElement());
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
|
||||
values = p.getParameterValues("foo");
|
||||
Assert.assertEquals(4, values.length);
|
||||
Assert.assertEquals("value1", values[0]);
|
||||
Assert.assertEquals("value2", values[1]);
|
||||
Assert.assertEquals("value3", values[2]);
|
||||
Assert.assertEquals("value4", values[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddParametersLimit() {
|
||||
Parameters p = new Parameters();
|
||||
|
||||
p.setLimit(2);
|
||||
|
||||
// Empty at this point
|
||||
Enumeration<String> names = p.getParameterNames();
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
String[] values = p.getParameterValues("foo1");
|
||||
Assert.assertNull(values);
|
||||
|
||||
// Add a parameter
|
||||
p.addParameter("foo1", "value1");
|
||||
|
||||
names = p.getParameterNames();
|
||||
Assert.assertTrue(names.hasMoreElements());
|
||||
Assert.assertEquals("foo1", names.nextElement());
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
|
||||
values = p.getParameterValues("foo1");
|
||||
Assert.assertEquals(1, values.length);
|
||||
Assert.assertEquals("value1", values[0]);
|
||||
|
||||
// Add another parameter
|
||||
p.addParameter("foo2", "value2");
|
||||
|
||||
names = p.getParameterNames();
|
||||
Assert.assertTrue(names.hasMoreElements());
|
||||
Assert.assertEquals("foo1", names.nextElement());
|
||||
Assert.assertEquals("foo2", names.nextElement());
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
|
||||
values = p.getParameterValues("foo1");
|
||||
Assert.assertEquals(1, values.length);
|
||||
Assert.assertEquals("value1", values[0]);
|
||||
|
||||
values = p.getParameterValues("foo2");
|
||||
Assert.assertEquals(1, values.length);
|
||||
Assert.assertEquals("value2", values[0]);
|
||||
|
||||
// Add another parameter
|
||||
IllegalStateException e = null;
|
||||
try {
|
||||
p.addParameter("foo3", "value3");
|
||||
} catch (IllegalStateException ise) {
|
||||
e = ise;
|
||||
}
|
||||
Assert.assertNotNull(e);
|
||||
|
||||
// Check current parameters remain unaffected
|
||||
names = p.getParameterNames();
|
||||
Assert.assertTrue(names.hasMoreElements());
|
||||
Assert.assertEquals("foo1", names.nextElement());
|
||||
Assert.assertEquals("foo2", names.nextElement());
|
||||
Assert.assertFalse(names.hasMoreElements());
|
||||
|
||||
values = p.getParameterValues("foo1");
|
||||
Assert.assertEquals(1, values.length);
|
||||
Assert.assertEquals("value1", values[0]);
|
||||
|
||||
values = p.getParameterValues("foo2");
|
||||
Assert.assertEquals(1, values.length);
|
||||
Assert.assertEquals("value2", values[0]);
|
||||
|
||||
}
|
||||
|
||||
private void validateParameters(Parameter[] parameters, Parameters p) {
|
||||
Enumeration<String> names = p.getParameterNames();
|
||||
|
||||
int i = 0;
|
||||
while (names.hasMoreElements()) {
|
||||
while (parameters[i].getName() == null) {
|
||||
i++;
|
||||
}
|
||||
|
||||
String name = names.nextElement();
|
||||
String[] values = p.getParameterValues(name);
|
||||
|
||||
boolean match = false;
|
||||
|
||||
for (Parameter parameter : parameters) {
|
||||
if (name.equals(parameter.getName())) {
|
||||
match = true;
|
||||
if (parameter.values.length == 0) {
|
||||
// Special case
|
||||
Assert.assertArrayEquals(new String[] {""}, values);
|
||||
} else {
|
||||
Assert.assertArrayEquals(parameter.getValues(), values);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.assertTrue(match);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Parameter {
|
||||
private final String name;
|
||||
private final String[] values;
|
||||
|
||||
public Parameter(String name, String... values) {
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String[] getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean first = true;
|
||||
if (values.length == 0) {
|
||||
return URLEncoder.encode(name, "UTF-8");
|
||||
}
|
||||
for (String value : values) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
result.append('&');
|
||||
}
|
||||
if (name != null) {
|
||||
result.append(URLEncoder.encode(name, "UTF-8"));
|
||||
}
|
||||
if (value != null) {
|
||||
result.append('=');
|
||||
result.append(URLEncoder.encode(value, "UTF-8"));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
return ex.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class TestRequestUtilNormalize {
|
||||
|
||||
@Parameterized.Parameters(name = "{index}: input[{0}]")
|
||||
public static Collection<Object[]> parameters() {
|
||||
List<Object[]> parameterSets = new ArrayList<>();
|
||||
|
||||
parameterSets.add(new String[] { "//something", "/something" });
|
||||
parameterSets.add(new String[] { "some//thing", "/some/thing" });
|
||||
parameterSets.add(new String[] { "something//", "/something/" });
|
||||
parameterSets.add(new String[] { "//", "/" });
|
||||
parameterSets.add(new String[] { "///", "/" });
|
||||
parameterSets.add(new String[] { "////", "/" });
|
||||
parameterSets.add(new String[] { "/.", "/" });
|
||||
parameterSets.add(new String[] { "/./", "/" });
|
||||
parameterSets.add(new String[] { ".", "/" });
|
||||
parameterSets.add(new String[] { "/..", null });
|
||||
parameterSets.add(new String[] { "/../", null });
|
||||
parameterSets.add(new String[] { "..", null });
|
||||
parameterSets.add(new String[] { "//..", null });
|
||||
parameterSets.add(new String[] { "//../", null });
|
||||
parameterSets.add(new String[] { "/./..", null });
|
||||
parameterSets.add(new String[] { "/./../", null });
|
||||
parameterSets.add(new String[] { "/a/../..", null });
|
||||
parameterSets.add(new String[] { "/a/../../", null });
|
||||
parameterSets.add(new String[] { "/a/..", "/" });
|
||||
parameterSets.add(new String[] { "/a/.", "/a" });
|
||||
parameterSets.add(new String[] { "/a/../", "/" });
|
||||
parameterSets.add(new String[] { "/a/./", "/a/" });
|
||||
parameterSets.add(new String[] { "/a/b/..", "/a" });
|
||||
parameterSets.add(new String[] { "/a/b/.", "/a/b" });
|
||||
parameterSets.add(new String[] { "/a/b/../", "/a/" });
|
||||
parameterSets.add(new String[] { "/a/b/./", "/a/b/" });
|
||||
|
||||
return parameterSets;
|
||||
}
|
||||
|
||||
|
||||
@Parameter(0)
|
||||
public String input;
|
||||
@Parameter(1)
|
||||
public String expected;
|
||||
|
||||
|
||||
@Test
|
||||
public void testNormalize() {
|
||||
Assert.assertEquals(expected,RequestUtil.normalize(input));
|
||||
}
|
||||
}
|
||||
113
test/org/apache/tomcat/util/http/TestRequestUtilSameOrigin.java
Normal file
113
test/org/apache/tomcat/util/http/TestRequestUtilSameOrigin.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class TestRequestUtilSameOrigin {
|
||||
|
||||
@Parameterized.Parameters(name = "{index}: request[{0}], origin[{1}]")
|
||||
public static Collection<Object[]> parameters() {
|
||||
List<Object[]> parameterSets = new ArrayList<>();
|
||||
|
||||
TesterRequest request1 = new TesterRequest("http", "example.com", 80);
|
||||
TesterRequest request2 = new TesterRequest("ws", "example.com", 80);
|
||||
TesterRequest request3 = new TesterRequest("http", "example.com", 443);
|
||||
TesterRequest request4 = new TesterRequest("http", "example.com", 8080);
|
||||
|
||||
parameterSets.add(new Object[] { request1, "http://example.com", Boolean.TRUE });
|
||||
parameterSets.add(new Object[] { request1, "http://example.com:80", Boolean.TRUE });
|
||||
parameterSets.add(new Object[] { request1, "http://example.com:8080", Boolean.FALSE});
|
||||
|
||||
parameterSets.add(new Object[] { request2, "ws://example.com", Boolean.TRUE });
|
||||
parameterSets.add(new Object[] { request2, "ws://example.com:80", Boolean.TRUE });
|
||||
parameterSets.add(new Object[] { request2, "ws://example.com:8080", Boolean.FALSE});
|
||||
|
||||
parameterSets.add(new Object[] { request3, "http://example.com", Boolean.FALSE });
|
||||
parameterSets.add(new Object[] { request3, "http://example.com:80", Boolean.FALSE });
|
||||
parameterSets.add(new Object[] { request3, "http://example.com:443", Boolean.TRUE});
|
||||
|
||||
parameterSets.add(new Object[] { request4, "http://example.com", Boolean.FALSE });
|
||||
parameterSets.add(new Object[] { request4, "http://example.com:80", Boolean.FALSE });
|
||||
parameterSets.add(new Object[] { request4, "http://example.com:8080", Boolean.TRUE});
|
||||
|
||||
return parameterSets;
|
||||
}
|
||||
|
||||
|
||||
@Parameter(0)
|
||||
public HttpServletRequest request;
|
||||
@Parameter(1)
|
||||
public String origin;
|
||||
@Parameter(2)
|
||||
public Boolean same;
|
||||
|
||||
|
||||
@Test
|
||||
public void testSameOrigin() {
|
||||
Assert.assertEquals(same, Boolean.valueOf(RequestUtil.isSameOrigin(request, origin)));
|
||||
}
|
||||
|
||||
|
||||
private static class TesterRequest extends HttpServletRequestWrapper {
|
||||
|
||||
private final String scheme;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public TesterRequest(String scheme, String host, int port) {
|
||||
super(new Request());
|
||||
this.scheme = scheme;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return scheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return scheme + "://" + host + ":" + port;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
test/org/apache/tomcat/util/http/TestResponseUtil.java
Normal file
217
test/org/apache/tomcat/util/http/TestResponseUtil.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.unittest.TesterResponse;
|
||||
|
||||
public class TestResponseUtil {
|
||||
|
||||
@Test
|
||||
public void testAddValidWithAll() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "host");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(response, "*", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddAllWithAll() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "*");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(response, "*", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddAllWithNone() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(response, "*", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithValidSingleHeader() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "foo, bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("too");
|
||||
doTestAddVaryFieldName(response, "too", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithValidSingleHeaderIncludingAll() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "foo, *");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(response, "too", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithValidSingleHeaderAlreadyPresent() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "foo, bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
doTestAddVaryFieldName(response, "foo", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithValidHeaders() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "foo");
|
||||
response.addHeader("vary", "bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("too");
|
||||
doTestAddVaryFieldName(response, "too", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithValidHeadersIncludingAll() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "foo");
|
||||
response.addHeader("vary", "*");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(response, "too", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithValidHeadersAlreadyPresent() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "foo");
|
||||
response.addHeader("vary", "bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
doTestAddVaryFieldName(response, "foo", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithPartiallyValidSingleHeader() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "{{{, bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("too");
|
||||
doTestAddVaryFieldName(response, "too", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithPartiallyValidSingleHeaderIncludingAll() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "{{{, *");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(response, "too", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddValidWithPartiallyValidSingleHeaderAlreadyPresent() {
|
||||
TesterResponse response = new TesterResponse();
|
||||
response.getCoyoteResponse();
|
||||
response.addHeader("vary", "{{{, bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
doTestAddVaryFieldName(response, "bar", expected);
|
||||
}
|
||||
|
||||
|
||||
private void doTestAddVaryFieldName(TesterResponse response, String fieldName,
|
||||
Set<String> expected) {
|
||||
ResponseUtil.addVaryFieldName(response, fieldName);
|
||||
// There will now only be one Vary header
|
||||
String resultHeader = response.getHeader("vary");
|
||||
Set<String> result = new HashSet<>();
|
||||
// Deliberately do not use Vary.parseVary as it will skip invalid values.
|
||||
for (String value : resultHeader.split(",")) {
|
||||
result.add(value.trim());
|
||||
}
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMimeHeadersAddAllWithNone() {
|
||||
MimeHeaders mh = new MimeHeaders();
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestAddVaryFieldName(mh, "*", expected);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMimeHeadersAddValidWithValidHeaders() {
|
||||
MimeHeaders mh = new MimeHeaders();
|
||||
mh.addValue("vary").setString("foo");
|
||||
mh.addValue("vary").setString("bar");
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("too");
|
||||
doTestAddVaryFieldName(mh, "too", expected);
|
||||
}
|
||||
|
||||
private void doTestAddVaryFieldName(MimeHeaders mh, String fieldName,
|
||||
Set<String> expected) {
|
||||
ResponseUtil.addVaryFieldName(mh, fieldName);
|
||||
// There will now only be one Vary header
|
||||
String resultHeader = mh.getHeader("vary");
|
||||
Set<String> result = new HashSet<>();
|
||||
// Deliberately do not use Vary.parseVary as it will skip invalid values.
|
||||
for (String value : resultHeader.split(",")) {
|
||||
result.add(value.trim());
|
||||
}
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
116
test/org/apache/tomcat/util/http/TestSameSiteCookies.java
Normal file
116
test/org/apache/tomcat/util/http/TestSameSiteCookies.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class TestSameSiteCookies {
|
||||
|
||||
@Test
|
||||
public void testUnset() {
|
||||
SameSiteCookies attribute = SameSiteCookies.UNSET;
|
||||
|
||||
Assert.assertEquals("Unset", attribute.getValue());
|
||||
Assert.assertEquals(SameSiteCookies.UNSET, attribute);
|
||||
|
||||
Assert.assertNotEquals(SameSiteCookies.NONE, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.LAX, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.STRICT, attribute);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNone() {
|
||||
SameSiteCookies attribute = SameSiteCookies.NONE;
|
||||
|
||||
Assert.assertEquals("None", attribute.getValue());
|
||||
Assert.assertEquals(SameSiteCookies.NONE, attribute);
|
||||
|
||||
Assert.assertNotEquals(SameSiteCookies.UNSET, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.LAX, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.STRICT, attribute);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLax() {
|
||||
SameSiteCookies attribute = SameSiteCookies.LAX;
|
||||
|
||||
Assert.assertEquals("Lax", attribute.getValue());
|
||||
Assert.assertEquals(SameSiteCookies.LAX, attribute);
|
||||
|
||||
Assert.assertNotEquals(SameSiteCookies.UNSET, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.NONE, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.STRICT, attribute);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrict() {
|
||||
SameSiteCookies attribute = SameSiteCookies.STRICT;
|
||||
|
||||
Assert.assertEquals("Strict", attribute.getValue());
|
||||
Assert.assertEquals(SameSiteCookies.STRICT, attribute);
|
||||
|
||||
Assert.assertNotEquals(SameSiteCookies.UNSET, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.NONE, attribute);
|
||||
Assert.assertNotEquals(SameSiteCookies.LAX, attribute);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToValidAttribute() {
|
||||
Assert.assertEquals(SameSiteCookies.fromString("unset"), SameSiteCookies.UNSET);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("Unset"), SameSiteCookies.UNSET);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("UNSET"), SameSiteCookies.UNSET);
|
||||
|
||||
Assert.assertEquals(SameSiteCookies.fromString("none"), SameSiteCookies.NONE);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("None"), SameSiteCookies.NONE);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("NONE"), SameSiteCookies.NONE);
|
||||
|
||||
Assert.assertEquals(SameSiteCookies.fromString("lax"), SameSiteCookies.LAX);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("Lax"), SameSiteCookies.LAX);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("LAX"), SameSiteCookies.LAX);
|
||||
|
||||
Assert.assertEquals(SameSiteCookies.fromString("strict"), SameSiteCookies.STRICT);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("Strict"), SameSiteCookies.STRICT);
|
||||
Assert.assertEquals(SameSiteCookies.fromString("STRICT"), SameSiteCookies.STRICT);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testToInvalidAttribute01() {
|
||||
SameSiteCookies.fromString("");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testToInvalidAttribute02() {
|
||||
SameSiteCookies.fromString(" ");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testToInvalidAttribute03() {
|
||||
SameSiteCookies.fromString("Strict1");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testToInvalidAttribute04() {
|
||||
SameSiteCookies.fromString("foo");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testToInvalidAttribute05() {
|
||||
SameSiteCookies.fromString("Lax ");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
|
||||
public class TesterCookiesPerformance {
|
||||
|
||||
@Test
|
||||
public void testPerformance01() throws Exception {
|
||||
final int cookieCount = 100;
|
||||
final int parsingLoops = 200000;
|
||||
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
|
||||
StringBuilder cookieHeader = new StringBuilder();
|
||||
// Create cookies
|
||||
for (int i = 0; i < cookieCount; i++) {
|
||||
cookieHeader.append("name");
|
||||
cookieHeader.append(i);
|
||||
cookieHeader.append('=');
|
||||
cookieHeader.append("value");
|
||||
cookieHeader.append(i);
|
||||
cookieHeader.append(';');
|
||||
}
|
||||
|
||||
byte[] cookieHeaderBytes = cookieHeader.toString().getBytes("UTF-8");
|
||||
|
||||
MessageBytes headerValue = mimeHeaders.addValue("Cookie");
|
||||
headerValue.setBytes(cookieHeaderBytes, 0, cookieHeaderBytes.length);
|
||||
ServerCookies serverCookies = new ServerCookies(4);
|
||||
|
||||
LegacyCookieProcessor originalCookieProcessor = new LegacyCookieProcessor();
|
||||
Rfc6265CookieProcessor rfc6265CookieProcessor = new Rfc6265CookieProcessor();
|
||||
|
||||
// warm up
|
||||
for (int i = 0; i < parsingLoops; i++) {
|
||||
originalCookieProcessor.parseCookieHeader(mimeHeaders, serverCookies);
|
||||
Assert.assertEquals(cookieCount, serverCookies.getCookieCount());
|
||||
serverCookies.recycle();
|
||||
}
|
||||
|
||||
long oldStart = System.nanoTime();
|
||||
for (int i = 0; i < parsingLoops; i++) {
|
||||
originalCookieProcessor.parseCookieHeader(mimeHeaders, serverCookies);
|
||||
Assert.assertEquals(cookieCount, serverCookies.getCookieCount());
|
||||
serverCookies.recycle();
|
||||
}
|
||||
long oldDuration = System.nanoTime() - oldStart;
|
||||
|
||||
long newStart = System.nanoTime();
|
||||
for (int i = 0; i < parsingLoops; i++) {
|
||||
rfc6265CookieProcessor.parseCookieHeader(mimeHeaders, serverCookies);
|
||||
Assert.assertEquals(cookieCount, serverCookies.getCookieCount());
|
||||
serverCookies.recycle();
|
||||
}
|
||||
long newDuration = System.nanoTime() - newStart;
|
||||
|
||||
System.out.println("Original duration: " + oldDuration);
|
||||
System.out.println("RFC6265 duration: " + newDuration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.buf.B2CConverter;
|
||||
|
||||
public class TesterParametersPerformance {
|
||||
|
||||
@Test
|
||||
public void testProcessParametersByteArrayIntInt() {
|
||||
LogManager.getLogManager().getLogger("").setLevel(Level.OFF);
|
||||
doTestProcessParametersMultiple("foo".getBytes());
|
||||
}
|
||||
|
||||
private void doTestProcessParametersMultiple(byte[] input) {
|
||||
System.out.println(doTestProcessParameters(input, 10000));
|
||||
System.out.println(doTestProcessParameters(input, 20000));
|
||||
System.out.println(doTestProcessParameters(input, 40000));
|
||||
System.out.println(doTestProcessParameters(input, 80000));
|
||||
System.out.println(doTestProcessParameters(input, 160000));
|
||||
System.out.println(doTestProcessParameters(input, 320000));
|
||||
System.out.println(doTestProcessParameters(input, 640000));
|
||||
System.out.println(doTestProcessParameters(input, 1280000));
|
||||
}
|
||||
|
||||
private long doTestProcessParameters(byte[] input, int size) {
|
||||
Assert.assertEquals(input.length, 3);
|
||||
|
||||
Parameters p = new Parameters();
|
||||
|
||||
byte[] params = createParams(input, size);
|
||||
//byte[] input = createParams(8);
|
||||
p.setCharset(StandardCharsets.ISO_8859_1);
|
||||
long start = System.nanoTime();
|
||||
p.processParameters(params, 0, params.length);
|
||||
return System.nanoTime() - start;
|
||||
}
|
||||
|
||||
private byte[] createParams(byte[] input, int len) {
|
||||
byte[] result = new byte[len * 4 - 1];
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
result[i * 4] = input[0];
|
||||
result[i * 4 + 1] = input[1];
|
||||
result[i * 4 + 2] = input[2];
|
||||
if (i < len -1) {
|
||||
result[i * 4 + 3] = 38;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateString() throws UnsupportedEncodingException {
|
||||
B2CConverter.getCharset("ISO-8859-1");
|
||||
doCreateStringMultiple("foo");
|
||||
}
|
||||
|
||||
private void doCreateStringMultiple(String input) {
|
||||
System.out.println(doCreateString(input, 10, true));
|
||||
System.out.println(doCreateString(input, 100, true));
|
||||
System.out.println(doCreateString(input, 1000, true));
|
||||
System.out.println(doCreateString(input, 10000, true));
|
||||
System.out.println(doCreateString(input, 100000, true));
|
||||
System.out.println(doCreateString(input, 1000000, true));
|
||||
System.out.println(doCreateString(input, 2000000, true));
|
||||
//System.out.println(doCreateString(input, 4000000, true));
|
||||
//System.out.println(doCreateString(input, 8000000, true));
|
||||
System.out.println(doCreateString(input, 10, false));
|
||||
System.out.println(doCreateString(input, 100, false));
|
||||
System.out.println(doCreateString(input, 1000, false));
|
||||
System.out.println(doCreateString(input, 10000, false));
|
||||
System.out.println(doCreateString(input, 100000, false));
|
||||
System.out.println(doCreateString(input, 1000000, false));
|
||||
System.out.println(doCreateString(input, 2000000, false));
|
||||
//System.out.println(doCreateString(input, 4000000, false));
|
||||
//System.out.println(doCreateString(input, 8000000, false));
|
||||
}
|
||||
|
||||
private long doCreateString(String input, int size,
|
||||
boolean defensiveCopyWorkAround) {
|
||||
int loops = 10000;
|
||||
byte[] inputBytes = input.getBytes();
|
||||
byte[] bytes = new byte[size];
|
||||
int inputLength = inputBytes.length;
|
||||
|
||||
System.arraycopy(inputBytes, 0, bytes, 0, inputLength);
|
||||
|
||||
String[] result = new String[loops];
|
||||
Charset charset = StandardCharsets.ISO_8859_1;
|
||||
|
||||
long start = System.nanoTime();
|
||||
for (int i = 0; i < loops; i++) {
|
||||
if (defensiveCopyWorkAround) {
|
||||
byte[] tmp = new byte[inputLength];
|
||||
System.arraycopy(bytes, 0, tmp, 0, inputLength);
|
||||
result[i] = new String(tmp, 0, inputLength, charset);
|
||||
} else {
|
||||
result[i] = new String(bytes, 0, inputLength, charset);
|
||||
}
|
||||
}
|
||||
|
||||
return System.nanoTime() - start;
|
||||
}
|
||||
}
|
||||
358
test/org/apache/tomcat/util/http/parser/TestAcceptLanguage.java
Normal file
358
test/org/apache/tomcat/util/http/parser/TestAcceptLanguage.java
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestAcceptLanguage {
|
||||
|
||||
private static final Locale L_EN = Locale.forLanguageTag("en");
|
||||
private static final Locale L_EN_GB = Locale.forLanguageTag("en-gb");
|
||||
private static final Locale L_FR = Locale.forLanguageTag("fr");
|
||||
private static final double Q1_000 = 1;
|
||||
private static final double Q0_500 = 0.5;
|
||||
private static final double Q0_050 = 0.05;
|
||||
|
||||
@Test
|
||||
public void testSingle01() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle02() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle03() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle04() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; "));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle05() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=1"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle06() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q=1"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle07() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q= 1"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle08() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q = 1"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle09() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q = 1 "));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle10() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q =\t1"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle11() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q =1\t"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle12() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb; q =\t1\t"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle13() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle14() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.50"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle15() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.500"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle16() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.5009"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle17() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;,"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testMalformed01() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;x=1,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed02() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=a,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed03() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.5a,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed04() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.05a,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed05() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.005a,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed06() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=0.00005a,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed07() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en,,"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed08() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader(",en,"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed09() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader(",,en"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed10() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en;q"));
|
||||
|
||||
Assert.assertEquals(0, actual.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed11() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=1a0"));
|
||||
|
||||
Assert.assertEquals(0, actual.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed12() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=1.a0"));
|
||||
|
||||
Assert.assertEquals(0, actual.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed13() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=1.0a0"));
|
||||
|
||||
Assert.assertEquals(0, actual.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed14() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=1.1"));
|
||||
|
||||
Assert.assertEquals(0, actual.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformed15() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en-gb;q=1a0,en-gb;q=0.5"));
|
||||
|
||||
Assert.assertEquals(1, actual.size());
|
||||
Assert.assertEquals(L_EN_GB, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultiple01() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en,fr"));
|
||||
|
||||
Assert.assertEquals(2, actual.size());
|
||||
Assert.assertEquals(L_EN, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(0).getQuality(), 0.0001);
|
||||
Assert.assertEquals(L_FR, actual.get(1).getLocale());
|
||||
Assert.assertEquals(Q1_000, actual.get(1).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiple02() throws Exception {
|
||||
List<AcceptLanguage> actual = AcceptLanguage.parse(new StringReader("en; q= 0.05,fr;q=0.5"));
|
||||
|
||||
Assert.assertEquals(2, actual.size());
|
||||
Assert.assertEquals(L_EN, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_050, actual.get(0).getQuality(), 0.0001);
|
||||
Assert.assertEquals(L_FR, actual.get(1).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(1).getQuality(), 0.0001);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void bug56848() throws Exception {
|
||||
List<AcceptLanguage> actual =
|
||||
AcceptLanguage.parse(new StringReader("zh-hant-CN;q=0.5,zh-hans-TW;q=0.05"));
|
||||
|
||||
Assert.assertEquals(2, actual.size());
|
||||
|
||||
Locale.Builder b = new Locale.Builder();
|
||||
b.setLanguage("zh").setRegion("CN").setScript("hant");
|
||||
Locale l1 = b.build();
|
||||
|
||||
b.clear().setLanguage("zh").setRegion("TW").setScript("hans");
|
||||
Locale l2 = b.build();
|
||||
|
||||
Assert.assertEquals(l1, actual.get(0).getLocale());
|
||||
Assert.assertEquals(Q0_500, actual.get(0).getQuality(), 0.0001);
|
||||
Assert.assertEquals(l2, actual.get(1).getLocale());
|
||||
Assert.assertEquals(Q0_050, actual.get(1).getQuality(), 0.0001);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestAuthorizationDigest {
|
||||
|
||||
@Test
|
||||
public void testBug54060a() throws Exception {
|
||||
String header = "Digest username=\"mthornton\", " +
|
||||
"realm=\"optrak.com\", " +
|
||||
"nonce=\"1351427243671:c1d6360150712149bae931a3ed7cb498\", " +
|
||||
"uri=\"/files/junk.txt\", " +
|
||||
"response=\"c5c2410bfc46753e83a8f007888b0d2e\", " +
|
||||
"opaque=\"DB85C1A73933A7EB586D10E4BF2924EF\", " +
|
||||
"qop=auth, " +
|
||||
"nc=00000001, " +
|
||||
"cnonce=\"9926cb3c334ede11\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("mthornton", result.get("username"));
|
||||
Assert.assertEquals("optrak.com", result.get("realm"));
|
||||
Assert.assertEquals("1351427243671:c1d6360150712149bae931a3ed7cb498",
|
||||
result.get("nonce"));
|
||||
Assert.assertEquals("/files/junk.txt", result.get("uri"));
|
||||
Assert.assertEquals("c5c2410bfc46753e83a8f007888b0d2e",
|
||||
result.get("response"));
|
||||
Assert.assertEquals("DB85C1A73933A7EB586D10E4BF2924EF",
|
||||
result.get("opaque"));
|
||||
Assert.assertEquals("auth", result.get("qop"));
|
||||
Assert.assertEquals("00000001", result.get("nc"));
|
||||
Assert.assertEquals("9926cb3c334ede11", result.get("cnonce"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug54060b() throws Exception {
|
||||
String header = "Digest username=\"mthornton\", " +
|
||||
"realm=\"optrak.com\", " +
|
||||
"nonce=\"1351427480964:a01c16fed5168d72a2b5267395a2022e\", " +
|
||||
"uri=\"/files\", " +
|
||||
"algorithm=MD5, " +
|
||||
"response=\"f310c44b87efc0bc0a7aab7096fd36b6\", " +
|
||||
"opaque=\"DB85C1A73933A7EB586D10E4BF2924EF\", " +
|
||||
"cnonce=\"MHg3ZjA3ZGMwMTUwMTA6NzI2OToxMzUxNDI3NDgw\", " +
|
||||
"nc=00000001, " +
|
||||
"qop=auth";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("mthornton", result.get("username"));
|
||||
Assert.assertEquals("optrak.com", result.get("realm"));
|
||||
Assert.assertEquals("1351427480964:a01c16fed5168d72a2b5267395a2022e",
|
||||
result.get("nonce"));
|
||||
Assert.assertEquals("/files", result.get("uri"));
|
||||
Assert.assertEquals("MD5", result.get("algorithm"));
|
||||
Assert.assertEquals("f310c44b87efc0bc0a7aab7096fd36b6",
|
||||
result.get("response"));
|
||||
Assert.assertEquals("DB85C1A73933A7EB586D10E4BF2924EF",
|
||||
result.get("opaque"));
|
||||
Assert.assertEquals("MHg3ZjA3ZGMwMTUwMTA6NzI2OToxMzUxNDI3NDgw",
|
||||
result.get("cnonce"));
|
||||
Assert.assertEquals("00000001", result.get("nc"));
|
||||
Assert.assertEquals("auth", result.get("qop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug54060c() throws Exception {
|
||||
String header = "Digest username=\"mthornton\", qop=auth";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("mthornton", result.get("username"));
|
||||
Assert.assertEquals("auth", result.get("qop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug54060d() throws Exception {
|
||||
String header = "Digest username=\"mthornton\"," +
|
||||
"qop=auth," +
|
||||
"cnonce=\"9926cb3c334ede11\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("mthornton", result.get("username"));
|
||||
Assert.assertEquals("auth", result.get("qop"));
|
||||
Assert.assertEquals("9926cb3c334ede11", result.get("cnonce"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndWithLhex() throws Exception {
|
||||
String header = "Digest nc=00000001";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("00000001", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndWithLhexReverse() throws Exception {
|
||||
String header = "Digest nc=10000000";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("10000000", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedLhex() throws Exception {
|
||||
String header = "Digest nc=\"09abcdef\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("09abcdef", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedLhexReverse() throws Exception {
|
||||
String header = "Digest nc=\"fedcba90\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("fedcba90", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLhex() throws Exception {
|
||||
String header = "Digest nc=09abcdef";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("09abcdef", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLhexReverse() throws Exception {
|
||||
String header = "Digest nc=fedcba90";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("fedcba90", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedLhexUppercase() throws Exception {
|
||||
String header = "Digest nc=\"00ABCDEF\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("00abcdef", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedLhexUppercaseReverse() throws Exception {
|
||||
String header = "Digest nc=\"FEDCBA00\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("fedcba00", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLhexUppercase() throws Exception {
|
||||
String header = "Digest nc=00ABCDEF";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("00abcdef", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLhexUppercaseReverse() throws Exception {
|
||||
String header = "Digest nc=FEDCBA00";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertEquals("fedcba00", result.get("nc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnclosedQuotedLhex() throws Exception {
|
||||
String header = "Digest nc=\"00000001";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyLhex() throws Exception {
|
||||
String header = "Digest nc=";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedEmptyLhex() throws Exception {
|
||||
String header = "Digest nc=\"\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnclosedQuotedString1() throws Exception {
|
||||
String header = "Digest username=\"test";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnclosedQuotedString2() throws Exception {
|
||||
String header = "Digest username=\"test\\";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonTokenDirective() throws Exception {
|
||||
String header = "Digest user{name=\"test\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenQop() throws Exception {
|
||||
String header = "Digest qop=auth";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertEquals("auth", result.get("qop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedTokenQop() throws Exception {
|
||||
String header = "Digest qop=\"auth\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertEquals("auth", result.get("qop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyQuotedTokenQop() throws Exception {
|
||||
String header = "Digest qop=\"\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonTokenQop01() throws Exception {
|
||||
String header = "Digest qop=au{th";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonTokenQop02() throws Exception {
|
||||
String header = "Digest qop=auth{";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedNonTokenQop() throws Exception {
|
||||
String header = "Digest qop=\"au{th\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotedNonTokenQop2() throws Exception {
|
||||
String header = "Digest qop=\"{auth\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnclosedQuotedTokenQop() throws Exception {
|
||||
String header = "Digest qop=\"auth";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInToken() throws Exception {
|
||||
String header = "Digest \u044f";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInToken2() throws Exception {
|
||||
String header = "Digest qop=\u044f";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInQuotedToken() throws Exception {
|
||||
String header = "Digest qop=\"\u044f\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInHex01() throws Exception {
|
||||
String header = "Digest nc=\u044f";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInHex02() throws Exception {
|
||||
String header = "Digest nc=aaa\u044f";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInHex03() throws Exception {
|
||||
String header = "Digest nc=\u044faaa";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCharacterInQuotedHex() throws Exception {
|
||||
String header = "Digest nc=\"\u044f\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseAuthParamA() throws Exception {
|
||||
// Test for HttpParser.readTokenOrQuotedString()
|
||||
// auth-param = token "=" ( token | quoted-string )
|
||||
String header = "Digest a=b";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertEquals("b", result.get("a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseAuthParamB() throws Exception {
|
||||
// Test for HttpParser.readTokenOrQuotedString()
|
||||
// auth-param = token "=" ( token | quoted-string )
|
||||
String header = "Digest a=\"b\"";
|
||||
|
||||
StringReader input = new StringReader(header);
|
||||
|
||||
Map<String,String> result = Authorization.parseAuthorizationDigest(input);
|
||||
Assert.assertEquals("b", result.get("a"));
|
||||
}
|
||||
}
|
||||
28
test/org/apache/tomcat/util/http/parser/TestHttpParser.java
Normal file
28
test/org/apache/tomcat/util/http/parser/TestHttpParser.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestHttpParser {
|
||||
|
||||
@Test
|
||||
public void testTokenDel() {
|
||||
Assert.assertFalse("DEL is not a token", HttpParser.isToken(127));
|
||||
}
|
||||
}
|
||||
255
test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
Normal file
255
test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class TestHttpParserHost {
|
||||
|
||||
private static final Class<? extends Exception> IAE = IllegalArgumentException.class;
|
||||
|
||||
@Parameter(0)
|
||||
public TestType testType;
|
||||
|
||||
@Parameter(1)
|
||||
public String input;
|
||||
|
||||
@Parameter(2)
|
||||
public Integer expectedResult;
|
||||
|
||||
@Parameter(3)
|
||||
public Class<? extends Exception> expectedException;
|
||||
|
||||
|
||||
@Parameters(name="{index}: host {1}")
|
||||
public static Collection<Object[]> inputs() {
|
||||
List<Object[]> result = new ArrayList<>();
|
||||
// IPv4 - valid
|
||||
result.add(new Object[] { TestType.IPv4, "127.0.0.1", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "127.0.0.1:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.0:8080", Integer.valueOf(7), null} );
|
||||
// IPv4 - invalid
|
||||
result.add(new Object[] { TestType.IPv4, ".0.0.0", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "0..0.0", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "0]", Integer.valueOf(-1), IAE} );
|
||||
// Domain Name - valid
|
||||
result.add(new Object[] { TestType.IPv4, "0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0:8080", Integer.valueOf(3), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0:8080", Integer.valueOf(5), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.00.0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.00.0.0:8080", Integer.valueOf(8), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "256.0.0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "256.0.0.0:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.256.0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.256.0.0:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.256.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.256.0:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.256", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.256:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.a.0.0", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.a.0.0:8080", Integer.valueOf(7), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "localhost", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "localhost:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "tomcat.apache.org", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "tomcat.apache.org:8080", Integer.valueOf(17), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.com:8080", Integer.valueOf(9), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.0.com:8080", Integer.valueOf(11), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.com:8080", Integer.valueOf(11), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1foo.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1foo.0.0.com:8080", Integer.valueOf(12), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo1.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo1.0.0.com:8080", Integer.valueOf(12), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1foo1.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1foo1.0.0.com:8080", Integer.valueOf(13), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1-foo.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1-foo.0.0.com:8080", Integer.valueOf(13), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1--foo.0.0.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "1--foo.0.0.com:8080", Integer.valueOf(14), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1com:8080", Integer.valueOf(12), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.com1", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.com1:8080", Integer.valueOf(12), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1com1", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1com1:8080", Integer.valueOf(13), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1-com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1-com:8080", Integer.valueOf(13), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1--com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.0.0.1--com:8080", Integer.valueOf(14), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "com:8080", Integer.valueOf(3), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0com:8080", Integer.valueOf(4), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0com:8080", Integer.valueOf(8), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.0com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.0com:8080", Integer.valueOf(10), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "123", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "123:8080", Integer.valueOf(3), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.bar.0com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.bar.0com:8080", Integer.valueOf(12), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.mydomain.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.mydomain.com:8080", Integer.valueOf(20), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.my-domain.com", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.my-domain.com:8080", Integer.valueOf(21), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.my-domain.c-om", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.my-domain.c-om:8080", Integer.valueOf(22), null} );
|
||||
// Domain Name with trailing dot - valid
|
||||
result.add(new Object[] { TestType.IPv4, "0.0.0.", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.mydomain.com.", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "myapp-t.mydomain.com.:8080", Integer.valueOf(21), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.bar.", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.bar.:8080", Integer.valueOf(8), null} );
|
||||
// Domain Name - invalid
|
||||
result.add(new Object[] { TestType.IPv4, ".", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, ".:8080", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, ".foo.bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "-foo.bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.bar-", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.bar-:8080", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "^foo.bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo-.bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "f*oo.bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo..bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.-bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.^bar", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv4, "foo.b*ar", Integer.valueOf(-1), IAE} );
|
||||
// IPv6 - valid
|
||||
result.add(new Object[] { TestType.IPv6, "[::1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::1]:8080", Integer.valueOf(5), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::1]:8080", Integer.valueOf(6), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A::A]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A::A]:8080", Integer.valueOf(6), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A:0::A]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A:0::A]:8080", Integer.valueOf(8), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:90AB:CDEF]",
|
||||
Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:90AB:CDEF]:8080",
|
||||
Integer.valueOf(41), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::5678:90AB:CDEF:1234:5678:90AB:CDEF]:8080",
|
||||
Integer.valueOf(38), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:90AB::]:8080",
|
||||
Integer.valueOf(38), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0:0:0:0:0:0:0:0]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0:0:0:0:0:0:0:0]:8080",
|
||||
Integer.valueOf(17), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::127.0.0.1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::127.0.0.1]:8080", Integer.valueOf(13), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127.0.0.1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127.0.0.1]:8080", Integer.valueOf(14), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A::127.0.0.1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A::127.0.0.1]:8080", Integer.valueOf(14), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A:0::127.0.0.1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[A:0::127.0.0.1]:8080", Integer.valueOf(16), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:127.0.0.1]",
|
||||
Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:127.0.0.1]:8080",
|
||||
Integer.valueOf(41), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::5678:90AB:CDEF:1234:5678:127.0.0.1]:8080",
|
||||
Integer.valueOf(38), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0:0:0:0:0:0:127.0.0.1]", Integer.valueOf(-1), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0:0:0:0:0:0:127.0.0.1]:8080",
|
||||
Integer.valueOf(23), null} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::1.2.3.4]", Integer.valueOf(-1), null} );
|
||||
// IPv6 - invalid
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:127.0.0.1]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:127.0.0.1",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0::0::0]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0:0:G:0:0:0:0:0]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[00000:0:0:0:0:0:0:0]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:90AB:]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1234:5678:90AB:CDEF:1234:5678:90AB:CDEF",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::127.00.0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0::0::127.0.0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[0:0:G:0:0:0:127.0.0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[00000:0:0:0:0:0:127.0.0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127..0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127..0.1]:8080", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127.a.0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127.a.0.1]:8080", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127.-.0.1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1::127.-.0.1]:8080", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[::1]'", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[:2222:3333:4444:5555:6666:7777:8888]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1111:::3333:4444:5555:6666:7777:8888]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "::1]", Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1111:2222:3333:4444:5555:6666:7777:8888:9999]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1111:2222:3333:4444:5555:6666:7777:1.2.3.4]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
result.add(new Object[] { TestType.IPv6, "[1111:2222:3333]",
|
||||
Integer.valueOf(-1), IAE} );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHost() {
|
||||
Class<? extends Exception> exceptionClass = null;
|
||||
int result = -1;
|
||||
try {
|
||||
StringReader sr = new StringReader(input);
|
||||
switch(testType) {
|
||||
case IPv4:
|
||||
result = HttpParser.readHostIPv4(sr, false);
|
||||
break;
|
||||
case IPv6:
|
||||
result = HttpParser.readHostIPv6(sr);
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
exceptionClass = e.getClass();
|
||||
}
|
||||
Assert.assertEquals(input, expectedResult.intValue(), result);
|
||||
if (expectedException == null) {
|
||||
Assert.assertNull(input, exceptionClass);
|
||||
} else {
|
||||
Assert.assertNotNull(exceptionClass);
|
||||
Assert.assertTrue(input, expectedException.isAssignableFrom(exceptionClass));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static enum TestType {
|
||||
IPv4,
|
||||
IPv6
|
||||
}
|
||||
}
|
||||
309
test/org/apache/tomcat/util/http/parser/TestMediaType.java
Normal file
309
test/org/apache/tomcat/util/http/parser/TestMediaType.java
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link HttpParser} focusing on media-type as defined in
|
||||
* section 3.7 of RFC 2616.
|
||||
*/
|
||||
public class TestMediaType {
|
||||
|
||||
// Include whitespace to ensure Parser handles it correctly (it should be
|
||||
// skipped).
|
||||
private static final String TYPE = " foo ";
|
||||
private static final String SUBTYPE = " bar ";
|
||||
private static final String TYPES = TYPE + "/" + SUBTYPE;
|
||||
|
||||
private static final Parameter PARAM_TOKEN =
|
||||
new Parameter("a", "b");
|
||||
private static final Parameter PARAM_QUOTED =
|
||||
new Parameter("x", "\"y\"");
|
||||
private static final Parameter PARAM_EMPTY_QUOTED =
|
||||
new Parameter("z", "\"\"");
|
||||
private static final Parameter PARAM_COMPLEX_QUOTED =
|
||||
new Parameter("w", "\"foo'bar,a=b;x=y\"");
|
||||
|
||||
private static final String CHARSET = "UTF-8";
|
||||
private static final String WS_CHARSET = " \tUTF-8";
|
||||
private static final String CHARSET_WS = "UTF-8 \t";
|
||||
// Since this is quoted, it should retain the space at the end
|
||||
private static final String CHARSET_QUOTED = "\"" + CHARSET_WS + "\"";
|
||||
private static final Parameter PARAM_CHARSET =
|
||||
new Parameter("charset", CHARSET);
|
||||
private static final Parameter PARAM_WS_CHARSET =
|
||||
new Parameter("charset", WS_CHARSET);
|
||||
private static final Parameter PARAM_CHARSET_WS =
|
||||
new Parameter("charset", CHARSET_WS);
|
||||
private static final Parameter PARAM_CHARSET_QUOTED =
|
||||
new Parameter("charset", CHARSET_QUOTED);
|
||||
|
||||
|
||||
private static final String[] LWS_VALUES = new String[] {
|
||||
"", " ", "\t", "\r", "\n", "\r\n", " \r", " \n", " \r\n",
|
||||
"\r ", "\n ", "\r\n ", " \r ", " \n ", " \r\n " };
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimple() throws IOException {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithToken() throws IOException {
|
||||
doTest(PARAM_TOKEN);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithQuotedString() throws IOException {
|
||||
doTest(PARAM_QUOTED);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithEmptyQuotedString() throws IOException {
|
||||
doTest(PARAM_EMPTY_QUOTED);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithComplexQuotedString() throws IOException {
|
||||
doTest(PARAM_COMPLEX_QUOTED);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithCharset() throws IOException {
|
||||
doTest(PARAM_CHARSET);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithCharsetWhitespaceBefore() throws IOException {
|
||||
doTest(PARAM_WS_CHARSET);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithCharsetWhitespaceAfter() throws IOException {
|
||||
doTest(PARAM_CHARSET_WS);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithCharsetQuoted() throws IOException {
|
||||
doTest(PARAM_CHARSET_QUOTED);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimpleWithAll() throws IOException {
|
||||
doTest(PARAM_COMPLEX_QUOTED, PARAM_EMPTY_QUOTED, PARAM_QUOTED,
|
||||
PARAM_TOKEN, PARAM_CHARSET);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCharset() throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(TYPES);
|
||||
sb.append(PARAM_CHARSET);
|
||||
sb.append(PARAM_TOKEN);
|
||||
|
||||
StringReader sr = new StringReader(sb.toString());
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
Assert.assertEquals("foo/bar; charset=UTF-8; a=b", m.toString());
|
||||
Assert.assertEquals(CHARSET, m.getCharset());
|
||||
Assert.assertEquals("foo/bar; a=b", m.toStringNoCharset());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCharsetQuoted() throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(TYPES);
|
||||
sb.append(PARAM_CHARSET_QUOTED);
|
||||
|
||||
StringReader sr = new StringReader(sb.toString());
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
Assert.assertEquals(CHARSET_WS, m.getCharset());
|
||||
Assert.assertEquals(TYPES.replaceAll(" ", ""),
|
||||
m.toStringNoCharset());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBug52811() throws IOException {
|
||||
String input = "multipart/related;boundary=1_4F50BD36_CDF8C28;" +
|
||||
"Start=\"<31671603.smil>\";" +
|
||||
"Type=\"application/smil;charset=UTF-8\"";
|
||||
|
||||
StringReader sr = new StringReader(input);
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
// Check the types
|
||||
Assert.assertEquals("multipart", m.getType());
|
||||
Assert.assertEquals("related", m.getSubtype());
|
||||
|
||||
// Check the parameters
|
||||
Assert.assertTrue(m.getParameterCount() == 3);
|
||||
|
||||
Assert.assertEquals("1_4F50BD36_CDF8C28", m.getParameterValue("boundary"));
|
||||
Assert.assertEquals("\"<31671603.smil>\"", m.getParameterValue("Start"));
|
||||
Assert.assertEquals("\"application/smil;charset=UTF-8\"",
|
||||
m.getParameterValue("Type"));
|
||||
|
||||
String expected = "multipart/related; boundary=1_4F50BD36_CDF8C28; " +
|
||||
"start=\"<31671603.smil>\"; " +
|
||||
"type=\"application/smil;charset=UTF-8\"";
|
||||
Assert.assertEquals(expected, m.toString());
|
||||
Assert.assertEquals(expected, m.toStringNoCharset());
|
||||
Assert.assertNull(m.getCharset());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBug53353() throws IOException {
|
||||
String input = "text/html; UTF-8;charset=UTF-8";
|
||||
|
||||
StringReader sr = new StringReader(input);
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
// Check the types
|
||||
Assert.assertEquals("text", m.getType());
|
||||
Assert.assertEquals("html", m.getSubtype());
|
||||
|
||||
// Check the parameters
|
||||
Assert.assertTrue(m.getParameterCount() == 2);
|
||||
|
||||
Assert.assertEquals("", m.getParameterValue("UTF-8"));
|
||||
Assert.assertEquals("UTF-8", m.getCharset());
|
||||
|
||||
// Note: Invalid input is filtered out
|
||||
Assert.assertEquals("text/html; charset=UTF-8", m.toString());
|
||||
Assert.assertEquals("UTF-8", m.getCharset());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBug55454() throws IOException {
|
||||
String input = "text/html;;charset=UTF-8";
|
||||
|
||||
StringReader sr = new StringReader(input);
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
Assert.assertEquals("text", m.getType());
|
||||
Assert.assertEquals("html", m.getSubtype());
|
||||
|
||||
Assert.assertTrue(m.getParameterCount() == 1);
|
||||
|
||||
Assert.assertEquals("UTF-8", m.getParameterValue("charset"));
|
||||
Assert.assertEquals("UTF-8", m.getCharset());
|
||||
|
||||
Assert.assertEquals("text/html; charset=UTF-8", m.toString());
|
||||
}
|
||||
|
||||
|
||||
private void doTest(Parameter... parameters) throws IOException {
|
||||
for (String lws : LWS_VALUES) {
|
||||
doTest(lws, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
private void doTest(String lws, Parameter... parameters)
|
||||
throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(TYPES);
|
||||
for (Parameter p : parameters) {
|
||||
sb.append(p.toString(lws));
|
||||
}
|
||||
|
||||
StringReader sr = new StringReader(sb.toString());
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
// Check all expected parameters are present
|
||||
Assert.assertTrue(m.getParameterCount() == parameters.length);
|
||||
|
||||
// Check the types
|
||||
Assert.assertEquals(TYPE.trim(), m.getType());
|
||||
Assert.assertEquals(SUBTYPE.trim(), m.getSubtype());
|
||||
|
||||
// Check the parameters
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
Assert.assertEquals(parameters[i].getValue().trim(),
|
||||
m.getParameterValue(parameters[i].getName().trim()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Parameter {
|
||||
private final String name;
|
||||
private final String value;
|
||||
|
||||
public Parameter(String name,String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString("");
|
||||
}
|
||||
|
||||
public String toString(String lws) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(lws);
|
||||
sb.append(";");
|
||||
sb.append(lws);
|
||||
sb.append(name);
|
||||
sb.append(lws);
|
||||
sb.append("=");
|
||||
sb.append(lws);
|
||||
sb.append(value);
|
||||
sb.append(lws);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCase() throws Exception {
|
||||
StringReader sr = new StringReader("type/sub-type;a=1;B=2");
|
||||
MediaType m = MediaType.parseMediaType(sr);
|
||||
|
||||
Assert.assertEquals("1", m.getParameterValue("A"));
|
||||
Assert.assertEquals("1", m.getParameterValue("a"));
|
||||
Assert.assertEquals("2", m.getParameterValue("B"));
|
||||
Assert.assertEquals("2", m.getParameterValue("b"));
|
||||
}
|
||||
}
|
||||
202
test/org/apache/tomcat/util/http/parser/TestTokenList.java
Normal file
202
test/org/apache/tomcat/util/http/parser/TestTokenList.java
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestTokenList {
|
||||
|
||||
@Test
|
||||
public void testAll() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("*");
|
||||
doTestVary("*", expected, true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingle() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("host");
|
||||
doTestVary("Host", expected, true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultiple() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("Host, Foo, Bar", expected, true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmptyString() throws IOException {
|
||||
Set<String> s = Collections.emptySet();
|
||||
doTestVary("", s, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingleInvalid() throws IOException {
|
||||
Set<String> s = Collections.emptySet();
|
||||
doTestVary("{{{", s, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleWithInvalidStart() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("{{{, Host, Foo, Bar", expected, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleWithInvalidMiddle() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("Host, {{{, Foo, Bar", expected, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleWithInvalidEnd() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("Host, Foo, Bar, {{{", expected, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleWithInvalidStart2() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("OK {{{, Host, Foo, Bar", expected, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleWithInvalidMiddle2() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("Host, OK {{{, Foo, Bar", expected, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleWithInvalidEnd2() throws IOException {
|
||||
Set<String> expected = new HashSet<>();
|
||||
expected.add("bar");
|
||||
expected.add("foo");
|
||||
expected.add("host");
|
||||
doTestVary("Host, Foo, Bar, OK {{{", expected, false);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void doTestVary(String input, Set<String> expectedTokens, boolean expectedResult) throws IOException {
|
||||
StringReader reader = new StringReader(input);
|
||||
Set<String> tokens = new HashSet<>();
|
||||
Vary.parseVary(reader, tokens);
|
||||
Assert.assertEquals(expectedTokens, tokens);
|
||||
|
||||
// Can't use reset(). Parser uses marks.
|
||||
reader = new StringReader(input);
|
||||
tokens.clear();
|
||||
boolean result = TokenList.parseTokenList(reader, tokens);
|
||||
Assert.assertEquals(expectedTokens, tokens);
|
||||
Assert.assertEquals(Boolean.valueOf(expectedResult), Boolean.valueOf(result));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleHeadersValidWithoutNull() throws IOException {
|
||||
doTestMultipleHeadersValid(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleHeadersValidWithNull() throws IOException {
|
||||
doTestMultipleHeadersValid(true);
|
||||
}
|
||||
|
||||
|
||||
private void doTestMultipleHeadersValid(boolean withNull) throws IOException {
|
||||
Set<String> expectedTokens = new HashSet<>();
|
||||
expectedTokens.add("bar");
|
||||
expectedTokens.add("foo");
|
||||
expectedTokens.add("foo2");
|
||||
|
||||
Set<String> inputs = new HashSet<>();
|
||||
inputs.add("foo");
|
||||
if (withNull) {
|
||||
inputs.add(null);
|
||||
}
|
||||
inputs.add("bar, foo2");
|
||||
|
||||
Set<String> tokens = new HashSet<>();
|
||||
|
||||
|
||||
boolean result = TokenList.parseTokenList(Collections.enumeration(inputs), tokens);
|
||||
Assert.assertEquals(expectedTokens, tokens);
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doTestMultipleHeadersInvalid() throws IOException {
|
||||
Set<String> expectedTokens = new HashSet<>();
|
||||
expectedTokens.add("bar");
|
||||
expectedTokens.add("bar2");
|
||||
expectedTokens.add("foo");
|
||||
expectedTokens.add("foo2");
|
||||
expectedTokens.add("foo3");
|
||||
|
||||
Set<String> inputs = new HashSet<>();
|
||||
inputs.add("foo");
|
||||
inputs.add("bar2, }}}, foo3");
|
||||
inputs.add("bar, foo2");
|
||||
|
||||
Set<String> tokens = new HashSet<>();
|
||||
|
||||
|
||||
boolean result = TokenList.parseTokenList(Collections.enumeration(inputs), tokens);
|
||||
Assert.assertEquals(expectedTokens, tokens);
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.http.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class TesterHostPerformance {
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> inputs() {
|
||||
List<Object[]> result = new ArrayList<>();
|
||||
result.add(new Object[] { "localhost" });
|
||||
result.add(new Object[] { "tomcat.apache.org" });
|
||||
result.add(new Object[] { "tomcat.apache.org." });
|
||||
result.add(new Object[] { "127.0.0.1" });
|
||||
result.add(new Object[] { "255.255.255.255" });
|
||||
result.add(new Object[] { "[::1]" });
|
||||
result.add(new Object[] { "[0123:4567:89AB:CDEF:0123:4567:89AB:CDEF]" });
|
||||
return result;
|
||||
}
|
||||
|
||||
@Parameter(0)
|
||||
public String hostname;
|
||||
|
||||
private static final int ITERATIONS = 100000000;
|
||||
|
||||
@Test
|
||||
public void testParseHost() throws Exception {
|
||||
long start = System.nanoTime();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
Host.parse(hostname);
|
||||
}
|
||||
long time = System.nanoTime() - start;
|
||||
|
||||
System.out.println("St " + hostname + ": " + ITERATIONS + " iterations in " + time + "ns");
|
||||
System.out.println("St " + hostname + ": " + ITERATIONS * 1000000000.0/time + " iterations per second");
|
||||
|
||||
MessageBytes mb = MessageBytes.newInstance();
|
||||
mb.setString(hostname);
|
||||
mb.toBytes();
|
||||
|
||||
start = System.nanoTime();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
Host.parse(mb);
|
||||
}
|
||||
time = System.nanoTime() - start;
|
||||
|
||||
System.out.println("MB " + hostname + ": " + ITERATIONS + " iterations in " + time + "ns");
|
||||
System.out.println("MB " + hostname + ": " + ITERATIONS * 1000000000.0/time + " iterations per second");
|
||||
}
|
||||
}
|
||||
141
test/org/apache/tomcat/util/net/IPv6UtilsTest.java
Normal file
141
test/org/apache/tomcat/util/net/IPv6UtilsTest.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* Mostly examples from RFC 5952
|
||||
*/
|
||||
public class IPv6UtilsTest {
|
||||
|
||||
@Test
|
||||
public void testMayBeIPv6Address() {
|
||||
Assert.assertFalse(IPv6Utils.mayBeIPv6Address(null));
|
||||
|
||||
Assert.assertTrue(IPv6Utils.mayBeIPv6Address("::1"));
|
||||
Assert.assertTrue(IPv6Utils.mayBeIPv6Address("::"));
|
||||
Assert.assertTrue(IPv6Utils.mayBeIPv6Address("2001:db8:0:0:1:0:0:1"));
|
||||
|
||||
Assert.assertFalse(IPv6Utils.mayBeIPv6Address(""));
|
||||
Assert.assertFalse(IPv6Utils.mayBeIPv6Address(":1"));
|
||||
Assert.assertFalse(IPv6Utils.mayBeIPv6Address("123.123.123.123"));
|
||||
Assert.assertFalse(IPv6Utils.mayBeIPv6Address("tomcat.eu.apache.org:443"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanonize() {
|
||||
Assert.assertNull(IPv6Utils.canonize(null));
|
||||
Assert.assertEquals("", IPv6Utils.canonize(""));
|
||||
|
||||
// IPv4-safe
|
||||
Assert.assertEquals("123.123.123.123", IPv6Utils.canonize("123.123.123.123"));
|
||||
Assert.assertEquals("123.1.2.23", IPv6Utils.canonize("123.1.2.23"));
|
||||
|
||||
// Introductory RFC 5952 examples
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0:0:1:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:0db8:0:0:1:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8::1:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8::0:1:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:0db8::1:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0:0:1::1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0000:0:1::1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:DB8:0:0:1::1"));
|
||||
|
||||
// Strip leading zeros (2.1)
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"));
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"));
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"));
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"));
|
||||
|
||||
// Zero compression (2.2)
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:0:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd::1"));
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:0:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:0:1"));
|
||||
|
||||
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8:0:0:0::1"));
|
||||
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8:0:0::1"));
|
||||
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8:0::1"));
|
||||
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8::1"));
|
||||
|
||||
Assert.assertEquals("2001:db8::aaaa:0:0:1", IPv6Utils.canonize("2001:db8::aaaa:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::aaaa:0:0:1", IPv6Utils.canonize("2001:db8:0:0:aaaa::1"));
|
||||
|
||||
// Uppercase or lowercase (2.3)
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"));
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA"));
|
||||
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa"));
|
||||
|
||||
// Some more zero compression for localhost addresses
|
||||
Assert.assertEquals("::1", IPv6Utils.canonize("0:0:0:0:0:0:0:1"));
|
||||
Assert.assertEquals("::1", IPv6Utils.canonize("0000:0:0:0:0:0:0:0001"));
|
||||
Assert.assertEquals("::1", IPv6Utils.canonize("00:00:0:0:00:00:0:01"));
|
||||
Assert.assertEquals("::1", IPv6Utils.canonize("::0001"));
|
||||
Assert.assertEquals("::1", IPv6Utils.canonize("::1"));
|
||||
|
||||
// IPv6 unspecified address
|
||||
Assert.assertEquals("::", IPv6Utils.canonize("0:0:0:0:0:0:0:0"));
|
||||
Assert.assertEquals("::", IPv6Utils.canonize("0000:0:0:0:0:0:0:0000"));
|
||||
Assert.assertEquals("::", IPv6Utils.canonize("00:00:0:0:00:00:0:00"));
|
||||
Assert.assertEquals("::", IPv6Utils.canonize("::0000"));
|
||||
Assert.assertEquals("::", IPv6Utils.canonize("::0"));
|
||||
Assert.assertEquals("::", IPv6Utils.canonize("::"));
|
||||
|
||||
// Leading zeros (4.1)
|
||||
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:0db8::0001"));
|
||||
|
||||
// Shorten as much as possible (4.2.1)
|
||||
Assert.assertEquals("2001:db8::2:1", IPv6Utils.canonize("2001:db8:0:0:0:0:2:1"));
|
||||
Assert.assertEquals("2001:db8::", IPv6Utils.canonize("2001:db8:0:0:0:0:0:0"));
|
||||
|
||||
// Handling One 16-Bit 0 Field (4.2.2)
|
||||
Assert.assertEquals("2001:db8:0:1:1:1:1:1", IPv6Utils.canonize("2001:db8:0:1:1:1:1:1"));
|
||||
Assert.assertEquals("2001:db8:0:1:1:1:1:1", IPv6Utils.canonize("2001:db8::1:1:1:1:1"));
|
||||
|
||||
// Choice in Placement of "::" (4.2.3)
|
||||
Assert.assertEquals("2001:0:0:1::1", IPv6Utils.canonize("2001:0:0:1:0:0:0:1"));
|
||||
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0:0:1:0:0:1"));
|
||||
|
||||
// IPv4 inside IPv6
|
||||
Assert.assertEquals("::ffff:192.0.2.1", IPv6Utils.canonize("::ffff:192.0.2.1"));
|
||||
Assert.assertEquals("::ffff:192.0.2.1", IPv6Utils.canonize("0:0:0:0:0:ffff:192.0.2.1"));
|
||||
Assert.assertEquals("::192.0.2.1", IPv6Utils.canonize("::192.0.2.1"));
|
||||
Assert.assertEquals("::192.0.2.1", IPv6Utils.canonize("0:0:0:0:0:0:192.0.2.1"));
|
||||
|
||||
// Zone ID
|
||||
Assert.assertEquals("fe80::f0f0:c0c0:1919:1234%4", IPv6Utils.canonize("fe80::f0f0:c0c0:1919:1234%4"));
|
||||
Assert.assertEquals("fe80::f0f0:c0c0:1919:1234%4", IPv6Utils.canonize("fe80:0:0:0:f0f0:c0c0:1919:1234%4"));
|
||||
|
||||
Assert.assertEquals("::%4", IPv6Utils.canonize("::%4"));
|
||||
Assert.assertEquals("::%4", IPv6Utils.canonize("::0%4"));
|
||||
Assert.assertEquals("::%4", IPv6Utils.canonize("0:0::0%4"));
|
||||
Assert.assertEquals("::%4", IPv6Utils.canonize("0:0:0:0:0:0:0:0%4"));
|
||||
|
||||
Assert.assertEquals("::1%4", IPv6Utils.canonize("::1%4"));
|
||||
Assert.assertEquals("::1%4", IPv6Utils.canonize("0:0::1%4"));
|
||||
Assert.assertEquals("::1%4", IPv6Utils.canonize("0:0:0:0:0:0:0:1%4"));
|
||||
|
||||
Assert.assertEquals("::1%eth0", IPv6Utils.canonize("::1%eth0"));
|
||||
Assert.assertEquals("::1%eth0", IPv6Utils.canonize("0:0::1%eth0"));
|
||||
Assert.assertEquals("::1%eth0", IPv6Utils.canonize("0:0:0:0:0:0:0:1%eth0"));
|
||||
|
||||
// Hostname safety
|
||||
Assert.assertEquals("www.apache.org", IPv6Utils.canonize("www.apache.org"));
|
||||
Assert.assertEquals("ipv6.google.com", IPv6Utils.canonize("ipv6.google.com"));
|
||||
}
|
||||
}
|
||||
182
test/org/apache/tomcat/util/net/TestClientCert.java
Normal file
182
test/org/apache/tomcat/util/net/TestClientCert.java
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* The keys and certificates used in this file are all available in svn and were
|
||||
* generated using a test CA the files for which are in the Tomcat PMC private
|
||||
* repository since not all of them are AL2 licensed.
|
||||
*/
|
||||
public class TestClientCert extends TomcatBaseTest {
|
||||
|
||||
@Test
|
||||
public void testClientCertGetWithoutPreemptive() throws Exception {
|
||||
doTestClientCertGet(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientCertGetWithPreemptive() throws Exception {
|
||||
doTestClientCertGet(true);
|
||||
}
|
||||
|
||||
private void doTestClientCertGet(boolean preemptive) throws Exception {
|
||||
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
|
||||
TesterSupport.isRenegotiationSupported(getTomcatInstance()));
|
||||
|
||||
if (preemptive) {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
// Only one context deployed
|
||||
Context c = (Context) tomcat.getHost().findChildren()[0];
|
||||
// Enable pre-emptive auth
|
||||
c.setPreemptiveAuthentication(true);
|
||||
}
|
||||
|
||||
getTomcatInstance().start();
|
||||
|
||||
// Unprotected resource
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() + "/unprotected");
|
||||
|
||||
int count = TesterSupport.getLastClientAuthRequestedIssuerCount();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
|
||||
", " + count + " requested Issuers, first one: " +
|
||||
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
|
||||
log.debug("Expected requested Issuer: " +
|
||||
(preemptive ? TesterSupport.getClientAuthExpectedIssuer() : "NONE"));
|
||||
}
|
||||
|
||||
if (preemptive) {
|
||||
Assert.assertTrue("Checking requested client issuer against " +
|
||||
TesterSupport.getClientAuthExpectedIssuer(),
|
||||
TesterSupport.checkLastClientAuthRequestedIssuers());
|
||||
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
|
||||
} else {
|
||||
Assert.assertEquals(0, count);
|
||||
Assert.assertEquals("OK", res.toString());
|
||||
}
|
||||
|
||||
// Protected resource
|
||||
res = getUrl("https://localhost:" + getPort() + "/protected");
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
count = TesterSupport.getLastClientAuthRequestedIssuerCount();
|
||||
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
|
||||
", " + count + " requested Issuers, first one: " +
|
||||
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
|
||||
log.debug("Expected requested Issuer: " + TesterSupport.getClientAuthExpectedIssuer());
|
||||
}
|
||||
Assert.assertTrue("Checking requested client issuer against " +
|
||||
TesterSupport.getClientAuthExpectedIssuer(),
|
||||
TesterSupport.checkLastClientAuthRequestedIssuers());
|
||||
|
||||
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientCertPostSmaller() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
int bodySize = tomcat.getConnector().getMaxSavePostSize() / 2;
|
||||
doTestClientCertPost(bodySize, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientCertPostSame() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
int bodySize = tomcat.getConnector().getMaxSavePostSize();
|
||||
doTestClientCertPost(bodySize, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientCertPostLarger() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
int bodySize = tomcat.getConnector().getMaxSavePostSize() * 2;
|
||||
doTestClientCertPost(bodySize, true);
|
||||
}
|
||||
|
||||
private void doTestClientCertPost(int bodySize, boolean expectProtectedFail)
|
||||
throws Exception {
|
||||
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
|
||||
TesterSupport.isRenegotiationSupported(getTomcatInstance()));
|
||||
|
||||
getTomcatInstance().start();
|
||||
|
||||
byte[] body = new byte[bodySize];
|
||||
Arrays.fill(body, TesterSupport.DATA);
|
||||
|
||||
// Unprotected resource
|
||||
ByteChunk res = postUrl(body, "https://localhost:" + getPort() + "/unprotected");
|
||||
|
||||
int count = TesterSupport.getLastClientAuthRequestedIssuerCount();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
|
||||
", " + count + " requested Issuers, first one: " +
|
||||
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
|
||||
log.debug("Expected requested Issuer: NONE");
|
||||
}
|
||||
|
||||
// Unprotected resource with no preemptive authentication
|
||||
Assert.assertEquals(0, count);
|
||||
// No authentication no need to buffer POST body during TLS handshake so
|
||||
// no possibility of hitting buffer limit
|
||||
Assert.assertEquals("OK-" + bodySize, res.toString());
|
||||
|
||||
// Protected resource
|
||||
res.recycle();
|
||||
int rc = postUrl(body, "https://localhost:" + getPort() + "/protected", res, null);
|
||||
|
||||
count = TesterSupport.getLastClientAuthRequestedIssuerCount();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
|
||||
", " + count + " requested Issuers, first one: " +
|
||||
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
|
||||
log.debug("Expected requested Issuer: " + TesterSupport.getClientAuthExpectedIssuer());
|
||||
}
|
||||
|
||||
if (expectProtectedFail) {
|
||||
Assert.assertEquals(401, rc);
|
||||
// POST body buffer fails so TLS handshake never happens
|
||||
Assert.assertEquals(0, count);
|
||||
} else {
|
||||
Assert.assertTrue("Checking requested client issuer against " +
|
||||
TesterSupport.getClientAuthExpectedIssuer(),
|
||||
TesterSupport.checkLastClientAuthRequestedIssuers());
|
||||
Assert.assertEquals("OK-" + bodySize, res.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
TesterSupport.configureClientCertContext(tomcat);
|
||||
|
||||
TesterSupport.configureClientSsl();
|
||||
}
|
||||
}
|
||||
84
test/org/apache/tomcat/util/net/TestClientCertTls13.java
Normal file
84
test/org/apache/tomcat/util/net/TestClientCertTls13.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
/**
|
||||
* The keys and certificates used in this file are all available in svn and were
|
||||
* generated using a test CA the files for which are in the Tomcat PMC private
|
||||
* repository since not all of them are AL2 licensed.
|
||||
*
|
||||
* The JSSE implementation of TLSv1.3 only supports authentication during the
|
||||
* initial handshake. This test requires TLSv1.3 on client and server so it is
|
||||
* skipped unless running on a Java version that supports TLSv1.3.
|
||||
*/
|
||||
public class TestClientCertTls13 extends TomcatBaseTest {
|
||||
|
||||
@Test
|
||||
public void testClientCertGet() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
tomcat.start();
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() + "/protected");
|
||||
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientCertPost() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
tomcat.start();
|
||||
|
||||
int size = 32 * 1024;
|
||||
|
||||
byte[] body = new byte[size];
|
||||
Arrays.fill(body, TesterSupport.DATA);
|
||||
|
||||
// Protected resource
|
||||
ByteChunk res = new ByteChunk();
|
||||
int rc = postUrl(body, "https://localhost:" + getPort() + "/protected", res, null);
|
||||
|
||||
Assert.assertEquals(200, rc);
|
||||
Assert.assertEquals("OK-" + size, res.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
Connector connector = tomcat.getConnector();
|
||||
Assume.assumeTrue(TesterSupport.isDefaultTLSProtocolForTesting13(connector));
|
||||
|
||||
TesterSupport.configureClientCertContext(tomcat);
|
||||
// Need to override some of the previous settings
|
||||
Assert.assertTrue(tomcat.getConnector().setProperty("sslEnabledProtocols", Constants.SSL_PROTO_TLSv1_3));
|
||||
// And add force authentication to occur on the initial handshake
|
||||
Assert.assertTrue(tomcat.getConnector().setProperty("clientAuth", "required"));
|
||||
|
||||
TesterSupport.configureClientSsl();
|
||||
}
|
||||
}
|
||||
184
test/org/apache/tomcat/util/net/TestCustomSsl.java
Normal file
184
test/org/apache/tomcat/util/net/TestCustomSsl.java
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.SocketException;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.coyote.ProtocolHandler;
|
||||
import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
|
||||
import org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl;
|
||||
import org.apache.tomcat.websocket.server.WsContextListener;
|
||||
|
||||
/**
|
||||
* The keys and certificates used in this file are all available in svn and were
|
||||
* generated using a test CA the files for which are in the Tomcat PMC private
|
||||
* repository since not all of them are AL2 licensed.
|
||||
*/
|
||||
public class TestCustomSsl extends TomcatBaseTest {
|
||||
|
||||
private static enum TrustType {
|
||||
ALL,
|
||||
CA,
|
||||
NONE
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomSslImplementation() throws Exception {
|
||||
|
||||
TesterSupport.configureClientSsl();
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
Connector connector = tomcat.getConnector();
|
||||
|
||||
Assume.assumeFalse("This test is only for JSSE based SSL connectors",
|
||||
connector.getProtocolHandlerClassName().contains("Apr"));
|
||||
|
||||
SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
|
||||
sslHostConfig.addCertificate(certificate);
|
||||
connector.addSslHostConfig(sslHostConfig);
|
||||
|
||||
Assert.assertTrue(connector.setProperty(
|
||||
"sslImplementationName", "org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl"));
|
||||
|
||||
// This setting will break ssl configuration unless the custom
|
||||
// implementation is used.
|
||||
sslHostConfig.setProtocols(TesterBug50640SslImpl.PROPERTY_VALUE);
|
||||
|
||||
sslHostConfig.setSslProtocol("tls");
|
||||
|
||||
File keystoreFile = new File(TesterSupport.LOCALHOST_RSA_JKS);
|
||||
certificate.setCertificateKeystoreFile(keystoreFile.getAbsolutePath());
|
||||
|
||||
connector.setSecure(true);
|
||||
Assert.assertTrue(connector.setProperty("SSLEnabled", "true"));
|
||||
|
||||
File appDir = new File(getBuildDirectory(), "webapps/examples");
|
||||
Context ctxt = tomcat.addWebapp(
|
||||
null, "/examples", appDir.getAbsolutePath());
|
||||
ctxt.addApplicationListener(WsContextListener.class.getName());
|
||||
|
||||
tomcat.start();
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() +
|
||||
"/examples/servlets/servlet/HelloWorldExample");
|
||||
Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomTrustManagerAll() throws Exception {
|
||||
doTestCustomTrustManager(TrustType.ALL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomTrustManagerCA() throws Exception {
|
||||
doTestCustomTrustManager(TrustType.CA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomTrustManagerNone() throws Exception {
|
||||
doTestCustomTrustManager(TrustType.NONE);
|
||||
}
|
||||
|
||||
private void doTestCustomTrustManager(TrustType trustType)
|
||||
throws Exception {
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
|
||||
TesterSupport.isRenegotiationSupported(tomcat));
|
||||
|
||||
TesterSupport.configureClientCertContext(tomcat);
|
||||
|
||||
Connector connector = tomcat.getConnector();
|
||||
|
||||
// Override the defaults
|
||||
ProtocolHandler handler = connector.getProtocolHandler();
|
||||
if (handler instanceof AbstractHttp11JsseProtocol) {
|
||||
connector.findSslHostConfigs()[0].setTruststoreFile(null);
|
||||
} else {
|
||||
// Unexpected
|
||||
Assert.fail("Unexpected handler type");
|
||||
}
|
||||
if (trustType.equals(TrustType.ALL)) {
|
||||
connector.findSslHostConfigs()[0].setTrustManagerClassName(
|
||||
"org.apache.tomcat.util.net.TesterSupport$TrustAllCerts");
|
||||
} else if (trustType.equals(TrustType.CA)) {
|
||||
connector.findSslHostConfigs()[0].setTrustManagerClassName(
|
||||
"org.apache.tomcat.util.net.TesterSupport$SequentialTrustManager");
|
||||
}
|
||||
|
||||
// Start Tomcat
|
||||
tomcat.start();
|
||||
|
||||
TesterSupport.configureClientSsl();
|
||||
|
||||
// Unprotected resource
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() + "/unprotected");
|
||||
Assert.assertEquals("OK", res.toString());
|
||||
|
||||
// Protected resource
|
||||
res.recycle();
|
||||
int rc = -1;
|
||||
try {
|
||||
rc = getUrl("https://localhost:" + getPort() + "/protected", res, null, null);
|
||||
} catch (SocketException se) {
|
||||
if (!trustType.equals(TrustType.NONE)) {
|
||||
Assert.fail(se.getMessage());
|
||||
se.printStackTrace();
|
||||
}
|
||||
} catch (SSLException he) {
|
||||
if (!trustType.equals(TrustType.NONE)) {
|
||||
Assert.fail(he.getMessage());
|
||||
he.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (trustType.equals(TrustType.CA)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
int count = TesterSupport.getLastClientAuthRequestedIssuerCount();
|
||||
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
|
||||
", " + count + " requested Issuers, first one: " +
|
||||
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
|
||||
log.debug("Expected requested Issuer: " + TesterSupport.getClientAuthExpectedIssuer());
|
||||
}
|
||||
Assert.assertTrue("Checking requested client issuer against " +
|
||||
TesterSupport.getClientAuthExpectedIssuer(),
|
||||
TesterSupport.checkLastClientAuthRequestedIssuers());
|
||||
}
|
||||
|
||||
if (trustType.equals(TrustType.NONE)) {
|
||||
Assert.assertTrue(rc != 200);
|
||||
Assert.assertEquals("", res.toString());
|
||||
} else {
|
||||
Assert.assertEquals(200, rc);
|
||||
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
112
test/org/apache/tomcat/util/net/TestSSLHostConfig.java
Normal file
112
test/org/apache/tomcat/util/net/TestSSLHostConfig.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.net.openssl.OpenSSLConf;
|
||||
import org.apache.tomcat.util.net.openssl.OpenSSLConfCmd;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
|
||||
public class TestSSLHostConfig {
|
||||
|
||||
@Test
|
||||
public void testCipher01() {
|
||||
SSLHostConfig hc = new SSLHostConfig();
|
||||
Cipher c = Cipher.TLS_RSA_WITH_NULL_MD5;
|
||||
|
||||
// Single JSSE name
|
||||
hc.setCiphers(c.getJsseNames().iterator().next());
|
||||
Assert.assertEquals(c.getOpenSSLAlias(), hc.getCiphers());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCipher02() {
|
||||
SSLHostConfig hc = new SSLHostConfig();
|
||||
Cipher c1 = Cipher.TLS_RSA_WITH_NULL_MD5;
|
||||
Cipher c2 = Cipher.TLS_RSA_WITH_NULL_SHA;
|
||||
|
||||
// Two JSSE names
|
||||
hc.setCiphers(c1.getJsseNames().iterator().next() + "," +
|
||||
c2.getJsseNames().iterator().next());
|
||||
Assert.assertEquals(c1.getOpenSSLAlias() + ":" + c2.getOpenSSLAlias(), hc.getCiphers());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCipher03() {
|
||||
SSLHostConfig hc = new SSLHostConfig();
|
||||
// Single OpenSSL alias
|
||||
hc.setCiphers("ALL");
|
||||
Assert.assertEquals("ALL", hc.getCiphers());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCipher04() {
|
||||
SSLHostConfig hc = new SSLHostConfig();
|
||||
Cipher c = Cipher.TLS_RSA_WITH_NULL_MD5;
|
||||
|
||||
// Single OpenSSLName name
|
||||
hc.setCiphers(c.getOpenSSLAlias());
|
||||
Assert.assertEquals(c.getOpenSSLAlias(), hc.getCiphers());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSerialization() throws IOException, ClassNotFoundException {
|
||||
// Dummy OpenSSL command name/value pair
|
||||
String name = "foo";
|
||||
String value = "bar";
|
||||
|
||||
// Set up the object
|
||||
SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
OpenSSLConf openSSLConf = new OpenSSLConf();
|
||||
OpenSSLConfCmd openSSLConfCmd = new OpenSSLConfCmd();
|
||||
openSSLConfCmd.setName(name);
|
||||
openSSLConfCmd.setValue(value);
|
||||
openSSLConf.addCmd(openSSLConfCmd);
|
||||
sslHostConfig.setOpenSslConf(openSSLConf);
|
||||
|
||||
// Serialize
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(sslHostConfig);
|
||||
oos.close();
|
||||
|
||||
// Deserialize
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
SSLHostConfig output = (SSLHostConfig) ois.readObject();
|
||||
|
||||
// Check values
|
||||
List<OpenSSLConfCmd> commands = output.getOpenSslConf().getCommands();
|
||||
Assert.assertEquals(1, commands.size());
|
||||
OpenSSLConfCmd command = commands.get(0);
|
||||
Assert.assertEquals(name, command.getName());
|
||||
Assert.assertEquals(value, command.getValue());
|
||||
}
|
||||
}
|
||||
349
test/org/apache/tomcat/util/net/TestSSLHostConfigCompat.java
Normal file
349
test/org/apache/tomcat/util/net/TestSSLHostConfigCompat.java
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.core.AprLifecycleListener;
|
||||
import org.apache.catalina.core.StandardServer;
|
||||
import org.apache.catalina.startup.TesterServlet;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate.StoreType;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
|
||||
import org.apache.tomcat.util.net.TesterSupport.ClientSSLSocketFactory;
|
||||
|
||||
/*
|
||||
* Tests compatibility of JSSE and OpenSSL settings.
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class TestSSLHostConfigCompat extends TomcatBaseTest {
|
||||
|
||||
@Parameterized.Parameters(name = "{0}-{3}")
|
||||
public static Collection<Object[]> parameters() {
|
||||
List<Object[]> parameterSets = new ArrayList<>();
|
||||
|
||||
for (StoreType storeType : new StoreType[] { StoreType.KEYSTORE, StoreType.PEM } ) {
|
||||
parameterSets.add(new Object[] {"NIO-JSSE", "org.apache.coyote.http11.Http11NioProtocol",
|
||||
"org.apache.tomcat.util.net.jsse.JSSEImplementation", storeType});
|
||||
|
||||
parameterSets.add(new Object[] {"NIO-OpenSSL", "org.apache.coyote.http11.Http11NioProtocol",
|
||||
"org.apache.tomcat.util.net.openssl.OpenSSLImplementation", storeType});
|
||||
|
||||
parameterSets.add(new Object[] { "APR/Native", "org.apache.coyote.http11.Http11AprProtocol",
|
||||
"org.apache.tomcat.util.net.openssl.OpenSSLImplementation", storeType});
|
||||
}
|
||||
|
||||
return parameterSets;
|
||||
}
|
||||
|
||||
@Parameter(0)
|
||||
public String connectorName;
|
||||
|
||||
@Parameter(1)
|
||||
public String protocolName;
|
||||
|
||||
@Parameter(2)
|
||||
public String sslImplementationName;
|
||||
|
||||
@Parameter(3)
|
||||
public StoreType storeType;
|
||||
|
||||
private SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostEC() throws Exception {
|
||||
configureHostEC();
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostRSA() throws Exception {
|
||||
configureHostRSA();
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostRSAandECwithDefaultClient() throws Exception {
|
||||
configureHostRSA();
|
||||
configureHostEC();
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test and the next just swap the order in which the server certs are
|
||||
* configured to ensure correct operation isn't dependent on order.
|
||||
*/
|
||||
@Test
|
||||
public void testHostRSAandECwithRSAClient() throws Exception {
|
||||
configureHostRSA();
|
||||
configureHostEC();
|
||||
|
||||
// Configure cipher suite that requires an RSA certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test and the previous just swap the order in which the server certs
|
||||
* are configured to ensure correct operation isn't dependent on order.
|
||||
*/
|
||||
@Test
|
||||
public void testHostECandRSAwithRSAClient() throws Exception {
|
||||
configureHostEC();
|
||||
configureHostRSA();
|
||||
|
||||
// Configure cipher suite that requires an RSA certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test and the next just swap the order in which the server certs are
|
||||
* configured to ensure correct operation isn't dependent on order.
|
||||
*/
|
||||
@Test
|
||||
public void testHostRSAandECwithECClient() throws Exception {
|
||||
configureHostRSA();
|
||||
configureHostEC();
|
||||
|
||||
// Configure cipher suite that requires an EC certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test and the previous just swap the order in which the server certs
|
||||
* are configured to ensure correct operation isn't dependent on order.
|
||||
*/
|
||||
@Test
|
||||
public void testHostECandRSAwithECClient() throws Exception {
|
||||
configureHostEC();
|
||||
configureHostRSA();
|
||||
|
||||
// Configure cipher suite that requires an EC certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostRSAwithRSAClient() throws Exception {
|
||||
configureHostRSA();
|
||||
|
||||
// Configure cipher suite that requires an RSA certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=javax.net.ssl.SSLHandshakeException.class)
|
||||
public void testHostRSAwithECClient() throws Exception {
|
||||
configureHostRSA();
|
||||
|
||||
// Configure cipher suite that requires an EC certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostRSAwithRSAandECClient() throws Exception {
|
||||
configureHostRSA();
|
||||
|
||||
// Configure cipher suite that requires an EC certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=javax.net.ssl.SSLHandshakeException.class)
|
||||
public void testHostECwithRSAClient() throws Exception {
|
||||
configureHostEC();
|
||||
|
||||
// Configure cipher suite that requires an RSA certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostECwithECClient() throws Exception {
|
||||
configureHostEC();
|
||||
|
||||
// Configure cipher suite that requires an EC certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHostECwithRSAandECClient() throws Exception {
|
||||
configureHostEC();
|
||||
|
||||
// Configure cipher suite that requires an RSA certificate on the server
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
|
||||
clientSSLSocketFactory.setCipher(new String[] {
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
|
||||
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
|
||||
private void configureHostRSA() {
|
||||
switch (storeType) {
|
||||
case KEYSTORE: {
|
||||
SSLHostConfigCertificate sslHostConfigCertificateRsa = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
|
||||
sslHostConfigCertificateRsa.setCertificateKeystoreFile(getPath(TesterSupport.LOCALHOST_RSA_JKS));
|
||||
sslHostConfig.addCertificate(sslHostConfigCertificateRsa);
|
||||
break;
|
||||
}
|
||||
case PEM: {
|
||||
SSLHostConfigCertificate sslHostConfigCertificateRsa = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
|
||||
sslHostConfigCertificateRsa.setCertificateFile(getPath(TesterSupport.LOCALHOST_RSA_CERT_PEM));
|
||||
sslHostConfigCertificateRsa.setCertificateKeyFile(getPath(TesterSupport.LOCALHOST_RSA_KEY_PEM));
|
||||
sslHostConfig.addCertificate(sslHostConfigCertificateRsa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void configureHostEC() {
|
||||
switch (storeType) {
|
||||
case KEYSTORE: {
|
||||
SSLHostConfigCertificate sslHostConfigCertificateEc = new SSLHostConfigCertificate(sslHostConfig, Type.EC);
|
||||
sslHostConfigCertificateEc.setCertificateKeystoreFile(getPath(TesterSupport.LOCALHOST_EC_JKS));
|
||||
sslHostConfig.addCertificate(sslHostConfigCertificateEc);
|
||||
break;
|
||||
}
|
||||
case PEM: {
|
||||
SSLHostConfigCertificate sslHostConfigCertificateEc = new SSLHostConfigCertificate(sslHostConfig, Type.EC);
|
||||
sslHostConfigCertificateEc.setCertificateFile(getPath(TesterSupport.LOCALHOST_EC_CERT_PEM));
|
||||
sslHostConfigCertificateEc.setCertificateKeyFile(getPath(TesterSupport.LOCALHOST_EC_KEY_PEM));
|
||||
sslHostConfig.addCertificate(sslHostConfigCertificateEc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doTest() throws Exception {
|
||||
// Use the default client TLS config
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
|
||||
private void doTest(boolean configureClientSsl) throws Exception {
|
||||
if (configureClientSsl) {
|
||||
TesterSupport.configureClientSsl();
|
||||
}
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
tomcat.start();
|
||||
|
||||
// Check a request can be made
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() + "/");
|
||||
Assert.assertEquals("OK", res.toString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getProtocol() {
|
||||
return protocolName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
AprLifecycleListener listener = new AprLifecycleListener();
|
||||
Assume.assumeTrue(AprLifecycleListener.isAprAvailable());
|
||||
Assume.assumeTrue(JreCompat.isJre8Available());
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
Connector connector = tomcat.getConnector();
|
||||
|
||||
connector.setPort(0);
|
||||
connector.setScheme("https");
|
||||
connector.setSecure(true);
|
||||
Assert.assertTrue(connector.setProperty("SSLEnabled", "true"));
|
||||
if (!connector.getProtocolHandlerClassName().contains("Apr")) {
|
||||
// Skip this for APR. It is not supported.
|
||||
Assert.assertTrue(connector.setProperty("sslImplementationName", sslImplementationName));
|
||||
}
|
||||
sslHostConfig.setProtocols("TLSv1.2");
|
||||
connector.addSslHostConfig(sslHostConfig);
|
||||
|
||||
StandardServer server = (StandardServer) tomcat.getServer();
|
||||
server.addLifecycleListener(listener);
|
||||
|
||||
// Simple webapp
|
||||
Context ctxt = tomcat.addContext("", null);
|
||||
Tomcat.addServlet(ctxt, "TesterServlet", new TesterServlet());
|
||||
ctxt.addServletMappingDecoded("/*", "TesterServlet");
|
||||
}
|
||||
|
||||
|
||||
private static String getPath(String relativePath) {
|
||||
File f = new File(relativePath);
|
||||
return f.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
|
||||
import org.apache.tomcat.websocket.server.WsContextListener;
|
||||
|
||||
public class TestSSLHostConfigIntegration extends TomcatBaseTest {
|
||||
|
||||
@Test
|
||||
public void testSslHostConfigIsSerializable() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
File appDir = new File(getBuildDirectory(), "webapps/examples");
|
||||
org.apache.catalina.Context ctxt = tomcat.addWebapp(
|
||||
null, "/examples", appDir.getAbsolutePath());
|
||||
ctxt.addApplicationListener(WsContextListener.class.getName());
|
||||
|
||||
TesterSupport.initSsl(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
SSLHostConfig[] sslHostConfigs =
|
||||
tomcat.getConnector().getProtocolHandler().findSslHostConfigs();
|
||||
|
||||
boolean written = false;
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
for (SSLHostConfig sslHostConfig : sslHostConfigs) {
|
||||
oos.writeObject(sslHostConfig);
|
||||
written = true;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertTrue(written);
|
||||
}
|
||||
}
|
||||
198
test/org/apache/tomcat/util/net/TestSsl.java
Normal file
198
test/org/apache/tomcat/util/net/TestSsl.java
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import javax.net.ssl.HandshakeCompletedEvent;
|
||||
import javax.net.ssl.HandshakeCompletedListener;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Wrapper;
|
||||
import org.apache.catalina.startup.TesterServlet;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.apache.tomcat.websocket.server.WsContextListener;
|
||||
|
||||
/**
|
||||
* The keys and certificates used in this file are all available in svn and were
|
||||
* generated using a test CA the files for which are in the Tomcat PMC private
|
||||
* repository since not all of them are AL2 licensed.
|
||||
*/
|
||||
public class TestSsl extends TomcatBaseTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleSsl() throws Exception {
|
||||
TesterSupport.configureClientSsl();
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
File appDir = new File(getBuildDirectory(), "webapps/examples");
|
||||
org.apache.catalina.Context ctxt = tomcat.addWebapp(
|
||||
null, "/examples", appDir.getAbsolutePath());
|
||||
ctxt.addApplicationListener(WsContextListener.class.getName());
|
||||
|
||||
TesterSupport.initSsl(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() +
|
||||
"/examples/servlets/servlet/HelloWorldExample");
|
||||
Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0);
|
||||
Assert.assertTrue("Checking no client issuer has been requested",
|
||||
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyPass() throws Exception {
|
||||
TesterSupport.configureClientSsl();
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
File appDir = new File(getBuildDirectory(), "webapps/examples");
|
||||
org.apache.catalina.Context ctxt = tomcat.addWebapp(
|
||||
null, "/examples", appDir.getAbsolutePath());
|
||||
ctxt.addApplicationListener(WsContextListener.class.getName());
|
||||
|
||||
TesterSupport.initSsl(tomcat, TesterSupport.LOCALHOST_KEYPASS_JKS,
|
||||
TesterSupport.JKS_PASS, TesterSupport.JKS_KEY_PASS);
|
||||
|
||||
tomcat.start();
|
||||
ByteChunk res = getUrl("https://localhost:" + getPort() +
|
||||
"/examples/servlets/servlet/HelloWorldExample");
|
||||
Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0);
|
||||
Assert.assertTrue("Checking no client issuer has been requested",
|
||||
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRenegotiateWorks() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
|
||||
TesterSupport.isClientRenegotiationSupported(getTomcatInstance()));
|
||||
|
||||
Context root = tomcat.addContext("", TEMP_DIR);
|
||||
Wrapper w =
|
||||
Tomcat.addServlet(root, "tester", new TesterServlet());
|
||||
w.setAsyncSupported(true);
|
||||
root.addServletMappingDecoded("/", "tester");
|
||||
|
||||
TesterSupport.initSsl(tomcat);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
SSLContext sslCtx;
|
||||
if (TesterSupport.isDefaultTLSProtocolForTesting13(tomcat.getConnector())) {
|
||||
// Force TLS 1.2 if TLS 1.3 is available as JSSE's TLS 1.3
|
||||
// implementation doesn't support Post Handshake Authentication
|
||||
// which is required for this test to pass.
|
||||
sslCtx = SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_2);
|
||||
} else {
|
||||
sslCtx = SSLContext.getInstance(Constants.SSL_PROTO_TLS);
|
||||
}
|
||||
sslCtx.init(null, TesterSupport.getTrustManagers(), null);
|
||||
SSLSocketFactory socketFactory = sslCtx.getSocketFactory();
|
||||
SSLSocket socket = (SSLSocket) socketFactory.createSocket("localhost",
|
||||
getPort());
|
||||
|
||||
OutputStream os = socket.getOutputStream();
|
||||
InputStream is = socket.getInputStream();
|
||||
Reader r = new InputStreamReader(is);
|
||||
|
||||
doRequest(os, r);
|
||||
Assert.assertTrue("Checking no client issuer has been requested",
|
||||
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
|
||||
|
||||
TesterHandshakeListener listener = new TesterHandshakeListener();
|
||||
socket.addHandshakeCompletedListener(listener);
|
||||
|
||||
socket.startHandshake();
|
||||
|
||||
doRequest(os, r);
|
||||
// Handshake complete appears to be called asynchronously
|
||||
int wait = 0;
|
||||
while (wait < 5000 && !listener.isComplete()) {
|
||||
wait += 50;
|
||||
Thread.sleep(50);
|
||||
}
|
||||
Assert.assertTrue("Checking no client issuer has been requested",
|
||||
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
|
||||
Assert.assertTrue(listener.isComplete());
|
||||
System.out.println("Renegotiation completed after " + wait + " ms");
|
||||
}
|
||||
|
||||
private void doRequest(OutputStream os, Reader r) throws IOException {
|
||||
char[] expectedResponseLine = "HTTP/1.1 200 \r\n".toCharArray();
|
||||
|
||||
os.write("GET /tester HTTP/1.1\r\n".getBytes());
|
||||
os.write("Host: localhost\r\n".getBytes());
|
||||
os.write("Connection: Keep-Alive\r\n\r\n".getBytes());
|
||||
os.flush();
|
||||
|
||||
// First check we get the expected response line
|
||||
for (char c : expectedResponseLine) {
|
||||
int read = r.read();
|
||||
Assert.assertEquals(c, read);
|
||||
}
|
||||
|
||||
// Skip to the end of the headers
|
||||
char[] endOfHeaders ="\r\n\r\n".toCharArray();
|
||||
int found = 0;
|
||||
while (found != endOfHeaders.length) {
|
||||
if (r.read() == endOfHeaders[found]) {
|
||||
found++;
|
||||
} else {
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the body
|
||||
char[] expectedBody = "OK".toCharArray();
|
||||
for (char c : expectedBody) {
|
||||
int read = r.read();
|
||||
Assert.assertEquals(c, read);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TesterHandshakeListener implements HandshakeCompletedListener {
|
||||
|
||||
private volatile boolean complete = false;
|
||||
|
||||
@Override
|
||||
public void handshakeCompleted(HandshakeCompletedEvent event) {
|
||||
complete = true;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult;
|
||||
|
||||
public class TestTLSClientHelloExtractor {
|
||||
|
||||
@Test
|
||||
public void testInputNeedRead01() throws IOException {
|
||||
ByteBuffer testInput = ByteBuffer.allocate(1024);
|
||||
doTestInputNeedRead(testInput);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=IOException.class)
|
||||
public void testInputMalformed01() throws IOException {
|
||||
ByteBuffer testInput = ByteBuffer.allocate(1024);
|
||||
|
||||
// TLS handshake
|
||||
testInput.put((byte) 22);
|
||||
// TLS 1.0
|
||||
testInput.put((byte) 3);
|
||||
testInput.put((byte) 1);
|
||||
// Record length 0 (correct, but not legal)
|
||||
testInput.put((byte) 0);
|
||||
testInput.put((byte) 0);
|
||||
|
||||
doTestInputNeedRead(testInput);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=IOException.class)
|
||||
public void testInputMalformed02() throws IOException {
|
||||
ByteBuffer testInput = ByteBuffer.allocate(1024);
|
||||
|
||||
// TLS handshake
|
||||
testInput.put((byte) 22);
|
||||
// TLS 1.0
|
||||
testInput.put((byte) 3);
|
||||
testInput.put((byte) 1);
|
||||
// Record length 4
|
||||
testInput.put((byte) 0);
|
||||
testInput.put((byte) 4);
|
||||
// Type 1 (client hello)
|
||||
testInput.put((byte) 1);
|
||||
// Client hello size 0 (correct, but not legal)
|
||||
testInput.put((byte) 0);
|
||||
testInput.put((byte) 0);
|
||||
testInput.put((byte) 0);
|
||||
|
||||
doTestInputNeedRead(testInput);
|
||||
}
|
||||
|
||||
|
||||
public void doTestInputMalformed(ByteBuffer input) throws IOException {
|
||||
TLSClientHelloExtractor extractor = new TLSClientHelloExtractor(input);
|
||||
// Expect this to fail
|
||||
extractor.getResult();
|
||||
}
|
||||
|
||||
|
||||
public void doTestInputNeedRead(ByteBuffer input) throws IOException {
|
||||
TLSClientHelloExtractor extractor = new TLSClientHelloExtractor(input);
|
||||
// Expect this to fail
|
||||
ExtractorResult result = extractor.getResult();
|
||||
Assert.assertEquals(ExtractorResult.NEED_READ, result);
|
||||
}
|
||||
}
|
||||
198
test/org/apache/tomcat/util/net/TestXxxEndpoint.java
Normal file
198
test/org/apache/tomcat/util/net/TestXxxEndpoint.java
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.jni.Address;
|
||||
import org.apache.tomcat.jni.Error;
|
||||
import org.apache.tomcat.jni.Library;
|
||||
import org.apache.tomcat.jni.OS;
|
||||
import org.apache.tomcat.jni.Pool;
|
||||
import org.apache.tomcat.jni.Socket;
|
||||
|
||||
/**
|
||||
* Test case for the Endpoint implementations. The testing framework will ensure
|
||||
* that each implementation is tested.
|
||||
*/
|
||||
public class TestXxxEndpoint extends TomcatBaseTest {
|
||||
|
||||
private long createAprPool() {
|
||||
|
||||
// Create the pool for the server socket
|
||||
try {
|
||||
return Pool.create(0);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
log.error("Could not create socket pool", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private long createAprSocket(int port, long pool)
|
||||
throws Exception {
|
||||
/**
|
||||
* Server socket "pointer".
|
||||
*/
|
||||
long serverSock = 0;
|
||||
|
||||
String address = InetAddress.getByName("localhost").getHostAddress();
|
||||
|
||||
// Create the APR address that will be bound
|
||||
int family = Socket.APR_INET;
|
||||
if (Library.APR_HAVE_IPV6) {
|
||||
if (!OS.IS_BSD && !OS.IS_WIN32 && !OS.IS_WIN64)
|
||||
family = Socket.APR_UNSPEC;
|
||||
}
|
||||
|
||||
long inetAddress = 0;
|
||||
try {
|
||||
inetAddress = Address.info(address, family,
|
||||
port, 0, pool);
|
||||
// Create the APR server socket
|
||||
serverSock = Socket.create(Address.getInfo(inetAddress).family,
|
||||
Socket.SOCK_STREAM,
|
||||
Socket.APR_PROTO_TCP, pool);
|
||||
} catch (Exception ex) {
|
||||
log.error("Could not create socket for address '" + address + "'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (OS.IS_UNIX) {
|
||||
Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
|
||||
}
|
||||
// Deal with the firewalls that tend to drop the inactive sockets
|
||||
Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1);
|
||||
// Bind the server socket
|
||||
int ret = Socket.bind(serverSock, inetAddress);
|
||||
if (ret != 0) {
|
||||
log.error("Could not bind: " + Error.strerror(ret));
|
||||
throw (new Exception(Error.strerror(ret)));
|
||||
}
|
||||
return serverSock;
|
||||
}
|
||||
|
||||
private void destroyAprSocket(long serverSock, long pool) {
|
||||
if (serverSock != 0) {
|
||||
Socket.shutdown(serverSock, Socket.APR_SHUTDOWN_READWRITE);
|
||||
Socket.close(serverSock);
|
||||
Socket.destroy(serverSock);
|
||||
}
|
||||
|
||||
if (pool != 0) {
|
||||
Pool.destroy(pool);
|
||||
pool = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartStopBindOnInit() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
File appDir = new File(getBuildDirectory(), "webapps/examples");
|
||||
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
|
||||
|
||||
tomcat.start();
|
||||
|
||||
int port = getPort();
|
||||
|
||||
tomcat.getConnector().stop();
|
||||
Exception e = null;
|
||||
ServerSocket s = null;
|
||||
long pool = 0;
|
||||
long nativeSocket = 0;
|
||||
boolean isApr = tomcat.getConnector().getProtocolHandlerClassName().contains("Apr");
|
||||
try {
|
||||
// This should throw an Exception
|
||||
if (isApr) {
|
||||
pool = createAprPool();
|
||||
Assert.assertTrue(pool != 0);
|
||||
nativeSocket = createAprSocket(port, pool);
|
||||
Assert.assertTrue(nativeSocket != 0);
|
||||
} else {
|
||||
s = new ServerSocket(port, 100,
|
||||
InetAddress.getByName("localhost"));
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
e = e1;
|
||||
} finally {
|
||||
try {
|
||||
if (isApr) {
|
||||
destroyAprSocket(nativeSocket, pool);
|
||||
} else if (s != null) {
|
||||
s.close();
|
||||
}
|
||||
} catch (Exception e2) { /* Ignore */ }
|
||||
}
|
||||
if (e != null) {
|
||||
log.info("Exception was", e);
|
||||
}
|
||||
Assert.assertNotNull(e);
|
||||
tomcat.getConnector().start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartStopBindOnStart() throws Exception {
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
Connector c = tomcat.getConnector();
|
||||
Assert.assertTrue(c.setProperty("bindOnInit", "false"));
|
||||
|
||||
File appDir = new File(getBuildDirectory(), "webapps/examples");
|
||||
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
|
||||
|
||||
|
||||
tomcat.start();
|
||||
int port = getPort();
|
||||
|
||||
tomcat.getConnector().stop();
|
||||
Exception e = null;
|
||||
ServerSocket s = null;
|
||||
long pool = 0;
|
||||
long nativeSocket = 0;
|
||||
boolean isApr = tomcat.getConnector().getProtocolHandlerClassName().contains("Apr");
|
||||
try {
|
||||
// This should not throw an Exception
|
||||
if (isApr) {
|
||||
pool = createAprPool();
|
||||
Assert.assertTrue(pool != 0);
|
||||
nativeSocket = createAprSocket(port, pool);
|
||||
Assert.assertTrue(nativeSocket != 0);
|
||||
} else {
|
||||
s = new ServerSocket(port, 100,
|
||||
InetAddress.getByName("localhost"));
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
e = e1;
|
||||
} finally {
|
||||
try {
|
||||
if (isApr) {
|
||||
destroyAprSocket(nativeSocket, pool);
|
||||
} else if (s != null) {
|
||||
s.close();
|
||||
}
|
||||
} catch (Exception e2) { /* Ignore */ }
|
||||
}
|
||||
Assert.assertNull(e);
|
||||
tomcat.getConnector().start();
|
||||
}
|
||||
}
|
||||
698
test/org/apache/tomcat/util/net/TesterSupport.java
Normal file
698
test/org/apache/tomcat/util/net/TesterSupport.java
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.authenticator.SSLAuthenticator;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.core.AprLifecycleListener;
|
||||
import org.apache.catalina.core.StandardServer;
|
||||
import org.apache.catalina.startup.TesterMapRealm;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.jni.Library;
|
||||
import org.apache.tomcat.jni.LibraryNotFoundError;
|
||||
import org.apache.tomcat.jni.SSL;
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.descriptor.web.LoginConfig;
|
||||
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
|
||||
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
|
||||
|
||||
public final class TesterSupport {
|
||||
|
||||
public static final String SSL_DIR = "test/org/apache/tomcat/util/net/";
|
||||
public static final String CA_ALIAS = "ca";
|
||||
public static final String CA_JKS = SSL_DIR + CA_ALIAS + ".jks";
|
||||
public static final String CLIENT_ALIAS = "user1";
|
||||
public static final String CLIENT_JKS = SSL_DIR + CLIENT_ALIAS + ".jks";
|
||||
public static final String LOCALHOST_EC_JKS = SSL_DIR + "localhost-ec.jks";
|
||||
public static final String LOCALHOST_RSA_JKS = SSL_DIR + "localhost-rsa.jks";
|
||||
public static final String LOCALHOST_KEYPASS_JKS = SSL_DIR + "localhost-rsa-copy1.jks";
|
||||
public static final String JKS_PASS = "changeit";
|
||||
public static final String JKS_KEY_PASS = "tomcatpass";
|
||||
public static final String CA_CERT_PEM = SSL_DIR + CA_ALIAS + "-cert.pem";
|
||||
public static final String LOCALHOST_EC_CERT_PEM = SSL_DIR + "localhost-ec-cert.pem";
|
||||
public static final String LOCALHOST_EC_KEY_PEM = SSL_DIR + "localhost-ec-key.pem";
|
||||
public static final String LOCALHOST_RSA_CERT_PEM = SSL_DIR + "localhost-rsa-cert.pem";
|
||||
public static final String LOCALHOST_RSA_KEY_PEM = SSL_DIR + "localhost-rsa-key.pem";
|
||||
public static final boolean OPENSSL_AVAILABLE;
|
||||
public static final int OPENSSL_VERSION;
|
||||
public static final boolean TLSV13_AVAILABLE;
|
||||
|
||||
public static final String ROLE = "testrole";
|
||||
|
||||
private static String clientAuthExpectedIssuer;
|
||||
private static String lastUsage = "NONE";
|
||||
private static Principal[] lastRequestedIssuers = new Principal[0];
|
||||
|
||||
static {
|
||||
boolean available = false;
|
||||
int version = 0;
|
||||
try {
|
||||
Library.initialize(null);
|
||||
available = true;
|
||||
version = SSL.version();
|
||||
Library.terminate();
|
||||
} catch (Exception | LibraryNotFoundError ex) {
|
||||
// Ignore
|
||||
}
|
||||
OPENSSL_AVAILABLE = available;
|
||||
OPENSSL_VERSION = version;
|
||||
|
||||
available = false;
|
||||
try {
|
||||
SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_3);
|
||||
available = true;
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
}
|
||||
TLSV13_AVAILABLE = available;
|
||||
}
|
||||
|
||||
public static boolean isOpensslAvailable() {
|
||||
return OPENSSL_AVAILABLE;
|
||||
}
|
||||
|
||||
public static int getOpensslVersion() {
|
||||
return OPENSSL_VERSION;
|
||||
}
|
||||
|
||||
public static boolean isTlsv13Available() {
|
||||
return TLSV13_AVAILABLE;
|
||||
}
|
||||
|
||||
public static void initSsl(Tomcat tomcat) {
|
||||
initSsl(tomcat, LOCALHOST_RSA_JKS, null, null);
|
||||
}
|
||||
|
||||
protected static void initSsl(Tomcat tomcat, String keystore,
|
||||
String keystorePass, String keyPass) {
|
||||
|
||||
Connector connector = tomcat.getConnector();
|
||||
connector.setSecure(true);
|
||||
Assert.assertTrue(connector.setProperty("SSLEnabled", "true"));
|
||||
|
||||
SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
|
||||
sslHostConfig.addCertificate(certificate);
|
||||
connector.addSslHostConfig(sslHostConfig);
|
||||
|
||||
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
|
||||
if (!protocol.contains("Apr")) {
|
||||
String sslImplementation = System.getProperty("tomcat.test.sslImplementation");
|
||||
if (sslImplementation != null && !"${test.sslImplementation}".equals(sslImplementation)) {
|
||||
StandardServer server = (StandardServer) tomcat.getServer();
|
||||
AprLifecycleListener listener = new AprLifecycleListener();
|
||||
listener.setSSLRandomSeed("/dev/urandom");
|
||||
server.addLifecycleListener(listener);
|
||||
connector.setAttribute("sslImplementationName", sslImplementation);
|
||||
}
|
||||
sslHostConfig.setSslProtocol("tls");
|
||||
certificate.setCertificateKeystoreFile(new File(keystore).getAbsolutePath());
|
||||
sslHostConfig.setTruststoreFile(new File(CA_JKS).getAbsolutePath());
|
||||
if (keystorePass != null) {
|
||||
certificate.setCertificateKeystorePassword(keystorePass);
|
||||
}
|
||||
if (keyPass != null) {
|
||||
certificate.setCertificateKeyPassword(keyPass);
|
||||
}
|
||||
} else {
|
||||
certificate.setCertificateFile(new File(LOCALHOST_RSA_CERT_PEM).getAbsolutePath());
|
||||
certificate.setCertificateKeyFile(new File(LOCALHOST_RSA_KEY_PEM).getAbsolutePath());
|
||||
sslHostConfig.setCaCertificateFile(new File(CA_CERT_PEM).getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
protected static KeyManager[] getUser1KeyManagers() throws Exception {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
|
||||
KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(getKeyStore(CLIENT_JKS), JKS_PASS.toCharArray());
|
||||
KeyManager[] managers = kmf.getKeyManagers();
|
||||
KeyManager manager;
|
||||
for (int i=0; i < managers.length; i++) {
|
||||
manager = managers[i];
|
||||
if (manager instanceof X509ExtendedKeyManager) {
|
||||
managers[i] = new TrackingExtendedKeyManager((X509ExtendedKeyManager)manager);
|
||||
} else if (manager instanceof X509KeyManager) {
|
||||
managers[i] = new TrackingKeyManager((X509KeyManager)manager);
|
||||
}
|
||||
}
|
||||
return managers;
|
||||
}
|
||||
|
||||
protected static TrustManager[] getTrustManagers() throws Exception {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
|
||||
TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(getKeyStore(CA_JKS));
|
||||
return tmf.getTrustManagers();
|
||||
}
|
||||
|
||||
protected static ClientSSLSocketFactory configureClientSsl() {
|
||||
ClientSSLSocketFactory clientSSLSocketFactory = null;
|
||||
try {
|
||||
SSLContext sc = SSLContext.getInstance(Constants.SSL_PROTO_TLS);
|
||||
sc.init(TesterSupport.getUser1KeyManagers(),
|
||||
TesterSupport.getTrustManagers(),
|
||||
null);
|
||||
clientSSLSocketFactory = new ClientSSLSocketFactory(sc.getSocketFactory());
|
||||
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(clientSSLSocketFactory);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return clientSSLSocketFactory;
|
||||
}
|
||||
|
||||
private static KeyStore getKeyStore(String keystore) throws Exception {
|
||||
File keystoreFile = new File(keystore);
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
try (InputStream is = new FileInputStream(keystoreFile)) {
|
||||
ks.load(is, JKS_PASS.toCharArray());
|
||||
}
|
||||
return ks;
|
||||
}
|
||||
|
||||
protected static boolean isMacOs() {
|
||||
return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("mac os x");
|
||||
}
|
||||
|
||||
protected static boolean isRenegotiationSupported(Tomcat tomcat) {
|
||||
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
|
||||
if (protocol.contains("Apr")) {
|
||||
// Disabled by default in 1.1.20 windows binary (2010-07-27)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static boolean isClientRenegotiationSupported(Tomcat tomcat) {
|
||||
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
|
||||
if (protocol.contains("Apr")) {
|
||||
// Disabled by default in 1.1.20 windows binary (2010-07-27)
|
||||
return false;
|
||||
}
|
||||
if (protocol.contains("NioProtocol") || (protocol.contains("Nio2Protocol") && isMacOs())) {
|
||||
// Doesn't work on all platforms - see BZ 56448.
|
||||
return false;
|
||||
}
|
||||
String sslImplementation = System.getProperty("tomcat.test.sslImplementation");
|
||||
if (sslImplementation != null && !"${test.sslImplementation}".equals(sslImplementation)) {
|
||||
// Assume custom SSL is not supporting this
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static void configureClientCertContext(Tomcat tomcat) {
|
||||
TesterSupport.initSsl(tomcat);
|
||||
|
||||
/* When running on Java 11, TLSv1.3 is enabled by default. The JSSE
|
||||
* implementation of TLSv1.3 does not support
|
||||
* certificateVerification="optional", a setting on which these tests
|
||||
* depend.
|
||||
* Java 7 does not enable TLSv1.1 or TLS1.2 by default
|
||||
*
|
||||
* Ensure these tests pass with all JREs from Java 7 onwards.
|
||||
*/
|
||||
if (JreCompat.isJre8Available()) {
|
||||
tomcat.getConnector().findSslHostConfigs()[0].setProtocols(Constants.SSL_PROTO_TLSv1_2);
|
||||
} else {
|
||||
tomcat.getConnector().findSslHostConfigs()[0].setProtocols(Constants.SSL_PROTO_TLSv1);
|
||||
}
|
||||
|
||||
// Need a web application with a protected and unprotected URL
|
||||
// No file system docBase required
|
||||
Context ctx = tomcat.addContext("", null);
|
||||
|
||||
Tomcat.addServlet(ctx, "simple", new SimpleServlet());
|
||||
ctx.addServletMappingDecoded("/unprotected", "simple");
|
||||
ctx.addServletMappingDecoded("/protected", "simple");
|
||||
|
||||
// Security constraints
|
||||
SecurityCollection collection = new SecurityCollection();
|
||||
collection.addPatternDecoded("/protected");
|
||||
SecurityConstraint sc = new SecurityConstraint();
|
||||
sc.addAuthRole(ROLE);
|
||||
sc.addCollection(collection);
|
||||
ctx.addConstraint(sc);
|
||||
|
||||
// Configure the Realm
|
||||
TesterMapRealm realm = new TesterMapRealm();
|
||||
|
||||
// Get the CA subject the server should send us for client cert selection
|
||||
try {
|
||||
KeyStore ks = getKeyStore(CA_JKS);
|
||||
X509Certificate cert = (X509Certificate)ks.getCertificate(CA_ALIAS);
|
||||
clientAuthExpectedIssuer = cert.getSubjectDN().getName();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
String cn = "NOTFOUND";
|
||||
try {
|
||||
KeyStore ks = getKeyStore(CLIENT_JKS);
|
||||
X509Certificate cert = (X509Certificate)ks.getCertificate(CLIENT_ALIAS);
|
||||
cn = cert.getSubjectDN().getName();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
realm.addUser(cn, "not used");
|
||||
realm.addUserRole(cn, ROLE);
|
||||
ctx.setRealm(realm);
|
||||
|
||||
// Configure the authenticator
|
||||
LoginConfig lc = new LoginConfig();
|
||||
lc.setAuthMethod("CLIENT-CERT");
|
||||
ctx.setLoginConfig(lc);
|
||||
ctx.getPipeline().addValve(new SSLAuthenticator());
|
||||
|
||||
// Clear the tracking data
|
||||
lastUsage = "NONE";
|
||||
lastRequestedIssuers = new Principal[0];
|
||||
}
|
||||
|
||||
protected static String getClientAuthExpectedIssuer() {
|
||||
return clientAuthExpectedIssuer;
|
||||
}
|
||||
|
||||
protected static void trackTrackingKeyManagers(@SuppressWarnings("unused") KeyManager wrapper,
|
||||
@SuppressWarnings("unused") KeyManager wrapped, String usage, Principal[] issuers) {
|
||||
lastUsage = usage;
|
||||
lastRequestedIssuers = issuers;
|
||||
}
|
||||
|
||||
protected static String getLastClientAuthKeyManagerUsage() {
|
||||
return lastUsage;
|
||||
}
|
||||
|
||||
protected static int getLastClientAuthRequestedIssuerCount() {
|
||||
return lastRequestedIssuers == null ? 0 : lastRequestedIssuers.length;
|
||||
}
|
||||
|
||||
protected static Principal getLastClientAuthRequestedIssuer(int index) {
|
||||
return lastRequestedIssuers[index];
|
||||
}
|
||||
|
||||
protected static boolean checkLastClientAuthRequestedIssuers() {
|
||||
if (lastRequestedIssuers == null || lastRequestedIssuers.length != 1)
|
||||
return false;
|
||||
return (new X500Principal(clientAuthExpectedIssuer)).equals(
|
||||
new X500Principal(lastRequestedIssuers[0].getName()));
|
||||
}
|
||||
|
||||
public static final byte DATA = (byte)33;
|
||||
|
||||
public static class SimpleServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
resp.getWriter().print("OK");
|
||||
if (req.isUserInRole(ROLE)) {
|
||||
resp.getWriter().print("-" + ROLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
// Swallow any request body
|
||||
int read = 0;
|
||||
int len = 0;
|
||||
byte[] buffer = new byte[4096];
|
||||
InputStream is = req.getInputStream();
|
||||
boolean contentOK = true;
|
||||
while (len > -1) {
|
||||
len = is.read(buffer);
|
||||
read = read + len;
|
||||
for (int i=0; i<len && contentOK; i++) {
|
||||
contentOK = (buffer[i] == DATA);
|
||||
}
|
||||
}
|
||||
// len will have been -1 on last iteration
|
||||
read++;
|
||||
|
||||
// Report the number of bytes read
|
||||
resp.setContentType("text/plain");
|
||||
if (contentOK)
|
||||
resp.getWriter().print("OK-" + read);
|
||||
else
|
||||
resp.getWriter().print("CONTENT-MISMATCH-" + read);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrackingKeyManager implements X509KeyManager {
|
||||
|
||||
private X509KeyManager manager = null;
|
||||
|
||||
public TrackingKeyManager(X509KeyManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
|
||||
trackTrackingKeyManagers(this, manager, "chooseClientAlias", issuers);
|
||||
return manager.chooseClientAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
|
||||
trackTrackingKeyManagers(this, manager, "chooseServerAlias", issuers);
|
||||
return manager.chooseServerAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
return manager.getCertificateChain(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(String keyType, Principal[] issuers) {
|
||||
trackTrackingKeyManagers(this, manager, "getClientAliases", issuers);
|
||||
return manager.getClientAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(String alias) {
|
||||
return manager.getPrivateKey(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(String keyType, Principal[] issuers) {
|
||||
trackTrackingKeyManagers(this, manager, "getServerAliases", issuers);
|
||||
return manager.getServerAliases(keyType, issuers);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrackingExtendedKeyManager extends X509ExtendedKeyManager {
|
||||
|
||||
private X509ExtendedKeyManager manager = null;
|
||||
|
||||
public TrackingExtendedKeyManager(X509ExtendedKeyManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
|
||||
trackTrackingKeyManagers(this, manager, "chooseClientAlias", issuers);
|
||||
return manager.chooseClientAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
|
||||
trackTrackingKeyManagers(this, manager, "chooseServerAlias", issuers);
|
||||
return manager.chooseServerAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
return manager.getCertificateChain(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(String keyType, Principal[] issuers) {
|
||||
trackTrackingKeyManagers(this, manager, "getClientAliases", issuers);
|
||||
return manager.getClientAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(String alias) {
|
||||
return manager.getPrivateKey(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(String keyType, Principal[] issuers) {
|
||||
trackTrackingKeyManagers(this, manager, "getServerAliases", issuers);
|
||||
return manager.getServerAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
|
||||
trackTrackingKeyManagers(this, manager, "chooseEngineClientAlias", issuers);
|
||||
return manager.chooseEngineClientAlias(keyType, issuers, engine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
|
||||
trackTrackingKeyManagers(this, manager, "chooseEngineServerAlias", issuers);
|
||||
return manager.chooseEngineServerAlias(keyType, issuers, engine);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrustAllCerts implements X509TrustManager {
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] certs,
|
||||
String authType) {
|
||||
// NOOP - Trust everything
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] certs,
|
||||
String authType) {
|
||||
// NOOP - Trust everything
|
||||
}
|
||||
}
|
||||
|
||||
public static class SequentialTrustManager implements X509TrustManager {
|
||||
|
||||
private static X509TrustManager[] tms;
|
||||
private static X509Certificate[] certs;
|
||||
|
||||
static {
|
||||
try {
|
||||
TrustManager[] managers = getTrustManagers();
|
||||
int mcount = 0;
|
||||
int ccount = 0;
|
||||
for (TrustManager tm : managers) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
mcount++;
|
||||
ccount += ((X509TrustManager)tm).getAcceptedIssuers().length;
|
||||
}
|
||||
}
|
||||
tms = new X509TrustManager[mcount];
|
||||
certs = new X509Certificate[ccount];
|
||||
mcount = 0;
|
||||
ccount = 0;
|
||||
for (TrustManager tm : managers) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
tms[mcount] = (X509TrustManager)tm;
|
||||
mcount++;
|
||||
for (X509Certificate cert : ((X509TrustManager)tm).getAcceptedIssuers()) {
|
||||
certs[ccount] = cert;
|
||||
ccount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
tms = new X509TrustManager[1];
|
||||
tms[0] = new TrustAllCerts();
|
||||
certs = new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return certs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] certs,
|
||||
String authType) throws CertificateException {
|
||||
boolean trust = false;
|
||||
for (X509TrustManager tm : tms) {
|
||||
try {
|
||||
tm.checkClientTrusted(certs, authType);
|
||||
trust = true;
|
||||
} catch (CertificateException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (!trust) {
|
||||
throw new CertificateException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] certs,
|
||||
String authType) throws CertificateException {
|
||||
boolean trust = false;
|
||||
for (X509TrustManager tm : tms) {
|
||||
try {
|
||||
tm.checkServerTrusted(certs, authType);
|
||||
trust = true;
|
||||
} catch (CertificateException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (!trust) {
|
||||
throw new CertificateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ClientSSLSocketFactory extends SSLSocketFactory {
|
||||
|
||||
private final SSLSocketFactory delegate;
|
||||
|
||||
private String[] ciphers = null;
|
||||
|
||||
|
||||
public ClientSSLSocketFactory(SSLSocketFactory delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the use of the specified cipher.
|
||||
*
|
||||
* @param ciphers Array of standard JSSE names of ciphers to use
|
||||
*/
|
||||
public void setCipher(String[] ciphers) {
|
||||
this.ciphers = ciphers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
||||
Socket result = delegate.createSocket(s, host, port, autoClose);
|
||||
reconfigureSocket(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return delegate.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return delegate.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
|
||||
Socket result = delegate.createSocket(host, port);
|
||||
reconfigureSocket(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
Socket result = delegate.createSocket(host, port);
|
||||
reconfigureSocket(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
|
||||
throws IOException, UnknownHostException {
|
||||
Socket result = delegate.createSocket(host, port, localHost, localPort);
|
||||
reconfigureSocket(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
|
||||
throws IOException {
|
||||
Socket result = delegate.createSocket(address, port, localAddress, localPort);
|
||||
reconfigureSocket(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Socket reconfigureSocket(Socket socket) {
|
||||
if (ciphers != null) {
|
||||
((SSLSocket) socket).setEnabledCipherSuites(ciphers);
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We want to use TLS 1.3 where we can but this requires TLS 1.3 to be
|
||||
* supported on the client and the server.
|
||||
*/
|
||||
public static String getDefaultTLSProtocolForTesting(Connector connector) {
|
||||
// Clients always use JSSE
|
||||
if (!TLSV13_AVAILABLE) {
|
||||
// Client doesn't support TLS 1.3 so we have to use TLS 1.2
|
||||
return Constants.SSL_PROTO_TLSv1_2;
|
||||
}
|
||||
|
||||
if (connector.getProtocolHandlerClassName().contains("Apr")) {
|
||||
// APR connector so OpenSSL is used for TLS.
|
||||
if (SSL.version() >= 0x1010100f) {
|
||||
return Constants.SSL_PROTO_TLSv1_3;
|
||||
} else {
|
||||
return Constants.SSL_PROTO_TLSv1_2;
|
||||
}
|
||||
} else {
|
||||
// NIO or NIO2. Tests do not use JSSE+OpenSSL so JSSE will be used.
|
||||
// Due to check above, it is known that TLS 1.3 is available
|
||||
return Constants.SSL_PROTO_TLSv1_3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isDefaultTLSProtocolForTesting13(Connector connector) {
|
||||
return Constants.SSL_PROTO_TLSv1_3.equals(
|
||||
TesterSupport.getDefaultTLSProtocolForTesting(connector));
|
||||
}
|
||||
}
|
||||
38
test/org/apache/tomcat/util/net/ca-cert.pem
Normal file
38
test/org/apache/tomcat/util/net/ca-cert.pem
Normal file
@@ -0,0 +1,38 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGpzCCBI+gAwIBAgIJAL51xu6EZW62MA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECBMCTUExEjAQBgNVBAcTCVdha2VmaWVsZDEnMCUGA1UE
|
||||
ChMeVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMRowGAYDVQQLExFBcGFj
|
||||
aGUgVG9tY2F0IFBNQzEeMBwGA1UEAxMVQXBhY2hlIFRvbWNhdCBUZXN0IENBMB4X
|
||||
DTE3MDgwODEwMzYzNloXDTI3MDgwNjEwMzYzNlowgZMxCzAJBgNVBAYTAlVTMQsw
|
||||
CQYDVQQIEwJNQTESMBAGA1UEBxMJV2FrZWZpZWxkMScwJQYDVQQKEx5UaGUgQXBh
|
||||
Y2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xGjAYBgNVBAsTEUFwYWNoZSBUb21jYXQg
|
||||
UE1DMR4wHAYDVQQDExVBcGFjaGUgVG9tY2F0IFRlc3QgQ0EwggIiMA0GCSqGSIb3
|
||||
DQEBAQUAA4ICDwAwggIKAoICAQCuokXuzdQ8HToRVcL07AdxHW9WmaMpcPWb/vyQ
|
||||
dcuha+JXJ9Wu+d7fpxppeuxnjDmDCZNo0kimI7nYIEDMd3WVen75aoMZnQ7+vN/G
|
||||
ZQXxzSPz2vzTZyEETAqs7DsGwO5CK2y5sWKl57+QCz/N+xM7EwOyNkmt+7xI1eQ+
|
||||
z2sUNLRMK7abom8nm/wVftGAXIiribmTqukoxjr8dpEDg77VCy9eqe6kcil6Fvnr
|
||||
mYrJqmrwzGldUlw4jqHl1IJnJ5z281vzzQ0U5ULeiuBpDGXcOHoaH8zYxilBVpPu
|
||||
RDRBOcX17e5NouZtDTFemkJq5ns3PDt+WjJvuYNSELLBbnP+S1V6mt+MU9PsF6Td
|
||||
lVZZxxFD9hPYqAzymwJGzTKbE8juZruQswL4iftyELmLPjIsetVtXifsUNay6CfD
|
||||
r5sN6r+KLrhJWUqhii2mH1jx4cLmlf308TOc80TldvvI9cfrb596954cEE+7dlaU
|
||||
vnRbBAeVNHNHl5e68fvwpKgtvQhtg1rZ2w1foSkAyyNRkYrUZKe4ztUx9E2w9qIm
|
||||
3OkZyMcPTKYkBVahR6K1bCo69uaUrxY4NaYlPfKdJmGfio/J2WGdqLq9na4iHRyY
|
||||
pb5zKvYmH9cNpmn5V42yhmX7tjMJzUyWw8KxXpE/qEVB2wl11wNguEL8CaZy+3u0
|
||||
iaCqbQIDAQABo4H7MIH4MB0GA1UdDgQWBBQA8phNISwAPECbhPTeKvAm7jIOnzCB
|
||||
yAYDVR0jBIHAMIG9gBQA8phNISwAPECbhPTeKvAm7jIOn6GBmaSBljCBkzELMAkG
|
||||
A1UEBhMCVVMxCzAJBgNVBAgTAk1BMRIwEAYDVQQHEwlXYWtlZmllbGQxJzAlBgNV
|
||||
BAoTHlRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEaMBgGA1UECxMRQXBh
|
||||
Y2hlIFRvbWNhdCBQTUMxHjAcBgNVBAMTFUFwYWNoZSBUb21jYXQgVGVzdCBDQYIJ
|
||||
AL51xu6EZW62MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAAJx4rzn
|
||||
rtrcic/F0keS2BSazERFmRlSOlHUsREk+6fq35h7ktnijBHsPXyLEPa5w9x5qJZf
|
||||
a2zFGiiiHqRBiX1E8JhKR6jjcX3D3VODfLomXWInHgEDcwNNcnvspG0RUX2jUh7m
|
||||
p1i1c32r1s51P0AEB4zmT6KZ7gAZThqwtkpf6FQXmKdVXQFbf8EP0+6HFpHhV4lc
|
||||
Ee4tDGJnc8X59Yzhu2rg8tF8OmNwcccTXthCH4I/4wymbw6YLg/B/V7AXH1/lui3
|
||||
B15MKabYgZOU3TeOmQ9sqFPztekEKe+sE3Mvdf90Fh4EBZCENWULGUJE9uVJuT8S
|
||||
2WVGOMmIkDlMP0t8Wnb3gMwUzhGyWp2FjzixVg8vS85ZE5wX4kGPD6nx+cAPDKrd
|
||||
j3TCdr0VHoxVoGkzvijDjf6+aNhHp87VYSOZDQh1ToNgDFHum362iXt7n+ppu3u4
|
||||
LDG3c1ztmUjgGrki+bQvnVyeYSprNWO1houo7xvZ61gWtzo1jwvcOwU0NxWtQMAg
|
||||
NLZeketZSAL2834Xhkj1tjP2HT5HffkYbg6QRWKPYk/vBUKU40VilDCXf2ieOR9A
|
||||
UtbcjjB5dRbR0CTnbwu33XeuhqobhaaAbp9gGt71WnOZpKIrkvVG3Z+YLpotRiYd
|
||||
cl3dVVqvg/CTCpwd/VOOAmW1ynLpflLR8rH/
|
||||
-----END CERTIFICATE-----
|
||||
BIN
test/org/apache/tomcat/util/net/ca.jks
Normal file
BIN
test/org/apache/tomcat/util/net/ca.jks
Normal file
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net.jsse;
|
||||
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.net.Constants;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLUtil;
|
||||
|
||||
public class TesterBug50640SslImpl extends JSSEImplementation {
|
||||
|
||||
public static final String PROPERTY_VALUE = "magic";
|
||||
|
||||
|
||||
@Override
|
||||
public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
|
||||
SSLHostConfig sslHostConfig = certificate.getSSLHostConfig();
|
||||
if (sslHostConfig.getProtocols().size() == 1 &&
|
||||
sslHostConfig.getProtocols().contains(PROPERTY_VALUE)) {
|
||||
if (JreCompat.isJre8Available()) {
|
||||
sslHostConfig.setProtocols(Constants.SSL_PROTO_TLSv1_2);
|
||||
} else {
|
||||
sslHostConfig.setProtocols(Constants.SSL_PROTO_TLSv1);
|
||||
}
|
||||
return super.getSSLUtil(certificate);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
test/org/apache/tomcat/util/net/keystore-info.txt
Normal file
28
test/org/apache/tomcat/util/net/keystore-info.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
================================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You 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
|
||||
|
||||
http://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.
|
||||
================================================================================
|
||||
|
||||
ca.jks (changeit)
|
||||
ca CN=Apache Tomcat Test CA
|
||||
|
||||
localhost-rsa.jks (changeit)
|
||||
tomcat CN=localhost
|
||||
|
||||
localhost-rsa-copy1.jks (changeit)
|
||||
tomcat CN=localhost (tomcatpass)
|
||||
|
||||
user1.jks (changeit)
|
||||
user1 CN=user1
|
||||
86
test/org/apache/tomcat/util/net/localhost-ec-cert.pem
Normal file
86
test/org/apache/tomcat/util/net/localhost-ec-cert.pem
Normal file
@@ -0,0 +1,86 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4098 (0x1002)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=Apache Tomcat Test CA
|
||||
Validity
|
||||
Not Before: Feb 15 19:32:18 2019 GMT
|
||||
Not After : Feb 14 19:32:18 2021 GMT
|
||||
Subject: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=localhost
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: id-ecPublicKey
|
||||
Public-Key: (256 bit)
|
||||
pub:
|
||||
04:10:cc:24:b7:0c:2a:fe:a6:af:ea:b2:dc:26:f1:
|
||||
81:06:ae:0b:eb:f0:c0:5f:a3:ee:5a:e3:d3:7c:02:
|
||||
b0:58:6c:47:0e:6e:08:ac:30:e1:76:e5:9c:06:80:
|
||||
af:42:ce:a7:6f:49:b5:ec:95:08:b1:a9:e3:7a:f7:
|
||||
84:4f:e2:05:60
|
||||
ASN1 OID: prime256v1
|
||||
NIST CURVE: P-256
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
F8:98:B3:3A:75:F3:09:EB:FF:CC:6E:26:39:F0:B5:FF:1F:0F:FB:01
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:00:F2:98:4D:21:2C:00:3C:40:9B:84:F4:DE:2A:F0:26:EE:32:0E:9F
|
||||
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
66:3f:a4:8e:4b:e0:3c:a2:54:d3:8d:6a:6d:83:fe:02:13:a8:
|
||||
79:41:55:68:33:7a:13:84:2f:92:db:aa:06:ab:4c:69:a7:fe:
|
||||
47:2f:31:a0:16:e8:cb:df:a8:d7:b3:21:27:2b:51:e2:77:05:
|
||||
65:40:17:40:ff:9c:b8:3c:9f:c7:bf:65:8e:00:6f:ce:01:6d:
|
||||
30:37:84:96:bd:78:11:26:be:27:22:53:67:c8:ac:cb:04:cb:
|
||||
e2:96:a3:9e:a3:16:af:bf:97:be:c6:3d:0a:0f:1d:e9:45:0b:
|
||||
ea:77:47:a7:d5:79:b2:5a:bc:83:4c:8c:2a:ca:b7:4c:0c:d4:
|
||||
17:d5:24:b1:b1:5b:2c:6e:59:5d:30:40:b5:72:6f:3a:b1:f4:
|
||||
f9:0d:7e:b9:aa:99:26:19:21:b0:07:4d:49:c3:e7:c2:3d:c8:
|
||||
98:62:cd:b6:d5:9a:21:f8:c7:b0:1a:72:59:02:80:0f:83:af:
|
||||
d7:3b:8a:7e:53:38:8c:0d:e9:03:9d:c8:f9:1d:5c:82:7f:49:
|
||||
8d:87:d3:89:69:a1:39:d3:fd:04:17:e5:63:af:55:02:ef:60:
|
||||
d7:70:1d:60:6c:aa:53:43:13:f1:82:f6:b6:41:71:7b:38:ff:
|
||||
82:78:73:73:11:e7:48:2f:f8:e8:77:27:7a:0f:a3:14:b0:33:
|
||||
f9:aa:65:0c:8f:69:3b:2f:ee:b3:51:d6:5d:8a:67:80:47:1e:
|
||||
a3:bd:d2:03:c3:62:45:1a:ac:dd:79:2e:84:a7:3d:8a:27:89:
|
||||
c4:31:cc:1c:0b:37:a6:9d:a4:e4:65:03:8b:a3:5a:63:60:fb:
|
||||
b9:7b:44:7f:8d:6a:74:9f:52:0e:b8:e7:12:52:98:5f:e9:34:
|
||||
20:5a:f6:b7:15:a1:81:5e:f4:18:6c:18:c7:e8:dc:64:f8:d1:
|
||||
a2:6f:98:a6:fd:36:e8:be:e7:a8:3f:a5:cb:de:1f:8f:ef:4a:
|
||||
29:ee:69:f3:81:cd:ce:ec:5f:d7:b8:61:c1:41:4b:b0:49:5c:
|
||||
29:eb:dd:e8:a6:54:4c:61:72:af:9c:50:da:16:1d:da:14:c9:
|
||||
5f:8a:ae:2a:41:3b:9d:1e:72:7d:c8:eb:28:f2:a5:49:9b:ca:
|
||||
0c:38:88:09:b3:5f:a9:83:13:6a:93:03:f9:3c:92:22:b8:cb:
|
||||
ad:ba:dc:9b:6d:a6:9e:b0:d5:5a:57:ea:ae:f7:e9:8f:03:c2:
|
||||
24:80:f8:50:21:94:7c:58:ac:b0:86:58:13:f2:d4:ef:f3:c1:
|
||||
53:96:88:f9:dd:19:a7:83:fe:a9:d1:0a:1c:d0:10:23:6e:24:
|
||||
47:41:3b:d4:dd:a1:06:2d:8a:ba:51:ef:34:e7:81:f0:94:51:
|
||||
28:3a:44:8e:de:25:fa:e3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIESDCCAjCgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVT
|
||||
MQswCQYDVQQIEwJNQTESMBAGA1UEBxMJV2FrZWZpZWxkMScwJQYDVQQKEx5UaGUg
|
||||
QXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xGjAYBgNVBAsTEUFwYWNoZSBUb21j
|
||||
YXQgUE1DMR4wHAYDVQQDExVBcGFjaGUgVG9tY2F0IFRlc3QgQ0EwHhcNMTkwMjE1
|
||||
MTkzMjE4WhcNMjEwMjE0MTkzMjE4WjCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
Ak1BMRIwEAYDVQQHDAlXYWtlZmllbGQxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29m
|
||||
dHdhcmUgRm91bmRhdGlvbjEaMBgGA1UECwwRQXBhY2hlIFRvbWNhdCBQTUMxEjAQ
|
||||
BgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBDMJLcM
|
||||
Kv6mr+qy3CbxgQauC+vwwF+j7lrj03wCsFhsRw5uCKww4XblnAaAr0LOp29JteyV
|
||||
CLGp43r3hE/iBWCjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T
|
||||
U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBT4mLM6dfMJ6//MbiY5
|
||||
8LX/Hw/7ATAfBgNVHSMEGDAWgBQA8phNISwAPECbhPTeKvAm7jIOnzANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEAZj+kjkvgPKJU041qbYP+AhOoeUFVaDN6E4QvktuqBqtMaaf+
|
||||
Ry8xoBboy9+o17MhJytR4ncFZUAXQP+cuDyfx79ljgBvzgFtMDeElr14ESa+JyJT
|
||||
Z8isywTL4pajnqMWr7+XvsY9Cg8d6UUL6ndHp9V5slq8g0yMKsq3TAzUF9UksbFb
|
||||
LG5ZXTBAtXJvOrH0+Q1+uaqZJhkhsAdNScPnwj3ImGLNttWaIfjHsBpyWQKAD4Ov
|
||||
1zuKflM4jA3pA53I+R1cgn9JjYfTiWmhOdP9BBflY69VAu9g13AdYGyqU0MT8YL2
|
||||
tkFxezj/gnhzcxHnSC/46Hcneg+jFLAz+aplDI9pOy/us1HWXYpngEceo73SA8Ni
|
||||
RRqs3XkuhKc9iieJxDHMHAs3pp2k5GUDi6NaY2D7uXtEf41qdJ9SDrjnElKYX+k0
|
||||
IFr2txWhgV70GGwYx+jcZPjRom+Ypv026L7nqD+ly94fj+9KKe5p84HNzuxf17hh
|
||||
wUFLsElcKevd6KZUTGFyr5xQ2hYd2hTJX4quKkE7nR5yfcjrKPKlSZvKDDiICbNf
|
||||
qYMTapMD+TySIrjLrbrcm22mnrDVWlfqrvfpjwPCJID4UCGUfFissIZYE/LU7/PB
|
||||
U5aI+d0Zp4P+qdEKHNAQI24kR0E71N2hBi2KulHvNOeB8JRRKDpEjt4l+uM=
|
||||
-----END CERTIFICATE-----
|
||||
5
test/org/apache/tomcat/util/net/localhost-ec-key.pem
Normal file
5
test/org/apache/tomcat/util/net/localhost-ec-key.pem
Normal file
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0U7ZRpeTEzVDXCCP
|
||||
oKwgWnN0tf7CMaE9dJmLIPpNgnChRANCAAQQzCS3DCr+pq/qstwm8YEGrgvr8MBf
|
||||
o+5a49N8ArBYbEcObgisMOF25ZwGgK9CzqdvSbXslQixqeN694RP4gVg
|
||||
-----END PRIVATE KEY-----
|
||||
BIN
test/org/apache/tomcat/util/net/localhost-ec.jks
Normal file
BIN
test/org/apache/tomcat/util/net/localhost-ec.jks
Normal file
Binary file not shown.
109
test/org/apache/tomcat/util/net/localhost-rsa-cert.pem
Normal file
109
test/org/apache/tomcat/util/net/localhost-rsa-cert.pem
Normal file
@@ -0,0 +1,109 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4102 (0x1006)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=Apache Tomcat Test CA
|
||||
Validity
|
||||
Not Before: Aug 7 20:30:28 2019 GMT
|
||||
Not After : Aug 6 20:30:28 2021 GMT
|
||||
Subject: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=localhost
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:cf:e2:56:a6:67:a6:e8:e7:f3:94:86:6e:f9:06:
|
||||
46:cf:20:66:b5:cd:b1:c7:d6:50:ea:4d:46:44:ed:
|
||||
45:65:ea:b6:9b:2e:49:a5:25:c1:8e:36:f6:2c:bc:
|
||||
8e:09:35:0b:2f:43:70:73:07:47:1d:78:a1:12:e9:
|
||||
56:5d:ab:84:15:16:0e:38:01:bb:81:87:2d:c4:3b:
|
||||
dc:2e:4a:e1:d4:66:1b:ce:87:2c:a9:b8:e3:aa:80:
|
||||
75:79:b1:98:f3:dd:df:66:d0:0d:e1:06:d8:6c:6c:
|
||||
50:f0:00:80:32:70:55:7b:dd:eb:ae:f2:6a:bf:93:
|
||||
3d:15:e1:25:f8:75:ce:d8:46:dc:c4:6b:ee:f9:f5:
|
||||
93:39:ad:90:47:15:4b:fa:ca:5b:fe:ca:1b:29:8a:
|
||||
74:19:2a:cb:1e:4f:20:d9:74:75:24:a0:06:d1:3a:
|
||||
ed:9b:88:87:f3:1b:0f:a6:14:67:e9:ed:47:2e:a1:
|
||||
25:6a:c2:97:04:13:f4:9f:62:38:cd:5a:e7:ad:c2:
|
||||
64:2c:8f:9c:3d:04:58:12:42:e5:0c:8e:8c:ce:78:
|
||||
3d:60:38:ce:06:ff:9c:ea:9c:c9:0f:73:90:b2:1a:
|
||||
4a:16:99:c9:fe:95:88:7b:3c:7f:19:d0:26:27:11:
|
||||
78:f9:92:5c:b4:f5:d4:cb:b0:84:0c:74:37:3d:87:
|
||||
1a:0b
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
0D:86:88:1D:07:59:CE:14:B4:89:81:58:C6:0B:FF:4C:CA:25:52:80
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:00:F2:98:4D:21:2C:00:3C:40:9B:84:F4:DE:2A:F0:26:EE:32:0E:9F
|
||||
|
||||
Authority Information Access:
|
||||
OCSP - URI:http://127.0.0.1:8888
|
||||
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:localhost, IP Address:127.0.0.1
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
7d:dc:b1:0f:dd:34:df:26:63:73:02:8a:d6:39:64:73:c3:fc:
|
||||
40:75:26:b6:9b:42:72:af:c9:63:41:68:d0:78:c7:47:ef:c2:
|
||||
44:5a:b3:58:95:a3:2c:f3:b1:f4:a3:3d:0b:94:ff:b4:97:6a:
|
||||
e9:4b:4b:c2:3a:f6:36:43:af:ee:2f:39:3e:f2:5f:2c:a2:b7:
|
||||
43:3c:13:42:d8:4e:e0:36:bc:23:c5:43:88:46:92:f7:77:14:
|
||||
67:73:14:5b:43:0e:3d:b5:1a:69:e9:ca:84:08:20:27:9f:23:
|
||||
4d:60:db:cb:98:4a:b3:3e:71:e6:e8:a1:11:1c:7e:7e:43:fb:
|
||||
6d:a5:41:c0:7e:3f:84:ed:06:28:dc:aa:80:17:76:ec:8a:e6:
|
||||
65:45:21:85:13:48:e0:5b:87:c8:2a:1a:0f:37:0f:2a:64:53:
|
||||
a8:e3:49:04:84:88:fe:8b:a2:3c:cc:41:c7:c0:ad:26:d6:e1:
|
||||
67:69:9a:50:c7:eb:3d:1c:7f:da:88:08:24:14:6e:a1:ab:3e:
|
||||
77:3f:88:12:55:98:97:9f:db:ad:09:e2:20:fe:8d:1f:ea:4f:
|
||||
46:7e:d8:aa:ba:14:bd:a8:c2:6f:1b:47:62:d9:05:ca:c7:30:
|
||||
7b:1e:95:2e:55:10:1d:b1:e3:44:95:07:25:6e:8c:9d:69:5b:
|
||||
5c:ad:5f:56:27:e8:60:9f:d2:f4:64:7f:f7:8f:dc:bb:ee:bf:
|
||||
be:0b:ea:34:9b:37:de:f0:5c:e0:64:c2:52:42:a6:0d:20:7d:
|
||||
78:34:42:c1:1c:43:a1:98:e8:48:7b:92:49:2b:d9:63:91:6a:
|
||||
70:02:d0:1b:a5:2a:ee:e5:1b:12:4f:cb:c9:e7:18:ae:66:f5:
|
||||
04:d9:d2:68:95:c1:31:fe:57:9d:51:f5:fc:ed:43:3b:79:bf:
|
||||
c3:9d:85:68:d8:98:a5:3c:a2:bb:fb:5b:19:5b:de:f0:7e:c8:
|
||||
5e:47:ba:5d:8a:5b:44:f1:44:54:64:c0:da:95:a6:f0:bf:a9:
|
||||
3f:5d:4c:72:97:86:ae:1e:0d:cd:20:4b:85:e0:4e:26:4d:29:
|
||||
4e:96:43:b0:fd:30:5f:53:24:97:bc:35:d8:31:4b:6c:ea:a7:
|
||||
f9:64:f9:cb:a0:14:c4:fc:54:78:13:52:b5:06:8f:7a:c2:00:
|
||||
14:97:18:06:ef:bc:2f:2a:31:fc:11:25:7f:47:e3:3b:54:e7:
|
||||
46:62:78:ba:52:07:32:41:48:9d:47:bd:1c:f4:eb:49:11:42:
|
||||
40:9c:36:5a:e0:84:bd:09:44:91:bb:5c:d1:c4:28:6a:68:34:
|
||||
f9:2c:22:b7:fc:43:bb:c4:96:02:ce:73:43:be:de:02:9c:e1:
|
||||
d2:2a:4a:76:19:d6:3f:b0
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFZDCCA0ygAwIBAgICEAYwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVT
|
||||
MQswCQYDVQQIEwJNQTESMBAGA1UEBxMJV2FrZWZpZWxkMScwJQYDVQQKEx5UaGUg
|
||||
QXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xGjAYBgNVBAsTEUFwYWNoZSBUb21j
|
||||
YXQgUE1DMR4wHAYDVQQDExVBcGFjaGUgVG9tY2F0IFRlc3QgQ0EwHhcNMTkwODA3
|
||||
MjAzMDI4WhcNMjEwODA2MjAzMDI4WjCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
|
||||
Ak1BMRIwEAYDVQQHEwlXYWtlZmllbGQxJzAlBgNVBAoTHlRoZSBBcGFjaGUgU29m
|
||||
dHdhcmUgRm91bmRhdGlvbjEaMBgGA1UECxMRQXBhY2hlIFRvbWNhdCBQTUMxEjAQ
|
||||
BgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AM/iVqZnpujn85SGbvkGRs8gZrXNscfWUOpNRkTtRWXqtpsuSaUlwY429iy8jgk1
|
||||
Cy9DcHMHRx14oRLpVl2rhBUWDjgBu4GHLcQ73C5K4dRmG86HLKm446qAdXmxmPPd
|
||||
32bQDeEG2GxsUPAAgDJwVXvd667yar+TPRXhJfh1zthG3MRr7vn1kzmtkEcVS/rK
|
||||
W/7KGymKdBkqyx5PINl0dSSgBtE67ZuIh/MbD6YUZ+ntRy6hJWrClwQT9J9iOM1a
|
||||
563CZCyPnD0EWBJC5QyOjM54PWA4zgb/nOqcyQ9zkLIaShaZyf6ViHs8fxnQJicR
|
||||
ePmSXLT11MuwhAx0Nz2HGgsCAwEAAaOByzCByDAJBgNVHRMEAjAAMCwGCWCGSAGG
|
||||
+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU
|
||||
DYaIHQdZzhS0iYFYxgv/TMolUoAwHwYDVR0jBBgwFoAUAPKYTSEsADxAm4T03irw
|
||||
Ju4yDp8wMQYIKwYBBQUHAQEEJTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAu
|
||||
MC4xOjg4ODgwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
|
||||
CwUAA4ICAQB93LEP3TTfJmNzAorWOWRzw/xAdSa2m0Jyr8ljQWjQeMdH78JEWrNY
|
||||
laMs87H0oz0LlP+0l2rpS0vCOvY2Q6/uLzk+8l8sordDPBNC2E7gNrwjxUOIRpL3
|
||||
dxRncxRbQw49tRpp6cqECCAnnyNNYNvLmEqzPnHm6KERHH5+Q/ttpUHAfj+E7QYo
|
||||
3KqAF3bsiuZlRSGFE0jgW4fIKhoPNw8qZFOo40kEhIj+i6I8zEHHwK0m1uFnaZpQ
|
||||
x+s9HH/aiAgkFG6hqz53P4gSVZiXn9utCeIg/o0f6k9GftiquhS9qMJvG0di2QXK
|
||||
xzB7HpUuVRAdseNElQclboydaVtcrV9WJ+hgn9L0ZH/3j9y77r++C+o0mzfe8Fzg
|
||||
ZMJSQqYNIH14NELBHEOhmOhIe5JJK9ljkWpwAtAbpSru5RsST8vJ5xiuZvUE2dJo
|
||||
lcEx/ledUfX87UM7eb/DnYVo2JilPKK7+1sZW97wfsheR7pdiltE8URUZMDalabw
|
||||
v6k/XUxyl4auHg3NIEuF4E4mTSlOlkOw/TBfUySXvDXYMUts6qf5ZPnLoBTE/FR4
|
||||
E1K1Bo96wgAUlxgG77wvKjH8ESV/R+M7VOdGYni6UgcyQUidR70c9OtJEUJAnDZa
|
||||
4IS9CUSRu1zRxChqaDT5LCK3/EO7xJYCznNDvt4CnOHSKkp2GdY/sA==
|
||||
-----END CERTIFICATE-----
|
||||
BIN
test/org/apache/tomcat/util/net/localhost-rsa-copy1.jks
Normal file
BIN
test/org/apache/tomcat/util/net/localhost-rsa-copy1.jks
Normal file
Binary file not shown.
28
test/org/apache/tomcat/util/net/localhost-rsa-key.pem
Normal file
28
test/org/apache/tomcat/util/net/localhost-rsa-key.pem
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDP4lamZ6bo5/OU
|
||||
hm75BkbPIGa1zbHH1lDqTUZE7UVl6rabLkmlJcGONvYsvI4JNQsvQ3BzB0cdeKES
|
||||
6VZdq4QVFg44AbuBhy3EO9wuSuHUZhvOhyypuOOqgHV5sZjz3d9m0A3hBthsbFDw
|
||||
AIAycFV73euu8mq/kz0V4SX4dc7YRtzEa+759ZM5rZBHFUv6ylv+yhspinQZKsse
|
||||
TyDZdHUkoAbROu2biIfzGw+mFGfp7UcuoSVqwpcEE/SfYjjNWuetwmQsj5w9BFgS
|
||||
QuUMjozOeD1gOM4G/5zqnMkPc5CyGkoWmcn+lYh7PH8Z0CYnEXj5kly09dTLsIQM
|
||||
dDc9hxoLAgMBAAECggEAXfOqO6yux6ZE9MRJFSzcBbJcGSBsj6dxjGL+NhqR+by5
|
||||
aKrjx8qnjpGScqeI/epGMsck5CfO4SfqjDR+vvjMSgdcx70otCKW8ZAoM5fONoMr
|
||||
YAzBh7cy1ZUXArfcK6MD22B+VUwVtfLCJaXkSmdwivnCEaAn1ItD2UaXNZJwuFeF
|
||||
pT9Veif4MwfRhrVvHeEK+hEsrUePOOZ7bvfvIyd2pKtBuniiaoP9LIE2E/s+G458
|
||||
xFZUHDxSgumEekZLv1mt03rcNDW9B9kLELaDuVbO4mQBn3edolvmL7N2iZpPIhM/
|
||||
UDMqs7HfZ70bLcENa26UAZqIenbkueg7UkZgCF5RWQKBgQDxVTizo8vF+f7BhY8o
|
||||
VSvGEhyRsJsyt9wb5AkVUCSM6Q+fKTimRBoDBQijDVc20uV5HpYIy35THphmXYX8
|
||||
qIYNQiaGyLwBk6YWJDfqcfCjKBm6P7vtSFWjroRj2c0GjmXBZPk4sGYj16P4Qy00
|
||||
ZssPsa+ENYgc4mox6szTp5Zp1wKBgQDchLRPaz1tWoLIlIl35a5GLHZwf6GGDeDI
|
||||
2bxTMhBAohbjW9NSWf7GeZgeigRd7p5s6m2EriEJwsn61W0IWUzPLJ7iTHKOrVxU
|
||||
tGxHd+SV3KhOkGn1EJ8zFiNIma/nAZraGW9zH/lhq09G8ygf1y3lSCQIABG8pAbK
|
||||
xHmn3BoS7QKBgQCi0hSHXqNE1v4CItILLCt0XxPXV4feGB3w01Eth/yg9T0M7QrD
|
||||
Yn8KOoMxPvbwjik0JmajWGfKPIIlzkNvy2Nl3pOPrC7sAWm01orDKkxoR83T0tw/
|
||||
ouXkoQHBPFkPa1NLv4xFqv2+gOanwOrmx9OIqyD32gYTNs7fDsNSqWbZ0QKBgCup
|
||||
WsoewZrVQO/V+SH0J/1c8FZ17tVMCiW6dr9COlWRwlZh6AV2LCvAB46EZTjz9go6
|
||||
oFSU5ZW5K6SufVgZ1ktu2kaUPFpjmNRspMPByVCiz/A+R7xt/hdvWq0VQO7MMozc
|
||||
XGS+//GGqbuyiU9Em6G6Fug+m0RudanQHQZPXhpBAoGBAIuWHrYCOWJRHDw8WdOE
|
||||
811QFYHpMbYc0G4/50+O/1qKADWKbqAZpnbIW8NpHrcfggkgJw6E9kmtt8HbBu/3
|
||||
NuCWK1K/0aLwQQMXqgrwuNYvk1QRXbAx86fbC1XVrY2KwmuCg6snXjJZqsTI91xm
|
||||
jO0LxqN3mDyK11I9/XuearPH
|
||||
-----END PRIVATE KEY-----
|
||||
BIN
test/org/apache/tomcat/util/net/localhost-rsa.jks
Normal file
BIN
test/org/apache/tomcat/util/net/localhost-rsa.jks
Normal file
Binary file not shown.
137
test/org/apache/tomcat/util/net/openssl/TestOpenSSLConf.java
Normal file
137
test/org/apache/tomcat/util/net/openssl/TestOpenSSLConf.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.jni.SSLContext;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig;
|
||||
import org.apache.tomcat.util.net.TesterSupport;
|
||||
|
||||
public class TestOpenSSLConf extends TomcatBaseTest {
|
||||
|
||||
private static final String ENABLED_CIPHER = "AES256-SHA256";
|
||||
private static final String[] EXPECTED_CIPHERS = {ENABLED_CIPHER};
|
||||
private static final String[] ENABLED_PROTOCOLS = {"TLSv1.1"};
|
||||
private static final String[] DISABLED_PROTOCOLS = {"SSLv3", "TLSv1", "TLSv1.2"};
|
||||
private static final String[] DISABLED_PROTOCOLS_TLS13 = {"TLSv1.3"};
|
||||
// Test behavior needs to adjust for OpenSSL 1.1.1-pre3 and above
|
||||
private static final int OPENSSL_TLS13_SUPPORT_MIN_VERSION = 0x10101003;
|
||||
|
||||
private static int OPENSSL_VERSION = TesterSupport.getOpensslVersion();
|
||||
|
||||
private static boolean hasTLS13() {
|
||||
return OPENSSL_VERSION >= OPENSSL_TLS13_SUPPORT_MIN_VERSION;
|
||||
}
|
||||
|
||||
public SSLHostConfig initOpenSSLConfCmd(String... commands) throws Exception {
|
||||
Assert.assertNotNull(commands);
|
||||
Assert.assertTrue("Invalid length", commands.length % 2 == 0);
|
||||
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
TesterSupport.initSsl(tomcat);
|
||||
|
||||
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
|
||||
// The tests are only supported for APR and OpenSSL
|
||||
if (!protocol.contains("Apr")) {
|
||||
String sslImplementation = String.valueOf(
|
||||
tomcat.getConnector().getProperty("sslImplementationName"));
|
||||
Assume.assumeTrue("This test is only for OpenSSL based SSL connectors",
|
||||
sslImplementation.contains("openssl"));
|
||||
}
|
||||
|
||||
OpenSSLConf conf = new OpenSSLConf();
|
||||
for (int i = 0; i < commands.length;) {
|
||||
OpenSSLConfCmd cmd = new OpenSSLConfCmd();
|
||||
cmd.setName(commands[i++]);
|
||||
cmd.setValue(commands[i++]);
|
||||
conf.addCmd(cmd);
|
||||
}
|
||||
|
||||
SSLHostConfig[] sslHostConfigs = tomcat.getConnector().
|
||||
getProtocolHandler().findSslHostConfigs();
|
||||
Assert.assertEquals("Wrong SSLHostConfigCount", 1, sslHostConfigs.length);
|
||||
sslHostConfigs[0].setOpenSslConf(conf);
|
||||
|
||||
tomcat.start();
|
||||
|
||||
sslHostConfigs = tomcat.getConnector().getProtocolHandler().findSslHostConfigs();
|
||||
Assert.assertEquals("Wrong SSLHostConfigCount", 1, sslHostConfigs.length);
|
||||
return sslHostConfigs[0];
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSSLConfCmdCipher() throws Exception {
|
||||
log.info("Found OpenSSL version 0x" + Integer.toHexString(OPENSSL_VERSION));
|
||||
SSLHostConfig sslHostConfig;
|
||||
if (hasTLS13()) {
|
||||
// Ensure TLSv1.3 ciphers aren't returned
|
||||
sslHostConfig = initOpenSSLConfCmd("CipherString", ENABLED_CIPHER,
|
||||
"CipherSuites", "");
|
||||
} else {
|
||||
sslHostConfig = initOpenSSLConfCmd("CipherString", ENABLED_CIPHER);
|
||||
}
|
||||
String[] ciphers = sslHostConfig.getEnabledCiphers();
|
||||
Assert.assertThat("Wrong HostConfig ciphers", ciphers,
|
||||
CoreMatchers.is(EXPECTED_CIPHERS));
|
||||
ciphers = SSLContext.getCiphers(sslHostConfig.getOpenSslContext().longValue());
|
||||
Assert.assertThat("Wrong native SSL context ciphers", ciphers,
|
||||
CoreMatchers.is(EXPECTED_CIPHERS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSSLConfCmdProtocol() throws Exception {
|
||||
log.info("Found OpenSSL version 0x" + Integer.toHexString(OPENSSL_VERSION));
|
||||
Set<String> disabledProtocols = new HashSet<>(Arrays.asList(DISABLED_PROTOCOLS));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String protocol : DISABLED_PROTOCOLS) {
|
||||
sb.append(",").append("-").append(protocol);
|
||||
}
|
||||
if (hasTLS13()) {
|
||||
// Also disable TLSv1.3
|
||||
for (String protocol : DISABLED_PROTOCOLS_TLS13) {
|
||||
sb.append(",").append("-").append(protocol);
|
||||
disabledProtocols.add(protocol);
|
||||
}
|
||||
}
|
||||
for (String protocol : ENABLED_PROTOCOLS) {
|
||||
sb.append(",").append(protocol);
|
||||
}
|
||||
SSLHostConfig sslHostConfig = initOpenSSLConfCmd("Protocol", sb.substring(1));
|
||||
String[] protocols = sslHostConfig.getEnabledProtocols();
|
||||
for (String protocol : protocols) {
|
||||
Assert.assertFalse("Protocol " + protocol + " is not allowed",
|
||||
disabledProtocols.contains(protocol));
|
||||
}
|
||||
Set<String> enabledProtocols = new HashSet<>(Arrays.asList(protocols));
|
||||
for (String protocol : ENABLED_PROTOCOLS) {
|
||||
Assert.assertTrue("Protocol " + protocol + " is not enabled",
|
||||
enabledProtocols.contains(protocol));
|
||||
}
|
||||
}
|
||||
}
|
||||
1117
test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
Normal file
1117
test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestOpenSSLCipherConfigurationParser {
|
||||
|
||||
@Test
|
||||
public void testDEFAULT() throws Exception {
|
||||
if (TesterOpenSSL.VERSION < 10100) {
|
||||
// Account for classes of ciphers removed from DEFAULT in 1.1.0
|
||||
testSpecification("DEFAULT:!RC4:!DSS:!SEED:!IDEA:!CAMELLIA:!AESCCM:!3DES");
|
||||
} else {
|
||||
testSpecification("DEFAULT");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCOMPLEMENTOFDEFAULT() throws Exception {
|
||||
if (TesterOpenSSL.VERSION < 10100) {
|
||||
// Account for classes of ciphers removed from DEFAULT in 1.1.0
|
||||
testSpecification("COMPLEMENTOFDEFAULT:RC4:DSS:SEED:IDEA:CAMELLIA:AESCCM:aNULL:3DES");
|
||||
} else {
|
||||
testSpecification("COMPLEMENTOFDEFAULT");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testALL() throws Exception {
|
||||
testSpecification("ALL");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCOMPLEMENTOFALL() throws Exception {
|
||||
testSpecification("COMPLEMENTOFALL");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaNULL() throws Exception {
|
||||
testSpecification("aNULL");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testeNULL() throws Exception {
|
||||
testSpecification("eNULL");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHIGH() throws Exception {
|
||||
testSpecification("HIGH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMEDIUM() throws Exception {
|
||||
testSpecification("MEDIUM");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLOW() throws Exception {
|
||||
testSpecification("LOW");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEXPORT40() throws Exception {
|
||||
testSpecification("EXPORT40");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEXPORT() throws Exception {
|
||||
testSpecification("EXPORT");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRSA() throws Exception {
|
||||
testSpecification("RSA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaRSA() throws Exception {
|
||||
testSpecification("aRSA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkRSA() throws Exception {
|
||||
testSpecification("kRSA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkEDH() throws Exception {
|
||||
testSpecification("kEDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkDHE() throws Exception {
|
||||
// This alias was introduced in 1.0.2
|
||||
if (TesterOpenSSL.VERSION >= 10002) {
|
||||
testSpecification("kDHE");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEDH() throws Exception {
|
||||
testSpecification("EDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDHE() throws Exception {
|
||||
// This alias was introduced in 1.0.2
|
||||
if (TesterOpenSSL.VERSION >= 10002) {
|
||||
testSpecification("DHE");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkDHr() throws Exception {
|
||||
testSpecification("kDHr");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkDHd() throws Exception {
|
||||
testSpecification("kDHd");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkDH() throws Exception {
|
||||
testSpecification("kDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkECDHr() throws Exception {
|
||||
testSpecification("kECDHr");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkECDHe() throws Exception {
|
||||
testSpecification("kECDHe");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkECDH() throws Exception {
|
||||
testSpecification("kECDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkEECDH() throws Exception {
|
||||
testSpecification("kEECDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testECDH() throws Exception {
|
||||
testSpecification("ECDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkECDHE() throws Exception {
|
||||
testSpecification("kECDHE");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testECDHE() throws Exception {
|
||||
testSpecification("ECDHE");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Ignore("Contrary to the docs, OpenSSL does not recognise EECDHE")
|
||||
public void testEECDHE() throws Exception {
|
||||
testSpecification("EECDHE");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAECDH() throws Exception {
|
||||
testSpecification("AECDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDSS() throws Exception {
|
||||
testSpecification("DSS");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaDSS() throws Exception {
|
||||
testSpecification("aDSS");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaDH() throws Exception {
|
||||
testSpecification("aDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaECDH() throws Exception {
|
||||
testSpecification("aECDH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaECDSA() throws Exception {
|
||||
testSpecification("aECDSA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testECDSA() throws Exception {
|
||||
testSpecification("ECDSA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkFZA() throws Exception {
|
||||
testSpecification("kFZA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaFZA() throws Exception {
|
||||
testSpecification("aFZA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testeFZA() throws Exception {
|
||||
testSpecification("eFZA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFZA() throws Exception {
|
||||
testSpecification("FZA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTLSv1_2() throws Exception {
|
||||
testSpecification("TLSv1.2");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTLSv1() throws Exception {
|
||||
// In OpenSSL 1.1.0-dev, TLSv1 refers to those ciphers that require
|
||||
// TLSv1 rather than being an alias for SSLv3
|
||||
if (TesterOpenSSL.VERSION >= 10100) {
|
||||
testSpecification("TLSv1");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSSLv2() throws Exception {
|
||||
testSpecification("SSLv2");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSSLv3() throws Exception {
|
||||
// In OpenSSL 1.1.0-dev, TLSv1 refers to those ciphers that require
|
||||
// TLSv1 rather than being an alias for SSLv3
|
||||
if (TesterOpenSSL.VERSION < 10100) {
|
||||
testSpecification("SSLv3:TLSv1");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDH() throws Exception {
|
||||
testSpecification("DH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testADH() throws Exception {
|
||||
testSpecification("ADH");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAES128() throws Exception {
|
||||
testSpecification("AES128");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAES256() throws Exception {
|
||||
testSpecification("AES256");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAES() throws Exception {
|
||||
testSpecification("AES");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAESGCM() throws Exception {
|
||||
testSpecification("AESGCM");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAESCCM() throws Exception {
|
||||
testSpecification("AESCCM");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAESCCM8() throws Exception {
|
||||
testSpecification("AESCCM8");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCAMELLIA128() throws Exception {
|
||||
testSpecification("CAMELLIA128");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCAMELLIA256() throws Exception {
|
||||
testSpecification("CAMELLIA256");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCAMELLIA() throws Exception {
|
||||
testSpecification("CAMELLIA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCHACHA20() throws Exception {
|
||||
testSpecification("CHACHA20");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test3DES() throws Exception {
|
||||
testSpecification("3DES");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDES() throws Exception {
|
||||
testSpecification("DES");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRC4() throws Exception {
|
||||
testSpecification("RC4");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRC2() throws Exception {
|
||||
testSpecification("RC2");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIDEA() throws Exception {
|
||||
testSpecification("IDEA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSEED() throws Exception {
|
||||
testSpecification("SEED");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMD5() throws Exception {
|
||||
testSpecification("MD5");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSHA1() throws Exception {
|
||||
testSpecification("SHA1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSHA() throws Exception {
|
||||
testSpecification("SHA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSHA256() throws Exception {
|
||||
testSpecification("SHA256");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSHA384() throws Exception {
|
||||
testSpecification("SHA384");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testKRB5() throws Exception {
|
||||
testSpecification("KRB5");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaGOST() throws Exception {
|
||||
testSpecification("aGOST");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaGOST01() throws Exception {
|
||||
testSpecification("aGOST01");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaGOST94() throws Exception {
|
||||
testSpecification("aGOST94");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkGOST() throws Exception {
|
||||
testSpecification("kGOST");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGOST94() throws Exception {
|
||||
testSpecification("GOST94");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGOST89MAC() throws Exception {
|
||||
testSpecification("GOST89MAC");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testaPSK() throws Exception {
|
||||
testSpecification("aPSK");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkPSK() throws Exception {
|
||||
testSpecification("kPSK");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkRSAPSK() throws Exception {
|
||||
testSpecification("kRSAPSK");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkECDHEPSK() throws Exception {
|
||||
testSpecification("kECDHEPSK");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testkDHEPSK() throws Exception {
|
||||
testSpecification("kDHEPSK");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPSK() throws Exception {
|
||||
testSpecification("PSK");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testARIA() throws Exception {
|
||||
testSpecification("ARIA");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testARIA128() throws Exception {
|
||||
testSpecification("ARIA128");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testARIA256() throws Exception {
|
||||
testSpecification("ARIA256");
|
||||
}
|
||||
|
||||
|
||||
// TODO: Add tests for the individual operators
|
||||
|
||||
@Test
|
||||
public void testSpecification01() throws Exception {
|
||||
// Tomcat 8 default as of 2014-08-04
|
||||
// This gets an A- from https://www.ssllabs.com/ssltest with no FS for
|
||||
// a number of the reference browsers
|
||||
testSpecification("HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSpecification02() throws Exception {
|
||||
// Suggestion from dev list (s/ECDHE/kEECDH/, s/DHE/EDH/
|
||||
testSpecification("!aNULL:!eNULL:!EXPORT:!DSS:!DES:!SSLv2:kEECDH:ECDH:EDH:AES256-GCM-SHA384:AES128-GCM-SHA256:+RC4:HIGH:aRSA:kECDHr:MEDIUM");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSpecification03() throws Exception {
|
||||
// Reported as failing during 8.0.11 release vote by Ognjen Blagojevic
|
||||
// EDH was introduced in 1.0.0
|
||||
testSpecification("EECDH+aRSA+SHA384:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS");
|
||||
}
|
||||
|
||||
private void testSpecification(String specification) throws Exception {
|
||||
// Filter out cipher suites that OpenSSL does not implement
|
||||
String openSSLCipherList = TesterOpenSSL.getOpenSSLCiphersAsExpression(specification);
|
||||
List<String> jsseCipherListFromOpenSSL =
|
||||
OpenSSLCipherConfigurationParser.parseExpression(openSSLCipherList);
|
||||
List<String> jsseCipherListFromParser =
|
||||
OpenSSLCipherConfigurationParser.parseExpression(specification);
|
||||
|
||||
TesterOpenSSL.removeUnimplementedCiphersJsse(jsseCipherListFromParser);
|
||||
|
||||
// First check the lists have the same entries
|
||||
// Order is NOT important at this point. It is checked below.
|
||||
Assert.assertEquals(
|
||||
"Expected " + jsseCipherListFromParser.size() + " ciphers but got "
|
||||
+ jsseCipherListFromOpenSSL.size() + " for the specification '"
|
||||
+ specification + "'",
|
||||
new TreeSet<>(jsseCipherListFromParser), new TreeSet<>(jsseCipherListFromOpenSSL));
|
||||
|
||||
// OpenSSL treats many ciphers as having equal preference. The order
|
||||
// returned depends on the order they are requested. The following code
|
||||
// checks that the Parser produces a cipher list that is consistent with
|
||||
// OpenSSL's preference order by confirming that running through OpenSSL
|
||||
// does not change the order.
|
||||
String parserOrderedExpression = listToString(jsseCipherListFromParser, ',');
|
||||
Assert.assertEquals(
|
||||
listToString(OpenSSLCipherConfigurationParser.parseExpression(
|
||||
parserOrderedExpression), ','),
|
||||
parserOrderedExpression);
|
||||
}
|
||||
|
||||
|
||||
private String listToString(List<String> list, char separator) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String entry : list) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(separator);
|
||||
}
|
||||
sb.append(entry);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/*
|
||||
* The unit test is independent of OpenSSL version and does not require OpenSSL
|
||||
* to be present.
|
||||
*/
|
||||
public class TestOpenSSLCipherConfigurationParserOnly {
|
||||
|
||||
@Test
|
||||
public void testDefaultSort01() throws Exception {
|
||||
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
|
||||
|
||||
// Everything else being equal, AES is preferred
|
||||
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
|
||||
input.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
input.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
|
||||
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
|
||||
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
|
||||
|
||||
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
|
||||
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
|
||||
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
|
||||
expected.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
|
||||
Assert.assertEquals(expected.toString(), result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSort02() throws Exception {
|
||||
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
|
||||
|
||||
// ECHDE should beat AES
|
||||
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
|
||||
input.add(Cipher.TLS_RSA_WITH_AES_256_CBC_SHA);
|
||||
input.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
|
||||
|
||||
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
|
||||
expected.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
expected.add(Cipher.TLS_RSA_WITH_AES_256_CBC_SHA);
|
||||
|
||||
Assert.assertEquals(expected.toString(), result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSort03() throws Exception {
|
||||
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
|
||||
|
||||
// AES should beat CAMELLIA
|
||||
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
|
||||
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
input.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
|
||||
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
|
||||
|
||||
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
|
||||
expected.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
|
||||
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
|
||||
Assert.assertEquals(expected.toString(), result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRename01() throws Exception {
|
||||
// EDH -> DHE
|
||||
LinkedHashSet<Cipher> result =
|
||||
OpenSSLCipherConfigurationParser.parse("EXP-EDH-DSS-DES-CBC-SHA");
|
||||
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
|
||||
expected.add(Cipher.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomOrdering() throws Exception {
|
||||
// https://bz.apache.org/bugzilla/show_bug.cgi?id=59081
|
||||
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.parse(
|
||||
"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:" +
|
||||
"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DES-CBC3-SHA");
|
||||
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
|
||||
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
|
||||
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
|
||||
expected.add(Cipher.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
expected.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
|
||||
expected.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
|
||||
expected.add(Cipher.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
|
||||
Assert.assertEquals(expected.toString(), result.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.catalina.util.IOTools;
|
||||
|
||||
public class TesterOpenSSL {
|
||||
|
||||
public static final int VERSION;
|
||||
|
||||
public static final Set<Cipher> OPENSSL_UNIMPLEMENTED_CIPHERS;
|
||||
|
||||
public static final Map<String,String> OPENSSL_RENAMED_CIPHERS;
|
||||
|
||||
static {
|
||||
// Note: The following lists are intended to be aligned with the most
|
||||
// recent release of each OpenSSL release branch. Running the unit
|
||||
// tests with earlier releases is likely to result in failures.
|
||||
|
||||
String versionString = null;
|
||||
try {
|
||||
versionString = executeOpenSSLCommand("version");
|
||||
} catch (IOException e) {
|
||||
versionString = "";
|
||||
}
|
||||
if (versionString.startsWith("OpenSSL 3.0.0")) {
|
||||
// Note: Gump currently tests 9.0.x with OpenSSL master
|
||||
// (a.k.a 3.0.0-dev)
|
||||
VERSION = 30000;
|
||||
} else if (versionString.startsWith("OpenSSL 1.1.1")) {
|
||||
// LTS
|
||||
// Supported until at least 2023-09-11
|
||||
VERSION = 10101;
|
||||
} else if (versionString.startsWith("OpenSSL 1.1.0")) {
|
||||
// Support ends 2019-09-11
|
||||
VERSION = 10100;
|
||||
} else if (versionString.startsWith("OpenSSL 1.0.2")) {
|
||||
// LTS
|
||||
// Support ends 2019-12-31
|
||||
// Note: Gump current tests 8.5.x with OpenSSL 1.0.2
|
||||
VERSION = 10002;
|
||||
// Note: Release branches 1.0.1 and earlier are no longer supported by
|
||||
// the OpenSSL team so these tests don't support them either.
|
||||
} else {
|
||||
VERSION = -1;
|
||||
}
|
||||
|
||||
HashSet<Cipher> unimplemented = new HashSet<>();
|
||||
|
||||
// These have been removed from all supported versions.
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_MD5);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_EXPORT_WITH_RC4_40_MD5);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_DES_CBC_SHA);
|
||||
unimplemented.add(Cipher.SSL2_DES_64_CBC_WITH_MD5);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5);
|
||||
unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_RC4_40_MD5);
|
||||
unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5);
|
||||
unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_WITH_MD5);
|
||||
unimplemented.add(Cipher.SSL_CK_RC4_128_WITH_MD5);
|
||||
unimplemented.add(Cipher.SSL2_RC4_128_EXPORT40_WITH_MD5);
|
||||
unimplemented.add(Cipher.SSL2_IDEA_128_CBC_WITH_MD5);
|
||||
unimplemented.add(Cipher.SSL2_DES_192_EDE3_CBC_WITH_MD5);
|
||||
|
||||
// These are TLS v1.3 cipher suites
|
||||
// Java does not currently support these so they are excluded from the
|
||||
// testing.
|
||||
// Note: If OpenSSL is used then some of these may be available
|
||||
// depending on the OpenSSL version used and the defaults for that
|
||||
// version
|
||||
unimplemented.add(Cipher.TLS_AES_128_CCM_8_SHA256);
|
||||
unimplemented.add(Cipher.TLS_AES_128_CCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_CHACHA20_POLY1305_SHA256);
|
||||
|
||||
if (VERSION < 10100) {
|
||||
// These were implemented in 1.1.0 so won't be available in any
|
||||
// earlier version
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA384);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA384);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_AES_128_CCM);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_AES_256_CCM);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CCM);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CCM);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_AES_128_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_AES_256_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CCM);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CCM);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CCM);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CCM);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_PSK_DHE_WITH_AES_128_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_PSK_DHE_WITH_AES_256_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CCM);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256);
|
||||
} else {
|
||||
// These were removed in 1.1.0 so won't be available from that
|
||||
// version onwards.
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_DSS_WITH_SEED_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_RSA_WITH_SEED_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_NULL_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_NULL_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_RC4_128_MD5);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_WITH_RC4_128_MD5);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_anon_WITH_RC4_128_SHA);
|
||||
// 3DES requires a compile time switch to enable. Treat as removed.
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA);
|
||||
unimplemented.add(Cipher.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA);
|
||||
}
|
||||
|
||||
if (VERSION < 10101) {
|
||||
// These were implemented in 1.1.1 so won't be available in any
|
||||
// earlier version
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_PSK_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256);
|
||||
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384);
|
||||
}
|
||||
|
||||
String skipCiphers = System.getProperty("tomcat.test.openssl.unimplemented", "");
|
||||
if (!skipCiphers.isEmpty()) {
|
||||
String[] skip = skipCiphers.split(",");
|
||||
for (Cipher c : Cipher.values()) {
|
||||
for (String s : skip) {
|
||||
if (c.toString().contains(s)) {
|
||||
unimplemented.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OPENSSL_UNIMPLEMENTED_CIPHERS = Collections.unmodifiableSet(unimplemented);
|
||||
|
||||
Map<String,String> renamed = new HashMap<>();
|
||||
renamed.put("ECDH-ECDSA-RC4-SHA+SSLv3", "ECDH-ECDSA-RC4-SHA+TLSv1");
|
||||
renamed.put("ECDHE-ECDSA-NULL-SHA+SSLv3", "ECDHE-ECDSA-NULL-SHA+TLSv1");
|
||||
renamed.put("ECDHE-ECDSA-DES-CBC3-SHA+SSLv3", "ECDHE-ECDSA-DES-CBC3-SHA+TLSv1");
|
||||
renamed.put("ECDHE-ECDSA-AES128-SHA+SSLv3", "ECDHE-ECDSA-AES128-SHA+TLSv1");
|
||||
renamed.put("ECDHE-ECDSA-AES256-SHA+SSLv3", "ECDHE-ECDSA-AES256-SHA+TLSv1");
|
||||
renamed.put("ECDHE-RSA-NULL-SHA+SSLv3", "ECDHE-RSA-NULL-SHA+TLSv1");
|
||||
renamed.put("ECDHE-RSA-RC4-SHA+SSLv3", "ECDHE-RSA-RC4-SHA+TLSv1");
|
||||
renamed.put("ECDHE-RSA-DES-CBC3-SHA+SSLv3", "ECDHE-RSA-DES-CBC3-SHA+TLSv1");
|
||||
renamed.put("ECDHE-RSA-AES128-SHA+SSLv3", "ECDHE-RSA-AES128-SHA+TLSv1");
|
||||
renamed.put("ECDHE-RSA-AES256-SHA+SSLv3", "ECDHE-RSA-AES256-SHA+TLSv1");
|
||||
renamed.put("AECDH-NULL-SHA+SSLv3", "AECDH-NULL-SHA+TLSv1");
|
||||
renamed.put("AECDH-RC4-SHA+SSLv3", "AECDH-RC4-SHA+TLSv1");
|
||||
renamed.put("AECDH-DES-CBC3-SHA+SSLv3", "AECDH-DES-CBC3-SHA+TLSv1");
|
||||
renamed.put("AECDH-AES128-SHA+SSLv3", "AECDH-AES128-SHA+TLSv1");
|
||||
renamed.put("AECDH-AES256-SHA+SSLv3", "AECDH-AES256-SHA+TLSv1");
|
||||
renamed.put("ECDHE-PSK-RC4-SHA+SSLv3", "ECDHE-PSK-RC4-SHA+TLSv1");
|
||||
renamed.put("ECDHE-PSK-3DES-EDE-CBC-SHA+SSLv3", "ECDHE-PSK-3DES-EDE-CBC-SHA+TLSv1");
|
||||
renamed.put("ECDHE-PSK-AES128-CBC-SHA+SSLv3", "ECDHE-PSK-AES128-CBC-SHA+TLSv1");
|
||||
renamed.put("ECDHE-PSK-AES256-CBC-SHA+SSLv3", "ECDHE-PSK-AES256-CBC-SHA+TLSv1");
|
||||
renamed.put("ECDHE-PSK-NULL-SHA+SSLv3", "ECDHE-PSK-NULL-SHA+TLSv1");
|
||||
OPENSSL_RENAMED_CIPHERS = Collections.unmodifiableMap(renamed);
|
||||
}
|
||||
|
||||
|
||||
private TesterOpenSSL() {
|
||||
// Utility class. Hide default constructor.
|
||||
}
|
||||
|
||||
|
||||
public static Set<String> getOpenSSLCiphersAsSet(String specification) throws Exception {
|
||||
String[] ciphers = getOpenSSLCiphersAsExpression(specification).trim().split(":");
|
||||
Set<String> result = new HashSet<>(ciphers.length);
|
||||
for (String cipher : ciphers) {
|
||||
result.add(cipher);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String getOpenSSLCiphersAsExpression(String specification) throws Exception {
|
||||
|
||||
List<String> args = new ArrayList<>();
|
||||
// Standard command to list the ciphers
|
||||
args.add("ciphers");
|
||||
args.add("-v");
|
||||
if (VERSION < 10100) {
|
||||
// Need to exclude the GOST ciphers
|
||||
if (specification == null) {
|
||||
specification = "DEFAULT:!aGOST";
|
||||
} else {
|
||||
specification = "!aGOST:" + specification;
|
||||
}
|
||||
}
|
||||
if (VERSION >= 10101) {
|
||||
// Need to exclude the TLSv1.3 ciphers
|
||||
args.add("-ciphersuites");
|
||||
args.add("");
|
||||
}
|
||||
// Include the specification if provided
|
||||
if (specification != null) {
|
||||
args.add(specification);
|
||||
}
|
||||
|
||||
String stdout = executeOpenSSLCommand(args.toArray(new String[args.size()]));
|
||||
|
||||
if (stdout.length() == 0) {
|
||||
return stdout;
|
||||
}
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
boolean first = true;
|
||||
|
||||
// OpenSSL should have returned one cipher per line
|
||||
String ciphers[] = stdout.split("\n");
|
||||
for (String cipher : ciphers) {
|
||||
// Handle rename for 1.1.0 onwards
|
||||
cipher = cipher.replaceAll("EDH", "DHE");
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output.append(':');
|
||||
}
|
||||
StringBuilder name = new StringBuilder();
|
||||
|
||||
// Name is first part
|
||||
int i = cipher.indexOf(' ');
|
||||
name.append(cipher.substring(0, i));
|
||||
|
||||
// Advance i past the space
|
||||
while (Character.isWhitespace(cipher.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
|
||||
// Protocol is the second
|
||||
int j = cipher.indexOf(' ', i);
|
||||
name.append('+');
|
||||
name.append(cipher.substring(i, j));
|
||||
|
||||
// More renames
|
||||
if (OPENSSL_RENAMED_CIPHERS.containsKey(name.toString())) {
|
||||
output.append(OPENSSL_RENAMED_CIPHERS.get(name.toString()));
|
||||
} else {
|
||||
output.append(name.toString());
|
||||
}
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Use this method to filter parser results when comparing them to OpenSSL
|
||||
* results to take account of unimplemented cipher suites.
|
||||
*/
|
||||
public static void removeUnimplementedCiphersJsse(List<String> list) {
|
||||
for (Cipher cipher : OPENSSL_UNIMPLEMENTED_CIPHERS) {
|
||||
for (String jsseName : cipher.getJsseNames()) {
|
||||
list.remove(jsseName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static String executeOpenSSLCommand(String... args) throws IOException {
|
||||
String openSSLPath = System.getProperty("tomcat.test.openssl.path");
|
||||
String openSSLLibPath = null;
|
||||
if (openSSLPath == null || openSSLPath.length() == 0) {
|
||||
openSSLPath = "openssl";
|
||||
} else {
|
||||
// Explicit OpenSSL path may also need explicit lib path
|
||||
// (e.g. Gump needs this)
|
||||
openSSLLibPath = openSSLPath.substring(0, openSSLPath.lastIndexOf('/'));
|
||||
openSSLLibPath = openSSLLibPath + "/../lib";
|
||||
}
|
||||
List<String> cmd = new ArrayList<>();
|
||||
cmd.add(openSSLPath);
|
||||
for (String arg : args) {
|
||||
cmd.add(arg);
|
||||
}
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(cmd.toArray(new String[cmd.size()]));
|
||||
|
||||
if (openSSLLibPath != null) {
|
||||
Map<String,String> env = pb.environment();
|
||||
String libraryPath = env.get("LD_LIBRARY_PATH");
|
||||
if (libraryPath == null) {
|
||||
libraryPath = openSSLLibPath;
|
||||
} else {
|
||||
libraryPath = libraryPath + ":" + openSSLLibPath;
|
||||
}
|
||||
env.put("LD_LIBRARY_PATH", libraryPath);
|
||||
}
|
||||
|
||||
Process p = pb.start();
|
||||
|
||||
InputStreamToText stdout = new InputStreamToText(p.getInputStream());
|
||||
InputStreamToText stderr = new InputStreamToText(p.getErrorStream());
|
||||
|
||||
Thread t1 = new Thread(stdout);
|
||||
t1.setName("OpenSSL stdout reader");
|
||||
t1.start();
|
||||
|
||||
Thread t2 = new Thread(stderr);
|
||||
t2.setName("OpenSSL stderr reader");
|
||||
t2.start();
|
||||
|
||||
try {
|
||||
t1.join();
|
||||
t2.join();
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
String errorText = stderr.getText();
|
||||
if (errorText.length() > 0) {
|
||||
System.err.println(errorText);
|
||||
}
|
||||
|
||||
return stdout.getText().trim();
|
||||
}
|
||||
|
||||
private static class InputStreamToText implements Runnable {
|
||||
|
||||
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
private final InputStream is;
|
||||
|
||||
InputStreamToText(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
IOTools.flow(is, baos);
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return baos.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/org/apache/tomcat/util/net/user1.jks
Normal file
BIN
test/org/apache/tomcat/util/net/user1.jks
Normal file
Binary file not shown.
46
test/org/apache/tomcat/util/res/TestStringManager.java
Normal file
46
test/org/apache/tomcat/util/res/TestStringManager.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.res;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestStringManager {
|
||||
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.naming");
|
||||
|
||||
@Test
|
||||
public void testNullKey() {
|
||||
boolean iaeThrown = false;
|
||||
|
||||
try {
|
||||
sm.getString(null);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
iaeThrown = true;
|
||||
}
|
||||
Assert.assertTrue("IAE not thrown on null key", iaeThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug46933() {
|
||||
// Check null args are OK
|
||||
sm.getString("namingContext.nameNotBound");
|
||||
sm.getString("namingContext.nameNotBound", (Object[]) null);
|
||||
sm.getString("namingContext.nameNotBound", new Object[1]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.scan;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.util.IOTools;
|
||||
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
|
||||
import org.apache.tomcat.Jar;
|
||||
|
||||
public class TestAbstractInputStreamJar {
|
||||
|
||||
@Before
|
||||
public void register() {
|
||||
TomcatURLStreamHandlerFactory.register();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNestedJarGetInputStream() throws Exception {
|
||||
File f = new File("test/webresources/war-url-connection.war");
|
||||
StringBuilder sb = new StringBuilder("war:");
|
||||
sb.append(f.toURI().toURL());
|
||||
sb.append("*/WEB-INF/lib/test.jar");
|
||||
|
||||
Jar jar = JarFactory.newInstance(new URL(sb.toString()));
|
||||
|
||||
InputStream is1 = jar.getInputStream("META-INF/resources/index.html");
|
||||
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
|
||||
IOTools.flow(is1, baos1);
|
||||
|
||||
InputStream is2 = jar.getInputStream("META-INF/resources/index.html");
|
||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
IOTools.flow(is2, baos2);
|
||||
|
||||
Assert.assertArrayEquals(baos1.toByteArray(), baos2.toByteArray());
|
||||
}
|
||||
}
|
||||
46
test/org/apache/tomcat/util/scan/TestJarScanner.java
Normal file
46
test/org/apache/tomcat/util/scan/TestJarScanner.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.scan;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
|
||||
public class TestJarScanner extends TomcatBaseTest {
|
||||
|
||||
@Test
|
||||
public void testJarsToSkipFormat() {
|
||||
|
||||
String jarList = System.getProperty(Constants.SKIP_JARS_PROPERTY);
|
||||
Assert.assertNotNull("Jar skip list is null", jarList);
|
||||
Assert.assertFalse("Jar skip list is empty", jarList.isEmpty());
|
||||
StringTokenizer tokenizer = new StringTokenizer(jarList, ",");
|
||||
String token;
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
Assert.assertTrue("Token \"" + token + "\" does not end with \".jar\"",
|
||||
token.endsWith(".jar"));
|
||||
Assert.assertEquals("Token \"" + token + "\" contains sub string \".jar\"" +
|
||||
" or separator \",\" is missing",
|
||||
token.length() - ".jar".length(),
|
||||
token.indexOf(".jar"));
|
||||
}
|
||||
}
|
||||
}
|
||||
132
test/org/apache/tomcat/util/scan/TestStandardJarScanner.java
Normal file
132
test/org/apache/tomcat/util/scan/TestStandardJarScanner.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.scan;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.tomcat.Jar;
|
||||
import org.apache.tomcat.JarScanType;
|
||||
import org.apache.tomcat.JarScannerCallback;
|
||||
import org.apache.tomcat.unittest.TesterServletContext;
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
|
||||
public class TestStandardJarScanner {
|
||||
|
||||
@Test
|
||||
public void testWebappClassPath() {
|
||||
Assume.assumeFalse("No URLClassLoader with Java 9", JreCompat.isJre9Available());
|
||||
|
||||
StandardJarScanner scanner = new StandardJarScanner();
|
||||
|
||||
scanner.setScanClassPath(true);
|
||||
// When running the test on Java 9, one or more URLs to jimage files may
|
||||
// be returned. By setting the scanAllFiles option, a callback will be
|
||||
// generated for these files which in turn will mean the number of URLs
|
||||
// and the number of call backs will agree and this test will pass.
|
||||
// There is a TODO in StandardJarScanner to add 'proper' Java 9 support.
|
||||
scanner.setScanAllFiles(true);
|
||||
|
||||
LoggingCallback callback = new LoggingCallback();
|
||||
|
||||
scanner.scan(JarScanType.PLUGGABILITY, new TesterServletContext(), callback);
|
||||
|
||||
List<String> callbacks = callback.getCallbacks();
|
||||
|
||||
ClassLoader cl = TesterServletContext.class.getClassLoader();
|
||||
if (cl instanceof URLClassLoader) {
|
||||
URL[] urls = ((URLClassLoader) cl).getURLs();
|
||||
|
||||
int size;
|
||||
if (urls == null) {
|
||||
size = 0;
|
||||
} else {
|
||||
size = urls.length;
|
||||
}
|
||||
// Some JREs (Gump) construct a class path that includes JARs that
|
||||
// reference additional JARs via the Class-Path attribute of the
|
||||
// Manifest. These JARs are not returned in ClassLoader.getURLs().
|
||||
// Therefore, this test looks for at least as many JARs as there are
|
||||
// URLs but it can't check for an exact match.
|
||||
Assert.assertTrue("[" + callbacks.size() + "] callbacks but expected at least [" +
|
||||
size + "]", callbacks.size() >= size);
|
||||
|
||||
} else {
|
||||
Assert.fail("Unexpected class loader type: " + cl.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tomcat should ignore URLs which do not have a file part and do not use the file scheme.
|
||||
*/
|
||||
@Test
|
||||
public void skipsInvalidClasspathURLNoFilePartNoFileScheme() {
|
||||
StandardJarScanner scanner = new StandardJarScanner();
|
||||
LoggingCallback callback = new LoggingCallback();
|
||||
TesterServletContext context = new TesterServletContext() {
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
URLClassLoader urlClassLoader;
|
||||
try {
|
||||
urlClassLoader = new URLClassLoader(
|
||||
new URL[] { new URL("http://felix.extensions:9/") });
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return urlClassLoader;
|
||||
}
|
||||
};
|
||||
scanner.scan(JarScanType.PLUGGABILITY, context, callback);
|
||||
}
|
||||
|
||||
|
||||
private static class LoggingCallback implements JarScannerCallback {
|
||||
|
||||
List<String> callbacks = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void scan(Jar jar, String webappPath,
|
||||
boolean isWebapp) throws IOException {
|
||||
callbacks.add(jar.getJarFileURL().toString() + "::" + webappPath + "::" + isWebapp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(File file, String webappPath, boolean isWebapp)
|
||||
throws IOException {
|
||||
callbacks.add(file.toString() + "::" + webappPath + "::" + isWebapp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanWebInfClasses() throws IOException {
|
||||
callbacks.add("N/A::WEB-INF/classes::N/A");
|
||||
}
|
||||
|
||||
public List<String> getCallbacks() {
|
||||
return callbacks;
|
||||
}
|
||||
}
|
||||
}
|
||||
236
test/org/apache/tomcat/util/threads/TestLimitLatch.java
Normal file
236
test/org/apache/tomcat/util/threads/TestLimitLatch.java
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* http://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.apache.tomcat.util.threads;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestLimitLatch {
|
||||
|
||||
// This should be plenty of time, even on slow systems.
|
||||
private static final long THREAD_WAIT_TIME = 60000;
|
||||
|
||||
@Test
|
||||
public void testNoThreads() throws Exception {
|
||||
LimitLatch latch = new LimitLatch(0);
|
||||
Assert.assertFalse("No threads should be waiting", latch.hasQueuedThreads());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneThreadNoWait() throws Exception {
|
||||
LimitLatch latch = new LimitLatch(1);
|
||||
Object lock = new Object();
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
TestThread testThread = new TestThread(latch, lock);
|
||||
testThread.start();
|
||||
if (!waitForThreadToStart(testThread)) {
|
||||
Assert.fail("Test thread did not start");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
if (!waitForThreadToStop(testThread, lock)) {
|
||||
Assert.fail("Test thread did not stop");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneThreadWaitCountDown() throws Exception {
|
||||
LimitLatch latch = new LimitLatch(1);
|
||||
Object lock = new Object();
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
TestThread testThread = new TestThread(latch, lock);
|
||||
latch.countUpOrAwait();
|
||||
testThread.start();
|
||||
if (!waitForThreadToStart(testThread)) {
|
||||
Assert.fail("Test thread did not start");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 1);
|
||||
latch.countDown();
|
||||
if (!waitForThreadToStop(testThread, lock)) {
|
||||
Assert.fail("Test thread did not stop");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneRelease() throws Exception {
|
||||
LimitLatch latch = new LimitLatch(1);
|
||||
Object lock = new Object();
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
TestThread testThread = new TestThread(latch, lock);
|
||||
latch.countUpOrAwait();
|
||||
testThread.start();
|
||||
if (!waitForThreadToStart(testThread)) {
|
||||
Assert.fail("Test thread did not start");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 1);
|
||||
latch.releaseAll();
|
||||
if (!waitForThreadToStop(testThread, lock)) {
|
||||
Assert.fail("Test thread did not stop");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTenWait() throws Exception {
|
||||
LimitLatch latch = new LimitLatch(10);
|
||||
Object lock = new Object();
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
|
||||
TestThread[] testThreads = new TestThread[30];
|
||||
for (int i = 0; i < 30; i++) {
|
||||
testThreads[i] = new TestThread(latch, lock);
|
||||
testThreads[i].start();
|
||||
}
|
||||
|
||||
// Should have 10 threads in stage 2 and 20 in stage 1
|
||||
|
||||
for (int i = 0; i < 30; i++) {
|
||||
if (!waitForThreadToStart(testThreads[i])) {
|
||||
Assert.fail("Test thread [" + i + "] did not start");
|
||||
}
|
||||
}
|
||||
|
||||
if (!waitForThreadsToReachStage(testThreads, 20, 10, 0)) {
|
||||
Assert.fail("Failed at 20-10-00");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 20);
|
||||
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
|
||||
if (!waitForThreadsToReachStage(testThreads, 10, 10, 10)) {
|
||||
Assert.fail("Failed at 10-10-10");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 10);
|
||||
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
|
||||
if (!waitForThreadsToReachStage(testThreads, 0, 10, 20)) {
|
||||
Assert.fail("Failed at 00-10-20");
|
||||
}
|
||||
checkWaitingThreadCount(latch, 0);
|
||||
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
|
||||
if (!waitForThreadsToReachStage(testThreads, 0, 0, 30)) {
|
||||
Assert.fail("Failed at 00-00-30");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean waitForThreadToStart(TestThread t) throws InterruptedException {
|
||||
long wait = 0;
|
||||
while (t.getStage() == 0 && wait < THREAD_WAIT_TIME) {
|
||||
Thread.sleep(100);
|
||||
wait += 100;
|
||||
}
|
||||
return t.getStage() > 0;
|
||||
}
|
||||
|
||||
private boolean waitForThreadToStop(TestThread t, Object lock) throws InterruptedException {
|
||||
long wait = 0;
|
||||
while (t.getStage() < 3 && wait < THREAD_WAIT_TIME) {
|
||||
Thread.sleep(100);
|
||||
wait += 100;
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
return t.getStage() == 3;
|
||||
}
|
||||
|
||||
private void checkWaitingThreadCount(LimitLatch latch, int target) throws InterruptedException {
|
||||
long wait = 0;
|
||||
while (latch.getQueuedThreads().size() != target && wait < THREAD_WAIT_TIME) {
|
||||
Thread.sleep(100);
|
||||
wait += 100;
|
||||
}
|
||||
Assert.assertEquals(target, latch.getQueuedThreads().size());
|
||||
}
|
||||
|
||||
private boolean waitForThreadsToReachStage(TestThread[] testThreads,
|
||||
int stage1Target, int stage2Target, int stage3Target) throws InterruptedException {
|
||||
|
||||
long wait = 0;
|
||||
|
||||
int stage1 = 0;
|
||||
int stage2 = 0;
|
||||
int stage3 = 0;
|
||||
|
||||
while((stage1 != stage1Target || stage2 != stage2Target || stage3 != stage3Target) &&
|
||||
wait < THREAD_WAIT_TIME) {
|
||||
stage1 = 0;
|
||||
stage2 = 0;
|
||||
stage3 = 0;
|
||||
for (TestThread testThread : testThreads) {
|
||||
switch(testThread.getStage()){
|
||||
case 1:
|
||||
stage1++;
|
||||
break;
|
||||
case 2:
|
||||
stage2++;
|
||||
break;
|
||||
case 3:
|
||||
stage3++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Thread.sleep(100);
|
||||
wait += 100;
|
||||
}
|
||||
return stage1 == stage1Target && stage2 == stage2Target && stage3 == stage3Target;
|
||||
}
|
||||
|
||||
private static class TestThread extends Thread {
|
||||
|
||||
private final Object lock;
|
||||
private final LimitLatch latch;
|
||||
private volatile int stage = 0;
|
||||
|
||||
public TestThread(LimitLatch latch, Object lock) {
|
||||
this.latch = latch;
|
||||
this.lock = lock;
|
||||
}
|
||||
|
||||
public int getStage() {
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
stage = 1;
|
||||
latch.countUpOrAwait();
|
||||
stage = 2;
|
||||
if (lock != null) {
|
||||
synchronized (lock) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
latch.countDown();
|
||||
stage = 3;
|
||||
} catch (InterruptedException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user