blob: 1a99c3ab416720212d97f4d02b5f4d42ef3880bf [file] [log] [blame]
/*
* 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.coyote.http2;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.util.ServerInfo;
import org.apache.catalina.valves.ErrorReportValve;
import org.apache.tomcat.util.res.StringManager;
public class TestHttp2InitialConnection extends Http2TestBase {
private TestData testData;
@Test
public void testValidHostHeader() throws Exception {
List<String> hostHeaders = new ArrayList<>(1);
hostHeaders.add("localhost:8080");
testData = new TestData(hostHeaders, 200);
http2Connect();
}
@Test
public void testMultipleHostHeaders() throws Exception {
List<String> hostHeaders = new ArrayList<>(1);
hostHeaders.add("localhost:8080");
hostHeaders.add("localhost:8081");
testData = new TestData(hostHeaders, 400);
http2Connect();
}
@Test
public void testNoHostHeader() throws Exception {
List<String> hostHeaders = new ArrayList<>(1);
testData = new TestData(hostHeaders, 400);
http2Connect();
}
@Override
protected void doHttpUpgrade(String connection, String upgrade, String settings,
boolean validate) throws IOException {
StringBuilder request = new StringBuilder();
request.append("GET /simple HTTP/1.1\r\n");
for (String hostHeader : testData.getHostHeaders()) {
request.append("Host: ");
request.append(hostHeader);
request.append("\r\n");
}
// Connection
request.append("Connection: ");
request.append(connection);
request.append("\r\n");
// Upgrade
request.append("Upgrade: ");
request.append(upgrade);
request.append("\r\n");
// Settings
request.append(settings);
// Locale - Force the en Locale else the i18n on the error page changes
// the size of the response body and that triggers a failure as the test
// checks the exact response length
request.append("Accept-Language: en\r\n");
// Request terminator
request.append("\r\n");
byte[] upgradeRequest = request.toString().getBytes(StandardCharsets.ISO_8859_1);
os.write(upgradeRequest);
os.flush();
if (validate) {
Assert.assertTrue("Failed to read HTTP Upgrade response",
readHttpUpgradeResponse());
}
}
@Override
protected String getResponseBodyFrameTrace(int streamId, String body) {
if (testData.getExpectedStatus() == 200) {
return super.getResponseBodyFrameTrace(streamId, body);
} else if (testData.getExpectedStatus() == 400) {
/*
* Need to be careful here. The test wants the exact content length
* in bytes.
* This will vary depending on where the test is run due to:
* - The length of the version string that appears once in the error
* page
* - The status header uses a UTF-8 EN dash. When running in an IDE
* the UTF-8 properties files will be used directly rather than
* after native2ascii conversion.
*
* Note: The status header appears twice in the error page.
*/
int serverInfoLength = ServerInfo.getServerInfo().getBytes().length;
StringManager sm = StringManager.getManager(
ErrorReportValve.class.getPackage().getName(), Locale.ENGLISH);
String reason = sm.getString("http." + testData.getExpectedStatus() + ".reason");
int descriptionLength = sm.getString("http." + testData.getExpectedStatus() + ".desc")
.getBytes(StandardCharsets.UTF_8).length;
int statusHeaderLength = sm
.getString("errorReportValve.statusHeader",
String.valueOf(testData.getExpectedStatus()), reason)
.getBytes(StandardCharsets.UTF_8).length;
int typeLabelLength = sm.getString("errorReportValve.type")
.getBytes(StandardCharsets.UTF_8).length;
int statusReportLabelLength = sm.getString("errorReportValve.statusReport")
.getBytes(StandardCharsets.UTF_8).length;
int descriptionLabelLength = sm.getString("errorReportValve.description")
.getBytes(StandardCharsets.UTF_8).length;
// 196 bytes is the static length of the pure HTML code from the ErrorReportValve
int len = 196 + org.apache.catalina.util.TomcatCSS.TOMCAT_CSS
.getBytes(StandardCharsets.UTF_8).length +
typeLabelLength + statusReportLabelLength + descriptionLabelLength +
descriptionLength + serverInfoLength + statusHeaderLength * 2;
String contentLength = String.valueOf(len);
return getResponseBodyFrameTrace(streamId,
testData.getExpectedStatus(), "text/html;charset=utf-8",
"en", contentLength, contentLength);
} else {
Assert.fail();
// To keep the IDE happy
return null;
}
}
private static class TestData {
private final List<String> hostHeaders;
private final int expectedStatus;
public TestData(List<String> hostHeaders, int expectedStatus) {
this.hostHeaders = hostHeaders;
this.expectedStatus = expectedStatus;
}
public List<String> getHostHeaders() {
return hostHeaders;
}
public int getExpectedStatus() {
return expectedStatus;
}
}
}