init
This commit is contained in:
423
java/org/apache/coyote/http2/Http2Protocol.java
Normal file
423
java/org/apache/coyote/http2/Http2Protocol.java
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* 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.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.coyote.Adapter;
|
||||
import org.apache.coyote.CompressionConfig;
|
||||
import org.apache.coyote.Processor;
|
||||
import org.apache.coyote.Request;
|
||||
import org.apache.coyote.Response;
|
||||
import org.apache.coyote.UpgradeProtocol;
|
||||
import org.apache.coyote.UpgradeToken;
|
||||
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
||||
import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler;
|
||||
import org.apache.coyote.http11.upgrade.UpgradeProcessorInternal;
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.apache.tomcat.util.net.SocketWrapperBase;
|
||||
|
||||
public class Http2Protocol implements UpgradeProtocol {
|
||||
|
||||
static final long DEFAULT_READ_TIMEOUT = 5000;
|
||||
static final long DEFAULT_WRITE_TIMEOUT = 5000;
|
||||
static final long DEFAULT_KEEP_ALIVE_TIMEOUT = 20000;
|
||||
static final long DEFAULT_STREAM_READ_TIMEOUT = 20000;
|
||||
static final long DEFAULT_STREAM_WRITE_TIMEOUT = 20000;
|
||||
// The HTTP/2 specification recommends a minimum default of 100
|
||||
static final long DEFAULT_MAX_CONCURRENT_STREAMS = 100;
|
||||
// Maximum amount of streams which can be concurrently executed over
|
||||
// a single connection
|
||||
static final int DEFAULT_MAX_CONCURRENT_STREAM_EXECUTION = 20;
|
||||
|
||||
static final int DEFAULT_OVERHEAD_COUNT_FACTOR = 1;
|
||||
static final int DEFAULT_OVERHEAD_CONTINUATION_THRESHOLD = 1024;
|
||||
static final int DEFAULT_OVERHEAD_DATA_THRESHOLD = 1024;
|
||||
static final int DEFAULT_OVERHEAD_WINDOW_UPDATE_THRESHOLD = 1024;
|
||||
|
||||
private static final String HTTP_UPGRADE_NAME = "h2c";
|
||||
private static final String ALPN_NAME = "h2";
|
||||
private static final byte[] ALPN_IDENTIFIER = ALPN_NAME.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// All timeouts in milliseconds
|
||||
// These are the socket level timeouts
|
||||
private long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
private long writeTimeout = DEFAULT_WRITE_TIMEOUT;
|
||||
private long keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
|
||||
// These are the stream level timeouts
|
||||
private long streamReadTimeout = DEFAULT_STREAM_READ_TIMEOUT;
|
||||
private long streamWriteTimeout = DEFAULT_STREAM_WRITE_TIMEOUT;
|
||||
|
||||
private long maxConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||
private int maxConcurrentStreamExecution = DEFAULT_MAX_CONCURRENT_STREAM_EXECUTION;
|
||||
// To advertise a different default to the client specify it here but DO NOT
|
||||
// change the default defined in ConnectionSettingsBase.
|
||||
private int initialWindowSize = ConnectionSettingsBase.DEFAULT_INITIAL_WINDOW_SIZE;
|
||||
// Limits
|
||||
private Set<String> allowedTrailerHeaders =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||
private int maxHeaderCount = Constants.DEFAULT_MAX_HEADER_COUNT;
|
||||
private int maxHeaderSize = Constants.DEFAULT_MAX_HEADER_SIZE;
|
||||
private int maxTrailerCount = Constants.DEFAULT_MAX_TRAILER_COUNT;
|
||||
private int maxTrailerSize = Constants.DEFAULT_MAX_TRAILER_SIZE;
|
||||
private int overheadCountFactor = DEFAULT_OVERHEAD_COUNT_FACTOR;
|
||||
private int overheadContinuationThreshold = DEFAULT_OVERHEAD_CONTINUATION_THRESHOLD;
|
||||
private int overheadDataThreshold = DEFAULT_OVERHEAD_DATA_THRESHOLD;
|
||||
private int overheadWindowUpdateThreshold = DEFAULT_OVERHEAD_WINDOW_UPDATE_THRESHOLD;
|
||||
|
||||
private boolean initiatePingDisabled = false;
|
||||
// Compression
|
||||
private final CompressionConfig compressionConfig = new CompressionConfig();
|
||||
// Reference to HTTP/1.1 protocol that this instance is configured under
|
||||
private AbstractHttp11Protocol<?> http11Protocol = null;
|
||||
|
||||
@Override
|
||||
public String getHttpUpgradeName(boolean isSSLEnabled) {
|
||||
if (isSSLEnabled) {
|
||||
return null;
|
||||
} else {
|
||||
return HTTP_UPGRADE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAlpnIdentifier() {
|
||||
return ALPN_IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlpnName() {
|
||||
return ALPN_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter) {
|
||||
UpgradeProcessorInternal processor = new UpgradeProcessorInternal(socketWrapper,
|
||||
new UpgradeToken(getInternalUpgradeHandler(adapter, null), null, null));
|
||||
return processor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InternalHttpUpgradeHandler getInternalUpgradeHandler(Adapter adapter,
|
||||
Request coyoteRequest) {
|
||||
Http2UpgradeHandler result = new Http2UpgradeHandler(this, adapter, coyoteRequest);
|
||||
|
||||
result.setReadTimeout(getReadTimeout());
|
||||
result.setKeepAliveTimeout(getKeepAliveTimeout());
|
||||
result.setWriteTimeout(getWriteTimeout());
|
||||
result.setMaxConcurrentStreams(getMaxConcurrentStreams());
|
||||
result.setMaxConcurrentStreamExecution(getMaxConcurrentStreamExecution());
|
||||
result.setInitialWindowSize(getInitialWindowSize());
|
||||
result.setAllowedTrailerHeaders(allowedTrailerHeaders);
|
||||
result.setMaxHeaderCount(getMaxHeaderCount());
|
||||
result.setMaxHeaderSize(getMaxHeaderSize());
|
||||
result.setMaxTrailerCount(getMaxTrailerCount());
|
||||
result.setMaxTrailerSize(getMaxTrailerSize());
|
||||
result.setInitiatePingDisabled(initiatePingDisabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(Request request) {
|
||||
// Should only be one HTTP2-Settings header
|
||||
Enumeration<String> settings = request.getMimeHeaders().values("HTTP2-Settings");
|
||||
int count = 0;
|
||||
while (settings.hasMoreElements()) {
|
||||
count++;
|
||||
settings.nextElement();
|
||||
}
|
||||
if (count != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration<String> connection = request.getMimeHeaders().values("Connection");
|
||||
boolean found = false;
|
||||
while (connection.hasMoreElements() && !found) {
|
||||
found = connection.nextElement().contains("HTTP2-Settings");
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
public long getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
|
||||
public void setReadTimeout(long readTimeout) {
|
||||
this.readTimeout = readTimeout;
|
||||
}
|
||||
|
||||
|
||||
public long getWriteTimeout() {
|
||||
return writeTimeout;
|
||||
}
|
||||
|
||||
|
||||
public void setWriteTimeout(long writeTimeout) {
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
|
||||
public long getKeepAliveTimeout() {
|
||||
return keepAliveTimeout;
|
||||
}
|
||||
|
||||
|
||||
public void setKeepAliveTimeout(long keepAliveTimeout) {
|
||||
this.keepAliveTimeout = keepAliveTimeout;
|
||||
}
|
||||
|
||||
|
||||
public long getStreamReadTimeout() {
|
||||
return streamReadTimeout;
|
||||
}
|
||||
|
||||
|
||||
public void setStreamReadTimeout(long streamReadTimeout) {
|
||||
this.streamReadTimeout = streamReadTimeout;
|
||||
}
|
||||
|
||||
|
||||
public long getStreamWriteTimeout() {
|
||||
return streamWriteTimeout;
|
||||
}
|
||||
|
||||
|
||||
public void setStreamWriteTimeout(long streamWriteTimeout) {
|
||||
this.streamWriteTimeout = streamWriteTimeout;
|
||||
}
|
||||
|
||||
|
||||
public long getMaxConcurrentStreams() {
|
||||
return maxConcurrentStreams;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxConcurrentStreams(long maxConcurrentStreams) {
|
||||
this.maxConcurrentStreams = maxConcurrentStreams;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxConcurrentStreamExecution() {
|
||||
return maxConcurrentStreamExecution;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxConcurrentStreamExecution(int maxConcurrentStreamExecution) {
|
||||
this.maxConcurrentStreamExecution = maxConcurrentStreamExecution;
|
||||
}
|
||||
|
||||
|
||||
public int getInitialWindowSize() {
|
||||
return initialWindowSize;
|
||||
}
|
||||
|
||||
|
||||
public void setInitialWindowSize(int initialWindowSize) {
|
||||
this.initialWindowSize = initialWindowSize;
|
||||
}
|
||||
|
||||
|
||||
public void setAllowedTrailerHeaders(String commaSeparatedHeaders) {
|
||||
// Jump through some hoops so we don't end up with an empty set while
|
||||
// doing updates.
|
||||
Set<String> toRemove = new HashSet<>();
|
||||
toRemove.addAll(allowedTrailerHeaders);
|
||||
if (commaSeparatedHeaders != null) {
|
||||
String[] headers = commaSeparatedHeaders.split(",");
|
||||
for (String header : headers) {
|
||||
String trimmedHeader = header.trim().toLowerCase(Locale.ENGLISH);
|
||||
if (toRemove.contains(trimmedHeader)) {
|
||||
toRemove.remove(trimmedHeader);
|
||||
} else {
|
||||
allowedTrailerHeaders.add(trimmedHeader);
|
||||
}
|
||||
}
|
||||
allowedTrailerHeaders.removeAll(toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getAllowedTrailerHeaders() {
|
||||
// Chances of a size change between these lines are small enough that a
|
||||
// sync is unnecessary.
|
||||
List<String> copy = new ArrayList<>(allowedTrailerHeaders.size());
|
||||
copy.addAll(allowedTrailerHeaders);
|
||||
return StringUtils.join(copy);
|
||||
}
|
||||
|
||||
|
||||
public void setMaxHeaderCount(int maxHeaderCount) {
|
||||
this.maxHeaderCount = maxHeaderCount;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxHeaderCount() {
|
||||
return maxHeaderCount;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxHeaderSize(int maxHeaderSize) {
|
||||
this.maxHeaderSize = maxHeaderSize;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxHeaderSize() {
|
||||
return maxHeaderSize;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxTrailerCount(int maxTrailerCount) {
|
||||
this.maxTrailerCount = maxTrailerCount;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxTrailerCount() {
|
||||
return maxTrailerCount;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxTrailerSize(int maxTrailerSize) {
|
||||
this.maxTrailerSize = maxTrailerSize;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxTrailerSize() {
|
||||
return maxTrailerSize;
|
||||
}
|
||||
|
||||
|
||||
public int getOverheadCountFactor() {
|
||||
return overheadCountFactor;
|
||||
}
|
||||
|
||||
|
||||
public void setOverheadCountFactor(int overheadCountFactor) {
|
||||
this.overheadCountFactor = overheadCountFactor;
|
||||
}
|
||||
|
||||
|
||||
public int getOverheadContinuationThreshold() {
|
||||
return overheadContinuationThreshold;
|
||||
}
|
||||
|
||||
|
||||
public void setOverheadContinuationThreshold(int overheadContinuationThreshold) {
|
||||
this.overheadContinuationThreshold = overheadContinuationThreshold;
|
||||
}
|
||||
|
||||
|
||||
public int getOverheadDataThreshold() {
|
||||
return overheadDataThreshold;
|
||||
}
|
||||
|
||||
|
||||
public void setOverheadDataThreshold(int overheadDataThreshold) {
|
||||
this.overheadDataThreshold = overheadDataThreshold;
|
||||
}
|
||||
|
||||
|
||||
public int getOverheadWindowUpdateThreshold() {
|
||||
return overheadWindowUpdateThreshold;
|
||||
}
|
||||
|
||||
|
||||
public void setOverheadWindowUpdateThreshold(int overheadWindowUpdateThreshold) {
|
||||
this.overheadWindowUpdateThreshold = overheadWindowUpdateThreshold;
|
||||
}
|
||||
|
||||
|
||||
public void setInitiatePingDisabled(boolean initiatePingDisabled) {
|
||||
this.initiatePingDisabled = initiatePingDisabled;
|
||||
}
|
||||
|
||||
|
||||
public void setCompression(String compression) {
|
||||
compressionConfig.setCompression(compression);
|
||||
}
|
||||
public String getCompression() {
|
||||
return compressionConfig.getCompression();
|
||||
}
|
||||
protected int getCompressionLevel() {
|
||||
return compressionConfig.getCompressionLevel();
|
||||
}
|
||||
|
||||
|
||||
public String getNoCompressionUserAgents() {
|
||||
return compressionConfig.getNoCompressionUserAgents();
|
||||
}
|
||||
protected Pattern getNoCompressionUserAgentsPattern() {
|
||||
return compressionConfig.getNoCompressionUserAgentsPattern();
|
||||
}
|
||||
public void setNoCompressionUserAgents(String noCompressionUserAgents) {
|
||||
compressionConfig.setNoCompressionUserAgents(noCompressionUserAgents);
|
||||
}
|
||||
|
||||
|
||||
public String getCompressibleMimeType() {
|
||||
return compressionConfig.getCompressibleMimeType();
|
||||
}
|
||||
public void setCompressibleMimeType(String valueS) {
|
||||
compressionConfig.setCompressibleMimeType(valueS);
|
||||
}
|
||||
public String[] getCompressibleMimeTypes() {
|
||||
return compressionConfig.getCompressibleMimeTypes();
|
||||
}
|
||||
|
||||
|
||||
public int getCompressionMinSize() {
|
||||
return compressionConfig.getCompressionMinSize();
|
||||
}
|
||||
public void setCompressionMinSize(int compressionMinSize) {
|
||||
compressionConfig.setCompressionMinSize(compressionMinSize);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public boolean getNoCompressionStrongETag() {
|
||||
return compressionConfig.getNoCompressionStrongETag();
|
||||
}
|
||||
@Deprecated
|
||||
public void setNoCompressionStrongETag(boolean noCompressionStrongETag) {
|
||||
compressionConfig.setNoCompressionStrongETag(noCompressionStrongETag);
|
||||
}
|
||||
|
||||
|
||||
public boolean useCompression(Request request, Response response) {
|
||||
return compressionConfig.useCompression(request, response);
|
||||
}
|
||||
|
||||
|
||||
public AbstractHttp11Protocol<?> getHttp11Protocol() {
|
||||
return this.http11Protocol;
|
||||
}
|
||||
public void setHttp11Protocol(AbstractHttp11Protocol<?> http11Protocol) {
|
||||
this.http11Protocol = http11Protocol;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user