¿Por qué el error de llamada o el hecho en una publicación de BodyParser la solicitud se cuelga en Play Framework 2.0?

Estoy tratando de entender los conceptos de E / S reactivos del marco Play 2.0. Para obtener una mejor comprensión desde el principio, decidí omitir a los ayudantes del framework para construir iteraciones de diferentes tipos y escribir una costumbre.Iteratee desde cero para ser utilizado por unBodyParser para analizar un cuerpo de solicitud.

A partir de la información disponible enIteratees yScalaBodyParser documentos y dos presentaciones sobre juego reactivo de E / S esto es lo que se me ocurrió:

import play.api.mvc._
import play.api.mvc.Results._
import play.api.libs.iteratee.{Iteratee, Input}
import play.api.libs.concurrent.Promise
import play.api.libs.iteratee.Input.{El, EOF, Empty}

01 object Upload extends Controller {
02   def send = Action(BodyParser(rh => new SomeIteratee)) { request =>
03     Ok("Done")
04   }
05 }
06
07 case class SomeIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] {
08   println(state + " " + input + " " + received)
09
10   def fold[B](
11     done: (Either[Result, Int], Input[Array[Byte]]) => Promise[B],
12     cont: (Input[Array[Byte]] => Iteratee[Array[Byte], Either[Result, Int]]) => Promise[B],
13     error: (String, Input[Array[Byte]]) => Promise[B]
14   ): Promise[B] = state match {
15     case 'Done => { println("Done"); done(Right(received), Input.Empty) }
16     case 'Cont => cont(in => in match {
17       case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length)
18       case Empty => copy(input = in)
19       case EOF => copy(state = 'Done, input = in)
20       case _ => copy(state = 'Error, input = in)
21     })
22     case _ => { println("Error"); error("Some error.", input) }
23   }
24 }

(Observación:Todos estas cosas son nuevas para mí, así que perdona si algo sobre esto es una mierda total. El Iteratee es bastante tonto, solo lee todos los fragmentos, resume el número de bytes recibidos e imprime algunos mensajes. Todo funciona como se esperaba cuando llamo a la acción del controlador con algunos datos. Puedo observar que todos los fragmentos son recibidos por Iteratee y cuando todos los datos se leen, el estado cambia y el pedido finaliza.

Ahora empecé a jugar con el código porque quería ver el comportamiento de estos dos casos:

Cambio a error de estado antes de que se lea toda la entrada.El cambio al estado se realiza antes de que se lea toda la entrada y se devuelva unResult en vez deInt.

Mi comprensión de la documentación mencionada anteriormente es que ambos deberían ser posibles, pero en realidad no puedo entender el comportamiento observado. Para probar el primer caso, cambié la línea 17 del código anterior a:

17       case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Error else 'Cont, input = in, received = received + in.e.length)

Así que acabo de agregar una condición para cambiar al estado de error si se recibieron más de 10000 bytes. La salida que obtengo es esta:

'Cont Empty 0
'Cont El([B@38ecece6) 8192
'Error El([B@4ab50d3c) 16384
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error

Entonces la solicitud se cuelga para siempre y nunca termina. Mi expectativa de los documentos mencionados anteriormente era que cuando llamo alerror función dentrofold de un Iteratee el procesamiento debe ser detenido. Lo que está sucediendo aquí es que el método de plegado de Iteratee se llama varias veces después deerror Se ha llamado - bueno y luego se cuelga la petición.

Cuando cambio al estado finalizado antes de leer todas las entradas, el comportamiento es bastante similar. Cambiando la línea 15 a:

15    case 'Done => { println("Done with " + input); done(if (input == EOF) Right(received) else Left(BadRequest), Input.Empty) }

y la línea 17 a:

17       case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Done else 'Cont, input = in, received = received + in.e.length)

produce la siguiente salida:

'Cont Empty 0
'Cont El([B@16ce00a8) 8192
'Done El([B@2e8d214a) 16384
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)

y otra vez la petición cuelga para siempre.

Mi pregunta principal es por qué la solicitud se cuelga en los casos mencionados anteriormente. ¡Si alguien pudiera arrojar luz sobre esto, lo apreciaría enormemente!

Respuestas a la pregunta(2)

Su respuesta a la pregunta