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,42 @@
/*
* 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.http11.upgrade;
import javax.servlet.http.HttpUpgradeHandler;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
/**
* This Tomcat specific interface is implemented by handlers that require direct
* access to Tomcat's I/O layer rather than going through the Servlet API.
*/
public interface InternalHttpUpgradeHandler extends HttpUpgradeHandler {
SocketState upgradeDispatch(SocketEvent status);
void timeoutAsync(long now);
void setSocketWrapper(SocketWrapperBase<?> wrapper);
void setSslSupport(SSLSupport sslSupport);
void pause();
}

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=Failed to close InputStream cleanly after a previous error
upgrade.sis.isFinished.ise=It is illegal to call isFinished() when the ServletInputStream is not in non-blocking mode (i.e. setReadListener() must be called first)
upgrade.sis.isReady.ise=It is illegal to call isReady() when the ServletInputStream is not in non-blocking mode (i.e. setReadListener() must be called first)
upgrade.sis.onErrorFail=onError processing for the registered ReadListener triggered this further error which was swallowed
upgrade.sis.read.closed=The InputStream has been closed
upgrade.sis.read.ise=It is illegal to call any of the read() methods in non-blocking mode without first checking that there is data available by calling isReady()
upgrade.sis.readListener.null=It is illegal to pass null to setReadListener()
upgrade.sis.readListener.set=It is illegal to call setReadListener() more than once for the same upgraded connection
upgrade.sos.canWrite.ise=It is illegal to call canWrite() when the ServletOutputStream is not in non-blocking mode (i.e. setWriteListener() must be called first)
upgrade.sos.errorCloseFail=Failed to close OutputStream cleanly after a previous error
upgrade.sos.onErrorFail=onError processing for the registered WriteListener triggered this further error which was swallowed
upgrade.sos.write.closed=The OutputStream has been closed
upgrade.sos.write.ise=It is illegal to call any of the write() methods in non-blocking mode without first checking that there is space available by calling isReady()
upgrade.sos.writeListener.null=It is illegal to pass null to setWriteListener()
upgrade.sos.writeListener.set=It is illegal to call setWriteListener() more than once for the same upgraded connection
upgradeProcessor.isCloseFail=Failed to close input stream associated with upgraded connection
upgradeProcessor.osCloseFail=Failed to close output stream associated with upgraded connection
upgradeProcessor.requiredClose=Closing upgraded connection due to closeRequired state of streams: Input [{0}], Output [{1}]
upgradeProcessor.stop=Closing upgraded connection as incoming socket status was STOP
upgradeProcessor.unexpectedState=Closing upgraded connection unexpectedly as incoming socket status was [{0}]

View File

@@ -0,0 +1,18 @@
# 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.
upgrade.sis.read.closed=Der InputStream wurde geschlossen.
upgrade.sis.readListener.set=setReadListener() darf nicht mehr als einmal für eine Upgraded-Verbindung aufgerufen werden
upgrade.sos.writeListener.null=setWriteListener() darf nicht mit null aufgerufen werden

View File

