java - cve - apache tomcat
¿Qué son los errores de hilos que no son contenedores en tomcat? (2)
En el registro catalina.out
de mi Tomcat7
un error causado por una biblioteca de terceros que comienza con:
INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
¿Qué significa realmente que el error ocurrió en un hilo no contenedor ?
Intenté obtener un mensaje de registro similar arrojando una excepción de un nuevo Thread
generado a partir de mi código de aplicación con algo así:
new Thread(){
@Override
public void run() {
Integer.parseInt("boom");
}
}.start();
pero resulta en
Exception in thread "Thread-28" java.lang.NumberFormatException: For input string: "boom"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at ...
Entonces la pregunta es: ¿qué significa cuando veo un registro como el que se cita en la parte superior? ¿Qué significa que el error ocurre en un hilo no contenedor ? ¿Cómo puedo recrear eso?
¿Qué significa realmente que el error ocurrió en un hilo no contenedor?
Esto sucede cuando está utilizando el procesamiento de solicitud asíncrono JSP 3.0+.
En el modo asíncrono, la solicitud del cliente se recibe mediante un hilo "contenedor" que llama al método service()
del Servlet. Este método (o uno de los métodos doXxxx
secundarios) llama a startAsync()
que crea un Runnable
para la solicitud y lo envía a un ejecutor. Este ejecutor luego procesa las solicitudes en hilos de trabajo ("sin contenedor").
(Puede encontrar una explicación más detallada de lo que está sucediendo en modo asíncrono, con un ejemplo).
De todos modos, el mensaje "INFO:" simplemente dice que la excepción original fue lanzada en la pila de uno de los hilos de trabajo del Ejecutor. Se produce cuando Tomcat decide enviar la solicitud fallida a un hilo contenedor para que se pueda realizar la limpieza de solicitud.
En su ejemplo, sospecho que la SocketException
original fue causada por el proceso de solicitud que tomó tanto tiempo que el cliente (por ejemplo, el navegador del usuario) agotó el tiempo de la solicitud y cerró el socket. Algún tiempo después, su servidor intentó escribir la respuesta y falló porque la conexión se había cerrado.
¿Cómo puedo recrear eso?
Estoy adivinando, pero debería poder reproducir ese mensaje "INFO:" arrojando una excepción en el Runnable
run()
Runnable
. Tienes que usar el modo asíncrono, por supuesto.
Primer problema:
INFORMACIÓN: Ocurrió un error en el procesamiento mientras estaba en un hilo que no era contenedor. La conexión se cerrará de inmediato
Ans:
El subproceso async.Stockticker
bloqueó debido a un ISE no gestionado. Esto explica el comportamiento. La excepción se registra solo en la consola. No está registrado en los archivos de registro de Tomcat. Es un error con el manejo de errores para Tomcat. No es una regresión de los cambios recientes. Es reproducible con Tomcat 7.0.59
.
Ya está arreglado en trunk 8.0.x (for 8.0.21 onwards)
y 7.0.x (for 7.0.60 onwards)
. Para que pueda actualizar su versión de tomcat . Entonces este mensaje de información no se mostrará.
Enlace de recursos:
Error 57683 - Crash of stockticket async ejemplo causado por una solicitud de cliente abortado
Segundo problema:
java.net.SocketException: tubería rota
Solución-1:
Este problema realmente ocurre cuando fallamos para cerrar las conexiones como URLConnection y cerrar varias transmisiones abiertas. Quiero compartir un ejemplo
Antes de:
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
out.close();
Después:
OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
bw.close(); //This is must. If you miss to close, then "java.net.SocketException: Broken pipe" error comes
out.close();
os.close();
Solución-2:
Cuando queremos cargar las pruebas en nuestro servidor de aplicaciones, a veces se produce este error.
Los datos tardan long time to be generated
y la herramienta de prueba de carga no wait for the large amounts of data
tiempo suficiente para cerrar la conexión. La memoria realmente baja hizo que la aplicación cerrara el zócalo de recepción o, de hecho, saliera por completo, con el mismo efecto.
Si agregamos memoria adicional a nuestra JVM, entonces resolvió el problema.
Solución-3:
Como @EJP sugirió,
Esto se produce al escribir en una conexión cuando el otro extremo ya la ha cerrado.
Entonces tiene un protocolo de aplicación mal definido o implementado. si esto está sucediendo, hay algo mal con la especificación o implementación de su protocolo de aplicación, lo más probable es que ni siquiera tenga conexión.
Si la aplicación HTTP del lado del servidor obtiene excepciones de Broken Pipe, significa que el navegador del cliente ha salido / ido a otra page/timed out/gone
retrocedido en el historial / lo que sea. Solo olvídalo.
Enlace de recursos:
- Cómo solucionar java.net.SocketException: Broken pipe?
- ¿Por qué se producirá una "java.net.SocketException: Broken pipe"?
Si desea reproducir este error, este tutorial puede ayudarlo.
Tercer problema:
Excepción en el hilo "Thread-28" java.lang.NumberFormatException: Para la cadena de entrada: "boom"
Este error se produce cuando intentaste convertir / analizar cadenas alfabéticas en interger . Es un error normal de Java NumberFormatException
.
ACTUALIZAR:
Como querías saber, en qué casos Tomcat decide registrar ese mensaje adicional cuando detecta una excepción que se expulsó de una aplicación. Así que estoy compartiendo brevemente.
Para hacer una idea clara de "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately java.net.SocketException: Broken pipe"
, Primero quiero compartir con usted que está relacionado con el socket problema. Hay 6 SocketEvent en Tomcat . Son OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT and ERROR
. Esto ocurre por socket que requiere un procesamiento adicional por parte del contenedor. Usualmente estos eventos son desencadenados por la implementación del socket pero también pueden ser activados por el contenedor.
Evento de socket "ERROR":
Se ha producido un error en un subproceso que no es de contenedor y el proceso debe volver al contenedor para realizar la limpieza necesaria. Los ejemplos de dónde se usa esto incluyen:
- por NIO2 para señalar la falla de un controlador de finalización
- por el contenedor para señalar un error de E / S en un hilo no contenedor durante el procesamiento asincrónico de Servlet 3.0.
¿Cuándo se produce este error y se muestra el mensaje INFO en TOMCAT?
Esta es la instantánea del código donde aparece el mensaje de información.
/**
* Update the current error state to the new error state if the new error
* state is more severe than the current error state.
* @param errorState The error status details
* @param t The error which occurred
*/
protected void setErrorState(ErrorState errorState, Throwable t) {
boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
this.errorState = this.errorState.getMostSevere(errorState);
if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) {
// The error occurred on a non-container thread during async
// processing which means not all of the necessary clean-up will
// have been completed. Dispatch to a container thread to do the
// clean-up. Need to do it this way to ensure that all the necessary
// clean-up is performed.
if (response.getStatus() < 400) {
response.setStatus(500);
}
getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t); // This section gives the INFO message "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately"
socketWrapper.processSocket(SocketEvent.ERROR, true);
}
}
¿Cómo puede ocurrir DEADLOCK?
Cuando una solicitud usa una secuencia de inicio múltiple (); dispatch()
con subprocesos sin contenedor es posible que un dispatch()
previo dispatch()
interfiera con un siguiente start()
. Este bloqueo evita que eso suceda. Es un objeto dedicado ya que el código de usuario puede bloquearse en el AsyncContext, por lo que si el código del contenedor también se bloquea en ese objeto, pueden producirse interbloqueos.
¿Cómo el hilo no contenedor define el estado de error actual y da respuesta?
Con la introducción del procesamiento asíncrono y la posibilidad de que non-container threads calling sendError() tracking the current error state
y asegurando que se llame a la página de error correcta se vuelve más complicado. Este atributo de estado ayuda a rastrear el estado de error actual e informar a los llamantes que intentan cambiar el estado si el cambio fue exitoso o si otro subió primero.
/**
* The state machine is very simple:
*
* 0 - NONE
* 1 - NOT_REPORTED
* 2 - REPORTED
*
*
* -->---->-- >NONE
* | | |
* | | | setError()
* ^ ^ |
* | | /|/
* | |-<-NOT_REPORTED
* | |
* ^ | report()
* | |
* | /|/
* |----<----REPORTED
*
*/
¿Cuándo se llama al método executeNonBlockingDispatches (...) en un hilo no contenedor y cómo interactúa con SocketWrapper?
Se invoca este método cuando se inicia IO no bloqueante al definir un oyente de lectura y / o escritura en un hilo no contenedor. Se llama una vez que se completa el subproceso no contenedor, de modo que el contenedor realiza las primeras llamadas a onWritePossible()
y / o onDataAvailable()
según corresponda.
Procesar los despachos requiere (for APR/native at least)
que el socket se haya agregado a la cola waitingRequests. Es posible que esto no se haya producido en el momento en que el subproceso no contenedor finaliza la activación de la llamada a este método. Por lo tanto, las sincronizaciones codificadas en el SocketWrapper como el hilo contenedor que inició este hilo que no es contenedor mantienen un bloqueo en el SocketWrapper . El hilo del contenedor agregará el socket a la cola waitingRequests antes de liberar el bloqueo en el socketWrapper. Por lo tanto, al obtener el bloqueo en socketWrapper antes de procesar los despachos, podemos estar seguros de que el socket se ha agregado a la waitingRequests queue
.