This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View 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;
}

View 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();
}
}
}

View 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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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");
}
}
}

View 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());
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View 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.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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}
}

View 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());
}
}

View 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;
}
}
}

View 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();
}
}
}
}

View 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.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));
}
}

View 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;
}
}
}

View 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);
}
}

View 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 ");
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View 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);
}
}

View File

@@ -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"));
}
}

View 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));
}
}

View 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
}
}

View 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"));
}
}

View 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);
}
}

View 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.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");
}
}