@@ -0,0 +1,20 @@
# 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.
upgrade.sis.read.closed=El InputStream ha sido cerrado.
upgrade.sis.readListener.set=Es ilegal llamar a setReadListener() más de una vez para la misma conexión actualizada\n
upgrade.sos.writeListener.null=Es ilegal pasar valor nulo a setWriteListener()\n
upgradeProcessor.unexpectedState=Cerrando la conexión actualizada inesperadamente debido al que el estatus del socket fue [{0}]\n

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=Impossible de fermer l'InputStream proprement après une précédente erreur
upgrade.sis.isFinished.ise=Il est illégal d'appeler isFinished() quand le ServletInputStream n'est pas en mode non bloquant, c'est à dire que setReadListener() doit d'abord être appelé
upgrade.sis.isReady.ise=il est illégal d'appeler isReady() quand le ServletInputStream n'est pas en mode non bloquant, c'est à dire que setReadListener() doit d'abord être appelé
upgrade.sis.onErrorFail=Le traitement de onError pour le ReadListener configuré a causé cette erreur qui a été avalée
upgrade.sis.read.closed=Le flux d'entrée (InputStream) a été fermé
upgrade.sis.read.ise=Il est interdit d'appeler une des méthodes read() en mode non bloquant avant de d'abord vérifier qu'il y a des données disponibles en utilisant isReady()
upgrade.sis.readListener.null=Il est illégal de passer un argument null à setReadListener()
upgrade.sis.readListener.set=Il est interdit d'appeler setReadListener() plus d'une fois pour une même connection upgradée
upgrade.sos.canWrite.ise=il est illégal d'appeler canWrite() quand le ServletOutputStream n'est pas en mode non bloquant, c'est à dire que setWriteListener() doit d'abord être appelé
upgrade.sos.errorCloseFail=Impossible de fermer l'OutputStream proprement après une précédente erreur
upgrade.sos.onErrorFail=Le traitement de onError pour le WriteListener configuré a causé cette erreur qui a été avalée
upgrade.sos.write.closed=L'OutputSteam a été fermée
upgrade.sos.write.ise=Il est interdit d'appeler une des méthodes write() en mode non bloquant avant de d'abord vérifier qu'il y a de la place disponible en utilisant isReady()
upgrade.sos.writeListener.null=Il est illégal de passer un argument null à setWriteListener()
upgrade.sos.writeListener.set=Il est interdit d'appeler setWriteListener() plus d'une fois pour une même connection upgradée
upgradeProcessor.isCloseFail=Impossible de fermer l'InputStream associée avec la connection upgradée
upgradeProcessor.osCloseFail=Impossible de fermer l'OutputStream associée avec la connection upgradée
upgradeProcessor.requiredClose=Fermeture de la connection upgradée à cause de l''état du closeRequired des flux: Entrée [{0}] Sortie [{1}]
upgradeProcessor.stop=Fermeture de la connection upgradée car l'état du socket est STOP
upgradeProcessor.unexpectedState=Fermeture inattendue de la connection upgradée alors que le statut du socket en lecture est [{0}]

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=直前のエラーの後に完全にInputStreamを閉じることができませんでした。
upgrade.sis.isFinished.ise=ノンブロッキングモードではない ServletInputStream の isFinished() を呼び出すことはできません。(すなわち最初に setReadListener() を呼び出さなければなりません。)
upgrade.sis.isReady.ise=ServletInputStreamが非ブロッキングモードでない場合つまり、最初にsetReadListener()を呼び出さなければならない場合isReady()を呼び出すことはできません。
upgrade.sis.onErrorFail=登録されたReadListenerのonError処理により、さらなるエラーがトリガされました。エラーは飲み込まれました。
upgrade.sis.read.closed=InputStream はすでに切断されています。
upgrade.sis.read.ise=isReady()を呼び出すことによって利用可能なデータがあることを最初にチェックすることなく、非ブロックモードでread()メソッドを呼び出すことは不正です。
upgrade.sis.readListener.null=setReadListener() には null を指定できません。
upgrade.sis.readListener.set=アップグレードしたコネクションに何度も setReadListener() を呼び出すのは不正な操作です。
upgrade.sos.canWrite.ise=ServletOutputStreamが非ブロッキングモードでない場合つまり、setWriteListener()を最初に呼び出さなければならない場合、canWrite()を呼び出すことはできません。
upgrade.sos.errorCloseFail=以前のエラーの後にOutputStreamをきれいに閉じることができませんでした。
upgrade.sos.onErrorFail=登録されたWriteListenerのonError処理により、これがトリガされました。さらなるエラーは飲み込まれました。
upgrade.sos.write.closed=OutputStreamはクローズされました
upgrade.sos.write.ise=ノンブロッキングモードでは初めに isReady() を呼び出して利用可能な領域があることを確かめなければ、あらゆる write() メソッドの呼び出しは不正になります。
upgrade.sos.writeListener.null=setWriteListener() に null を渡すのは不正な操作です。
upgrade.sos.writeListener.set=同じアップグレードされたコネクションに対してsetWriteListener()を複数回呼び出すことはできません。
upgradeProcessor.isCloseFail=アップグレードされたコネクションに関連する入力ストリームを閉じることができませんでした。
upgradeProcessor.osCloseFail=アップグレードされた接続に関連する出力ストリームを閉じることができませんでした
upgradeProcessor.requiredClose=ストリームのcloseRequired状態によるアップグレードされた接続のクローズ入力[{0}]、出力[{1}]
upgradeProcessor.stop=到着したソケットステータスがSTOPであるためにアップグレードされたコネクションを閉じます。
upgradeProcessor.unexpectedState=ソケットの状態は [{0}] でしたがアップグレードしたコネクションは予期せぬ理由で切断しました。

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=이전 오류 발생 이후, InputStream을 깨끗하게 닫지 못했습니다.
upgrade.sis.isFinished.ise=ServletInputStream이 non-blocking 모드 안에 있지 않을 때, isFinished()를 호출하는 것은 불허됩니다. (즉, setReadListener()가 먼저 호출되어야만 합니다.)
upgrade.sis.isReady.ise=ServletInputStream이 non-blocking 모드 안에 있지 않을 때, isReady()를 호출하는 것은 불허됩니다. (즉 setReadListener()가 반드시 먼저 호출되어야 합니다.)
upgrade.sis.onErrorFail=등록된 ReadListener를 위한 onError 처리가 더많은 오류를 유발시켰습니다. 이 추가 오류는 별도로 표출되지 않습니다.
upgrade.sis.read.closed=InputStream은 이미 닫혀 있습니다.
upgrade.sis.read.ise=Non-blocking 모드에서는, 먼저 isReady()를 호출하여 가용한 데이터가 있는지 여부를 점검하지 않은 상태에서, 어떤 종류의 read() 메소드라도 호출하는 것은 불허됩니다.
upgrade.sis.readListener.null=setReadListener()에 널을 넘기는 것은 불허됩니다.
upgrade.sis.readListener.set=업그레이드된 동일한 연결을 위해, setReadListener()를 두 번 이상 호출하는 것은 불허됩니다.
upgrade.sos.canWrite.ise=ServletOutputStream이 non-blocking 모드 안에 있지 않을 때, canWrite()를 호출하는 것은 불허됩니다. (즉 setWriteListener()가 반드시 먼저 호출되어야 합니다.)
upgrade.sos.errorCloseFail=이전 오류 발생 이후, OutputStream을 깨끗하게 닫지 못했습니다.
upgrade.sos.onErrorFail=등록된 WriteListener를 위한 onError 처리가 이 오류를 더 유발시켰습니다. 이 추가 오류는 별도로 표출되지 않습니다.
upgrade.sos.write.closed=OutputStream이 이미 닫혀 있습니다.
upgrade.sos.write.ise=Non-blocking 모드에서는, 먼저 isReady()를 호출하여 공간이 남아있는지 점검하지 않고, 어떤 종류의 write() 메소드들을 호출하는 것은 불허됩니다.
upgrade.sos.writeListener.null=setWriteListener() 호출 시, 널을 넘기는 것은 불허됩니다.
upgrade.sos.writeListener.set=동일한 업그레이드된 연결에 대하여, setWriteListener()를 두번 이상 호출하는 것은 불허됩니다.
upgradeProcessor.isCloseFail=업그레이드된 연결과 연관된 입력 스트림을 닫지 못했습니다.
upgradeProcessor.osCloseFail=업그레이드된 연결과 연관된 출력 스트림을 닫지 못했습니다.
upgradeProcessor.requiredClose=스트림들의 closeRequired 상태로 인하여, 업그레이드된 연결을 닫습니다: 입력 [{0}], 출력 [{1}]
upgradeProcessor.stop=Incoming 소켓의 상태가 STOP임에 따라, 업그레이드된 연결을 닫습니다.
upgradeProcessor.unexpectedState=Incoming 소켓의 상태가 [{0}](이)라서, 업그레이드된 연결을 예기치 않게 종료합니다.

