init
This commit is contained in:
@@ -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();
|
||||
}
|
||||
@@ -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}]
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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}]
|
||||
@@ -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}] でしたがアップグレードしたコネクションは予期せぬ理由で切断しました。
|
||||
@@ -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}](이)라서, 업그레이드된 연결을 예기치 않게 종료합니다.
|
||||
@@ -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 был закрыт
|
||||
@@ -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}]而意外关闭升级连接
|
||||
105
java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java
Normal file
105
java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user