You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2017/03/19 20:50:37 UTC
svn commit: r1787662 - in /tomcat/trunk:
java/org/apache/tomcat/util/http/parser/
test/org/apache/tomcat/util/http/parser/
Author: markt
Date: Sun Mar 19 20:50:36 2017
New Revision: 1787662
URL: http://svn.apache.org/viewvc?rev=1787662&view=rev
Log:
Expand the HttpParser to include Host header validation / port location extraction.
Note: This is not yet integrated into the request handling
Added:
tomcat/trunk/java/org/apache/tomcat/util/http/parser/Host.java (with props)
tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java (with props)
tomcat/trunk/test/org/apache/tomcat/util/http/parser/TesterHostPerformance.java (with props)
Modified:
tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
Added: tomcat/trunk/java/org/apache/tomcat/util/http/parser/Host.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/parser/Host.java?rev=1787662&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/parser/Host.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/parser/Host.java Sun Mar 19 20:50:36 2017
@@ -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.http.parser;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+public class Host {
+
+ /**
+ * Parse the given input as a HTTP Host header value.
+ *
+ * @param mb The host header value
+ *
+ * @return The position of ':' that separates the host from the port or -1
+ * if it is not present
+ *
+ * @throws IllegalArgumentException If the host header value is not
+ * specification compliant
+ *
+ * @throws IOException If a problem occurs reading the data from the input
+ */
+ public static int parse(MessageBytes mb) throws IOException {
+ return parse(new MessageBytesReader(mb));
+ }
+
+
+ /**
+ * Parse the given input as a HTTP Host header value.
+ *
+ * @param string The host header value
+ *
+ * @return The position of ':' that separates the host from the port or -1
+ * if it is not present
+ *
+ * @throws IllegalArgumentException If the host header value is not
+ * specification compliant
+ *
+ * @throws IOException If a problem occurs reading the data from the input
+ */
+ public static int parse(String string) throws IOException {
+ return parse(new StringReader(string));
+ }
+
+
+ private static int parse(Reader reader) throws IOException {
+ reader.mark(1);
+ int first = reader.read();
+ reader.reset();
+ if (HttpParser.isAlpha(first)) {
+ return HttpParser.readHostDomainName(reader);
+ } else if (HttpParser.isNumeric(first)) {
+ return HttpParser.readHostIPv4(reader, false);
+ } else if ('[' == first) {
+ return HttpParser.readHostIPv6(reader);
+ } else {
+ // Invalid
+ throw new IllegalArgumentException();
+ }
+ }
+
+
+ private static class MessageBytesReader extends Reader {
+
+ private final byte[] bytes;
+ private final int end;
+ private int pos;
+ private int mark;
+
+ public MessageBytesReader(MessageBytes mb) {
+ ByteChunk bc = mb.getByteChunk();
+ bytes = bc.getBytes();
+ pos = bc.getOffset();
+ end = bc.getEnd();
+ }
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ for (int i = off; i < off + len; i++) {
+ cbuf[i] = (char) bytes[pos++];
+ }
+ return len;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // NO-OP
+ }
+
+ // Over-ridden methods to improve performance
+
+ @Override
+ public int read() throws IOException {
+ if (pos < end) {
+ return bytes[pos++];
+ } else {
+ return -1;
+ }
+ }
+
+ // Methods to support mark/reset
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public void mark(int readAheadLimit) throws IOException {
+ mark = pos;
+ }
+
+ @Override
+ public void reset() throws IOException {
+ pos = mark;
+ }
+ }
+}
Propchange: tomcat/trunk/java/org/apache/tomcat/util/http/parser/Host.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java?rev=1787662&r1=1787661&r2=1787662&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java Sun Mar 19 20:50:36 2017
@@ -17,7 +17,7 @@
package org.apache.tomcat.util.http.parser;
import java.io.IOException;
-import java.io.StringReader;
+import java.io.Reader;
/**
* HTTP header value parser implementation. Parsing HTTP headers as per RFC2616
@@ -42,6 +42,8 @@ public class HttpParser {
private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];
+ private static final boolean[] IS_ALPHA = new boolean[ARRAY_SIZE];
+ private static final boolean[] IS_NUMERIC = new boolean[ARRAY_SIZE];
static {
for (int i = 0; i < ARRAY_SIZE; i++) {
@@ -82,6 +84,14 @@ public class HttpParser {
if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
IS_HTTP_PROTOCOL[i] = true;
}
+
+ if (i >= '0' && i <= '9') {
+ IS_NUMERIC[i] = true;
+ }
+
+ if (i >= 'a' && i <= 'z' || i >= 'A' && i <= 'Z') {
+ IS_ALPHA[i] = true;
+ }
}
}
@@ -159,8 +169,30 @@ public class HttpParser {
}
+ public static boolean isAlpha(int c) {
+ // Fast for valid alpha characters, slower for some incorrect
+ // ones
+ try {
+ return IS_ALPHA[c];
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ return false;
+ }
+ }
+
+
+ public static boolean isNumeric(int c) {
+ // Fast for valid numeric characters, slower for some incorrect
+ // ones
+ try {
+ return IS_NUMERIC[c];
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ return false;
+ }
+ }
+
+
// Skip any LWS and return the next char
- static int skipLws(StringReader input, boolean withReset) throws IOException {
+ static int skipLws(Reader input, boolean withReset) throws IOException {
if (withReset) {
input.mark(1);
@@ -180,7 +212,7 @@ public class HttpParser {
return c;
}
- static SkipResult skipConstant(StringReader input, String constant) throws IOException {
+ static SkipResult skipConstant(Reader input, String constant) throws IOException {
int len = constant.length();
int c = skipLws(input, false);
@@ -205,7 +237,7 @@ public class HttpParser {
* available to read or <code>null</code> if data other than a
* token was found
*/
- static String readToken(StringReader input) throws IOException {
+ static String readToken(Reader input) throws IOException {
StringBuilder result = new StringBuilder();
int c = skipLws(input, false);
@@ -229,7 +261,7 @@ public class HttpParser {
* quoted string was found or null if the end of data was reached
* before the quoted string was terminated
*/
- static String readQuotedString(StringReader input, boolean returnQuoted) throws IOException {
+ static String readQuotedString(Reader input, boolean returnQuoted) throws IOException {
int c = skipLws(input, false);
@@ -264,7 +296,7 @@ public class HttpParser {
return result.toString();
}
- static String readTokenOrQuotedString(StringReader input, boolean returnQuoted)
+ static String readTokenOrQuotedString(Reader input, boolean returnQuoted)
throws IOException {
// Go back so first non-LWS character is available to be read again
@@ -289,7 +321,7 @@ public class HttpParser {
* quoted token was found or null if the end of data was reached
* before a quoted token was terminated
*/
- static String readQuotedToken(StringReader input) throws IOException {
+ static String readQuotedToken(Reader input) throws IOException {
StringBuilder result = new StringBuilder();
boolean quoted = false;
@@ -340,7 +372,7 @@ public class HttpParser {
* @return the sequence of LHEX (minus any surrounding quotes) if any was
* found, or <code>null</code> if data other LHEX was found
*/
- static String readLhex(StringReader input) throws IOException {
+ static String readLhex(Reader input) throws IOException {
StringBuilder result = new StringBuilder();
boolean quoted = false;
@@ -383,7 +415,7 @@ public class HttpParser {
}
}
- static double readWeight(StringReader input, char delimiter) throws IOException {
+ static double readWeight(Reader input, char delimiter) throws IOException {
int c = skipLws(input, false);
if (c == -1 || c == delimiter) {
// No q value just whitespace
@@ -447,10 +479,177 @@ public class HttpParser {
/**
+ * @return If inIPv6 us false, the position of ':' that separates the host
+ * from the port or -1 if it is not present. If inIPv6 is true, the
+ * number of characters read
+ */
+ static int readHostIPv4(Reader reader, boolean inIPv6) throws IOException {
+ int octect = -1;
+ int octectCount = 1;
+ int c;
+ int pos = 0;
+
+ do {
+ c = reader.read();
+ if (c == '.') {
+ if (octect > -1 && octect < 256) {
+ // Valid
+ octectCount++;
+ octect = -1;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else if (isNumeric(c)) {
+ if (octect == -1) {
+ octect = c - '0';
+ } else {
+ octect = octect * 10 + c - '0';
+ }
+ } else if (c == ':') {
+ break;
+ } else if (c == -1) {
+ if (inIPv6) {
+ throw new IllegalArgumentException();
+ } else {
+ pos = -1;
+ break;
+ }
+ } else if (c == ']') {
+ if (inIPv6) {
+ pos++;
+ break;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ pos++;
+ } while (true);
+
+ if (octectCount != 4) {
+ throw new IllegalArgumentException();
+ }
+ if (octect < 0 || octect > 255) {
+ throw new IllegalArgumentException();
+ }
+
+ return pos;
+ }
+
+
+ /**
+ * @return The position of ':' that separates the host from the port or -1
+ * if it is not present
+ */
+ static int readHostIPv6(Reader reader) throws IOException {
+ // Must start with '['
+ int c = reader.read();
+ if (c != '[') {
+ throw new IllegalArgumentException();
+ }
+
+ int h16Count = 0;
+ int h16Size = 0;
+ int pos = 1;
+ boolean parsedDoubleColon = false;
+ boolean previousWasColon = false;
+
+ do {
+ c = reader.read();
+ if (h16Count == 0 && previousWasColon && c != ':') {
+ // Can't start with a single :
+ throw new IllegalArgumentException();
+ }
+ if (HttpParser.isHex(c)) {
+ if (h16Size == 0) {
+ // Start of a new h16 block
+ previousWasColon = false;
+ h16Count++;
+ reader.mark(4);
+ }
+ h16Size++;
+ if (h16Size > 4) {
+ throw new IllegalArgumentException();
+ }
+ } else if (c == ':') {
+ if (previousWasColon) {
+ // End of ::
+ if (parsedDoubleColon) {
+ // Only allowed one :: sequence
+ throw new IllegalArgumentException();
+ }
+ parsedDoubleColon = true;
+ previousWasColon = false;
+ // :: represents at least one h16 block
+ h16Count++;
+ } else {
+ previousWasColon = true;
+ }
+ h16Size = 0;
+ } else if (c == ']') {
+ if (previousWasColon) {
+ // Can't end on a single ':'
+ throw new IllegalArgumentException();
+ }
+ break;
+ } else if (c == '.') {
+ if (h16Count == 7 || h16Count < 7 && parsedDoubleColon) {
+ reader.reset();
+ pos -= h16Size;
+ pos += readHostIPv4(reader, true);
+ h16Count++;
+ break;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ pos++;
+ } while (true);
+
+ if (h16Count > 8) {
+ throw new IllegalArgumentException();
+ } else if (h16Count != 8 && !parsedDoubleColon) {
+ throw new IllegalArgumentException();
+ }
+
+ c = reader.read();
+ if (c == ':') {
+ return pos + 1;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * @return The position of ':' that separates the host from the port or -1
+ * if it is not present
+ */
+ static int readHostDomainName(Reader reader) throws IOException {
+ DomainParseState state = DomainParseState.NEW;
+ int pos = 0;
+
+ while (state.mayContinue()) {
+ state = state.next(reader.read());
+ pos++;
+ }
+
+ if (DomainParseState.COLON == state) {
+ // State identifies the state of the previous character
+ return pos - 1;
+ } else {
+ return -1;
+ }
+ }
+
+
+ /**
* Skips all characters until EOF or the specified target is found. Normally
* used to skip invalid input until the next separator.
*/
- static SkipResult skipUntil(StringReader input, int c, char target) throws IOException {
+ static SkipResult skipUntil(Reader input, int c, char target) throws IOException {
while (c != -1 && c != target) {
c = input.read();
}
@@ -460,4 +659,74 @@ public class HttpParser {
return SkipResult.FOUND;
}
}
+
+
+ private static enum DomainParseState {
+ NEW( true, false, false, false, false, false),
+ ALPHA( true, true, true, true, true, true),
+ NUMERIC( true, true, true, true, true, true),
+ PERIOD( true, false, false, false, true, true),
+ HYPHEN( true, true, true, false, false, false),
+ COLON( false, false, false, false, false, false),
+ END( false, false, false, false, false, false);
+
+ private final boolean mayContinue;
+ private final boolean allowsNumeric;
+ private final boolean allowsHyphen;
+ private final boolean allowsPeriod;
+ private final boolean allowsColon;
+ private final boolean allowsEnd;
+
+ private DomainParseState(boolean mayContinue, boolean allowsNumeric, boolean allowsHyphen,
+ boolean allowsPeriod, boolean allowsColon, boolean allowsEnd) {
+ this.mayContinue = mayContinue;
+ this.allowsNumeric = allowsNumeric;
+ this.allowsHyphen = allowsHyphen;
+ this.allowsPeriod = allowsPeriod;
+ this.allowsColon = allowsColon;
+ this.allowsEnd = allowsEnd;
+ }
+
+ public boolean mayContinue() {
+ return mayContinue;
+ }
+
+ public DomainParseState next(int c) {
+ if (HttpParser.isAlpha(c)) {
+ return ALPHA;
+ } else if (HttpParser.isNumeric(c)) {
+ if (allowsNumeric) {
+ return NUMERIC;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else if (c == '.') {
+ if (allowsPeriod) {
+ return PERIOD;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else if (c == ':') {
+ if (allowsColon) {
+ return COLON;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else if (c == -1) {
+ if (allowsEnd) {
+ return END;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else if (c == '-') {
+ if (allowsHyphen) {
+ return HYPHEN;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
}
Added: tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java?rev=1787662&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java Sun Mar 19 20:50:36 2017
@@ -0,0 +1,178 @@
+/*
+ * 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
+ 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", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.IPv4, "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.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, "256.0.0.0", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.IPv4, "0.256.0.0", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.IPv4, "0.0.256.0", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.IPv4, "0.0.0.256", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.IPv4, "0.a.0.0", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.IPv4, "0..0.0", Integer.valueOf(-1), IAE} );
+ // Domain Name - valid
+ result.add(new Object[] { TestType.DOMAIN_NAME, "localhost", Integer.valueOf(-1), null} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "localhost:8080", Integer.valueOf(9), null} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "tomcat.apache.org", Integer.valueOf(-1), null} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "tomcat.apache.org:8080", Integer.valueOf(17), null} );
+ // Domain Name - invalid
+ result.add(new Object[] { TestType.DOMAIN_NAME, ".foo.bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "2foo.bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "-foo.bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "^foo.bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "foo-.bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "f*oo.bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "foo..bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "foo.2bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "foo.-bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "foo.^bar", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "foo.bar-", Integer.valueOf(-1), IAE} );
+ result.add(new Object[] { TestType.DOMAIN_NAME, "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} );
+ // 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, "[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} );
+ 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;
+ case DOMAIN_NAME:
+ result = HttpParser.readHostDomainName(sr);
+ break;
+
+ }
+ } catch (Exception e) {
+ exceptionClass = e.getClass();
+ }
+ Assert.assertEquals(input, expectedResult.intValue(), result);
+ if (expectedException == null) {
+ Assert.assertNull(input, exceptionClass);
+ } else {
+ Assert.assertTrue(input, expectedException.isAssignableFrom(exceptionClass));
+ }
+ }
+
+
+ private static enum TestType {
+ IPv4,
+ IPv6,
+ DOMAIN_NAME
+ }
+}
Propchange: tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: tomcat/trunk/test/org/apache/tomcat/util/http/parser/TesterHostPerformance.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/parser/TesterHostPerformance.java?rev=1787662&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/http/parser/TesterHostPerformance.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/util/http/parser/TesterHostPerformance.java Sun Mar 19 20:50:36 2017
@@ -0,0 +1,75 @@
+/*
+ * 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[] { "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");
+ }
+}
Propchange: tomcat/trunk/test/org/apache/tomcat/util/http/parser/TesterHostPerformance.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org