View File

@@ -0,0 +1,16 @@
# 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.
upgrade.sis.read.closed=InputStream был закрыт

View File

@@ -0,0 +1,26 @@
# 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.
upgrade.sis.isFinished.ise=当 ServletInputStream 不处于非阻塞模式时调用 isFinished() 是非法的(即必须首先调用 setReadListener()
upgrade.sis.onErrorFail=对注册的readlistener的错误处理触发了这个进一步的错误该错误被吞入
upgrade.sis.read.closed=InputStream 已被关闭
upgrade.sis.read.ise=在非阻塞模式下调用任何read()方法而不首先通过调用isready()检查是否有可用的数据是非法的
upgrade.sis.readListener.set=在同一个upgraded连接上调用多次setReadListener()函数是非法的
upgrade.sos.onErrorFail=对注册的WriteListener 的错误处理触发了这个进一步的错误,该错误被吞入
upgrade.sos.write.closed=输出流已被关闭
upgrade.sos.write.ise=在非阻塞模式下调用任何写()方法都是非法的而无需首先检查是否有可用的空间只需调用isreadi()
upgrade.sos.writeListener.null=对setWriteListener()传递null是非法的
upgradeProcessor.unexpectedState=因传入套接字状态为[{0}]而意外关闭升级连接

View File

@@ -0,0 +1,105 @@
/*
* 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.http11.upgrade;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.servlet.http.WebConnection;
import org.apache.coyote.AbstractProcessorLight;
import org.apache.coyote.Request;
import org.apache.coyote.UpgradeToken;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SocketWrapperBase;
public abstract class UpgradeProcessorBase extends AbstractProcessorLight implements WebConnection {
protected static final int INFINITE_TIMEOUT = -1;
private final UpgradeToken upgradeToken;
public UpgradeProcessorBase(UpgradeToken upgradeToken) {
this.upgradeToken = upgradeToken;
}
// ------------------------------------------- Implemented Processor methods
@Override
public final boolean isUpgrade() {
return true;
}
@Override
public UpgradeToken getUpgradeToken() {
return upgradeToken;
}
@Override
public final void recycle() {
// Currently a NO-OP as upgrade processors are not recycled.
}
// ---------------------------- Processor methods that are NO-OP for upgrade
@Override
public final SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException {
return null;
}
@Override
public final SocketState asyncPostProcess() {
return null;
}
@Override
public final boolean isAsync() {
return false;
}
@Override
public final Request getRequest() {
return null;
}
@Override
public ByteBuffer getLeftoverInput() {
return null;
}
@Override
public boolean checkAsyncTimeoutGeneration() {
return false;
}
// ----------------- Processor methods that are NO-OP by default for upgrade
@Override
public void timeoutAsync(long now) {
// NO-OP
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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.http11.upgrade;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import org.apache.coyote.UpgradeToken;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
public class UpgradeProcessorExternal extends UpgradeProcessorBase {
private static final Log log = LogFactory.getLog(UpgradeProcessorExternal.class);
private static final StringManager sm = StringManager.getManager(UpgradeProcessorExternal.class);
private final UpgradeServletInputStream upgradeServletInputStream;
private final UpgradeServletOutputStream upgradeServletOutputStream;
public UpgradeProcessorExternal(SocketWrapperBase<?> wrapper,
UpgradeToken upgradeToken) {
super(upgradeToken);
this.upgradeServletInputStream = new UpgradeServletInputStream(this, wrapper);
this.upgradeServletOutputStream = new UpgradeServletOutputStream(this, wrapper);
/*
* Leave timeouts in the hands of the upgraded protocol.
*/
wrapper.setReadTimeout(INFINITE_TIMEOUT);
wrapper.setWriteTimeout(INFINITE_TIMEOUT);
}
@Override
protected Log getLog() {
return log;
}
// --------------------------------------------------- AutoCloseable methods
@Override
public void close() throws Exception {
upgradeServletInputStream.close();
upgradeServletOutputStream.close();
}
// --------------------------------------------------- WebConnection methods
@Override
public ServletInputStream getInputStream() throws IOException {
return upgradeServletInputStream;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return upgradeServletOutputStream;
}
// ------------------------------------------- Implemented Processor methods
@Override
public final SocketState dispatch(SocketEvent status) {
if (status == SocketEvent.OPEN_READ) {
upgradeServletInputStream.onDataAvailable();
} else if (status == SocketEvent.OPEN_WRITE) {
upgradeServletOutputStream.onWritePossible();
} else if (status == SocketEvent.STOP) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgradeProcessor.stop"));
}
try {
upgradeServletInputStream.close();
} catch (IOException ioe) {
log.debug(sm.getString("upgradeProcessor.isCloseFail", ioe));
}
try {
upgradeServletOutputStream.close();
} catch (IOException ioe) {
log.debug(sm.getString("upgradeProcessor.osCloseFail", ioe));
}
return SocketState.CLOSED;
} else {
// Unexpected state
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgradeProcessor.unexpectedState"));
}
return SocketState.CLOSED;
}
if (upgradeServletInputStream.isClosed() &&
upgradeServletOutputStream.isClosed()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgradeProcessor.requiredClose",
Boolean.valueOf(upgradeServletInputStream.isClosed()),
Boolean.valueOf(upgradeServletOutputStream.isClosed())));
}
return SocketState.CLOSED;
}
return SocketState.UPGRADED;
}
// ----------------------------------------- Unimplemented Processor methods
@Override
public final void setSslSupport(SSLSupport sslSupport) {
// NO-OP
}
@Override
public void pause() {
// NOOP
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.http11.upgrade;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import org.apache.coyote.UpgradeToken;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
public class UpgradeProcessorInternal extends UpgradeProcessorBase {
private static final Log log = LogFactory.getLog(UpgradeProcessorInternal.class);
private final InternalHttpUpgradeHandler internalHttpUpgradeHandler;
public UpgradeProcessorInternal(SocketWrapperBase<?> wrapper,
UpgradeToken upgradeToken) {
super(upgradeToken);
this.internalHttpUpgradeHandler = (InternalHttpUpgradeHandler) upgradeToken.getHttpUpgradeHandler();
/*
* Leave timeouts in the hands of the upgraded protocol.
*/
wrapper.setReadTimeout(INFINITE_TIMEOUT);
wrapper.setWriteTimeout(INFINITE_TIMEOUT);
internalHttpUpgradeHandler.setSocketWrapper(wrapper);
}
@Override
public SocketState dispatch(SocketEvent status) {
return internalHttpUpgradeHandler.upgradeDispatch(status);
}
@Override
public final void setSslSupport(SSLSupport sslSupport) {
internalHttpUpgradeHandler.setSslSupport(sslSupport);
}
@Override
public void pause() {
internalHttpUpgradeHandler.pause();
}
@Override
protected Log getLog() {
return log;
}
@Override
public void timeoutAsync(long now) {
internalHttpUpgradeHandler.timeoutAsync(now);
}
// --------------------------------------------------- AutoCloseable methods
@Override
public void close() throws Exception {
internalHttpUpgradeHandler.destroy();
}
// --------------------------------------------------- WebConnection methods
@Override
public ServletInputStream getInputStream() throws IOException {
return null;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return null;
}
}

View File

@@ -0,0 +1,258 @@
/*
* 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.http11.upgrade;
import java.io.IOException;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import org.apache.coyote.ContainerThreadMarker;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.DispatchType;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
public class UpgradeServletInputStream extends ServletInputStream {
private static final Log log = LogFactory.getLog(UpgradeServletInputStream.class);
private static final StringManager sm =
StringManager.getManager(UpgradeServletInputStream.class);
private final UpgradeProcessorBase processor;
private final SocketWrapperBase<?> socketWrapper;
private volatile boolean closed = false;
private volatile boolean eof = false;
// Start in blocking-mode
private volatile Boolean ready = Boolean.TRUE;
private volatile ReadListener listener = null;
public UpgradeServletInputStream(UpgradeProcessorBase processor,
SocketWrapperBase<?> socketWrapper) {
this.processor = processor;
this.socketWrapper = socketWrapper;
}
@Override
public final boolean isFinished() {
if (listener == null) {
throw new IllegalStateException(
sm.getString("upgrade.sis.isFinished.ise"));
}
return eof;
}
@Override
public final boolean isReady() {
if (listener == null) {
throw new IllegalStateException(
sm.getString("upgrade.sis.isReady.ise"));
}
if (eof || closed) {
return false;
}
// If we already know the current state, return it.
if (ready != null) {
return ready.booleanValue();
}
try {
ready = Boolean.valueOf(socketWrapper.isReadyForRead());
} catch (IOException e) {
onError(e);
}
return ready.booleanValue();
}
@Override
public final void setReadListener(ReadListener listener) {
if (listener == null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sis.readListener.null"));
}
if (this.listener != null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sis.readListener.set"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sis.read.closed"));
}
this.listener = listener;
// Container is responsible for first call to onDataAvailable().
if (ContainerThreadMarker.isContainerThread()) {
processor.addDispatch(DispatchType.NON_BLOCKING_READ);
} else {
socketWrapper.registerReadInterest();
}
// Switching to non-blocking. Don't know if data is available.
ready = null;
}
@Override
public final int read() throws IOException {
preReadChecks();
return readInternal();
}
@Override
public final int readLine(byte[] b, int off, int len) throws IOException {
preReadChecks();
if (len <= 0) {
return 0;
}
int count = 0, c;
while ((c = readInternal()) != -1) {
b[off++] = (byte) c;
count++;
if (c == '\n' || count == len) {
break;
}
}
return count > 0 ? count : -1;
}
@Override
public final int read(byte[] b, int off, int len) throws IOException {
preReadChecks();
try {
int result = socketWrapper.read(listener == null, b, off, len);
if (result == -1) {
eof = true;
}
return result;
} catch (IOException ioe) {
close();
throw ioe;
}
}
@Override
public void close() throws IOException {
eof = true;
closed = true;
}
private void preReadChecks() {
if (listener != null && (ready == null || !ready.booleanValue())) {
throw new IllegalStateException(sm.getString("upgrade.sis.read.ise"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sis.read.closed"));
}
// No longer know if data is available
ready = null;
}
private int readInternal() throws IOException {
// Single byte reads for non-blocking need special handling so all
// single byte reads run through this method.
byte[] b = new byte[1];
int result;
try {
result = socketWrapper.read(listener == null, b, 0, 1);
} catch (IOException ioe) {
close();
throw ioe;
}
if (result == 0) {
return -1;
} else if (result == -1) {
eof = true;
return -1;
} else {
return b[0] & 0xFF;
}
}
final void onDataAvailable() {
try {
if (listener == null || !socketWrapper.isReadyForRead()) {
return;
}
} catch (IOException e) {
onError(e);
}
ready = Boolean.TRUE;
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
if (!eof) {
listener.onDataAvailable();
}
if (eof) {
listener.onAllDataRead();
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
onError(t);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
}
private final void onError(Throwable t) {
if (listener == null) {
return;
}
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
listener.onError(t);
} catch (Throwable t2) {
ExceptionUtils.handleThrowable(t2);
log.warn(sm.getString("upgrade.sis.onErrorFail"), t2);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
try {
close();
} catch (IOException ioe) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgrade.sis.errorCloseFail"), ioe);
}
}
ready = Boolean.FALSE;
}
final boolean isClosed() {
return closed;
}
}

View File

@@ -0,0 +1,282 @@
/*
* 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.http11.upgrade;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import org.apache.coyote.ContainerThreadMarker;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.DispatchType;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
public class UpgradeServletOutputStream extends ServletOutputStream {
private static final Log log = LogFactory.getLog(UpgradeServletOutputStream.class);
private static final StringManager sm =
StringManager.getManager(UpgradeServletOutputStream.class);
private final UpgradeProcessorBase processor;
private final SocketWrapperBase<?> socketWrapper;
// Used to ensure that isReady() and onWritePossible() have a consistent
// view of buffer and registered.
private final Object registeredLock = new Object();
// Used to ensure that only one thread writes to the socket at a time and
// that buffer is consistently updated with any unwritten data after the
// write. Note it is not necessary to hold this lock when checking if buffer
// contains data but, depending on how the result is used, some form of
// synchronization may be required (see fireListenerLock for an example).
private final Object writeLock = new Object();
private volatile boolean flushing = false;
private volatile boolean closed = false;
// Start in blocking-mode
private volatile WriteListener listener = null;
// Guarded by registeredLock
private boolean registered = false;
public UpgradeServletOutputStream(UpgradeProcessorBase processor,
SocketWrapperBase<?> socketWrapper) {
this.processor = processor;
this.socketWrapper = socketWrapper;
}
@Override
public final boolean isReady() {
if (listener == null) {
throw new IllegalStateException(
sm.getString("upgrade.sos.canWrite.ise"));
}
if (closed) {
return false;
}
// Make sure isReady() and onWritePossible() have a consistent view of
// fireListener when determining if the listener should fire
synchronized (registeredLock) {
if (flushing) {
// Since flushing is true the socket must already be registered
// for write and multiple registrations will cause problems.
registered = true;
return false;
} else if (registered){
// The socket is already registered for write and multiple
// registrations will cause problems.
return false;
} else {
boolean result = socketWrapper.isReadyForWrite();
registered = !result;
return result;
}
}
}
@Override
public final void setWriteListener(WriteListener listener) {
if (listener == null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sos.writeListener.null"));
}
if (this.listener != null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sos.writeListener.set"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sos.write.closed"));
}
this.listener = listener;
// Container is responsible for first call to onWritePossible().
synchronized (registeredLock) {
registered = true;
// Container is responsible for first call to onDataAvailable().
if (ContainerThreadMarker.isContainerThread()) {
processor.addDispatch(DispatchType.NON_BLOCKING_WRITE);
} else {
socketWrapper.registerWriteInterest();
}
}
}
final boolean isClosed() {
return closed;
}
@Override
public void write(int b) throws IOException {
synchronized (writeLock) {
preWriteChecks();
writeInternal(new byte[] { (byte) b }, 0, 1);
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
synchronized (writeLock) {
preWriteChecks();
writeInternal(b, off, len);
}
}
@Override
public void flush() throws IOException {
preWriteChecks();
flushInternal(listener == null, true);
}
private void flushInternal(boolean block, boolean updateFlushing) throws IOException {
try {
synchronized (writeLock) {
if (updateFlushing) {
flushing = socketWrapper.flush(block);
if (flushing) {
socketWrapper.registerWriteInterest();
}
} else {
socketWrapper.flush(block);
}
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
onError(t);
if (t instanceof IOException) {
throw (IOException) t;
} else {
throw new IOException(t);
}
}
}
@Override
public void close() throws IOException {
if (closed) {
return;
}
closed = true;
flushInternal((listener == null), false);
}
private void preWriteChecks() {
if (listener != null && !socketWrapper.canWrite()) {
throw new IllegalStateException(sm.getString("upgrade.sos.write.ise"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sos.write.closed"));
}
}
/**
* Must hold writeLock to call this method.
*/
private void writeInternal(byte[] b, int off, int len) throws IOException {
if (listener == null) {
// Simple case - blocking IO
socketWrapper.write(true, b, off, len);
} else {
socketWrapper.write(false, b, off, len);
}
}
final void onWritePossible() {
try {
if (flushing) {
flushInternal(false, true);
if (flushing) {
return;
}
} else {
// This may fill the write buffer in which case the
// isReadyForWrite() call below will re-register the socket for
// write
flushInternal(false, false);
}
} catch (IOException ioe) {
onError(ioe);
return;
}
// Make sure isReady() and onWritePossible() have a consistent view
// of buffer and fireListener when determining if the listener
// should fire
boolean fire = false;
synchronized (registeredLock) {
if (socketWrapper.isReadyForWrite()) {
registered = false;
fire = true;
} else {
registered = true;
}
}
if (fire) {
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
listener.onWritePossible();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
onError(t);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
}
}
private final void onError(Throwable t) {
if (listener == null) {
return;
}
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
listener.onError(t);
} catch (Throwable t2) {
ExceptionUtils.handleThrowable(t2);
log.warn(sm.getString("upgrade.sos.onErrorFail"), t2);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
try {
close();
} catch (IOException ioe) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgrade.sos.errorCloseFail"), ioe);
}
}
}
}