Por que fazer um erro de chamada ou feito em um Iterate BodyParser a solicitação está pendente no Play Framework 2.0?

Eu estou tentando entender os conceitos de I / O reativa do framework Play 2.0. A fim de obter uma melhor compreensão desde o início, decidi pular os ajudantes do framework para construir iteratees de diferentes tipos e escrever umIteratee a partir do zero para ser usado por umBodyParser para analisar um corpo de solicitação.

Começando com as informações disponíveis emIterados eScalaBodyParser docs e duas apresentações sobre reproduzir I / O reativa é isso que eu criei:

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 }

(Observação:Todos essas coisas são novas para mim, então, por favor, perdoe se algo sobre isso é uma porcaria total.) O Iteratee é muito idiota, apenas lê todos os pedaços, resume o número de bytes recebidos e imprime algumas mensagens. Tudo funciona como esperado quando eu chamo a ação do controller com alguns dados - eu posso observar que todos os pedaços são recebidos pelo Iteratee e quando todos os dados são lidos, ele muda para state done e o request termina.

Agora comecei a brincar com o código porque queria ver o comportamento desses dois casos:

Comutação para erro de estado antes de toda entrada ser lida.Mudando para o estado feito antes que toda a entrada seja lida e retornando umResult ao invés deInt.

Meu entendimento da documentação mencionada acima é que ambas devem ser possíveis, mas na verdade não sou capaz de entender o comportamento observado. Para testar o primeiro caso, mudei a linha 17 do código acima para:

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

Então eu acabei de adicionar uma condição para mudar para o estado de erro se mais de 10000 bytes foram recebidos. A saída que recebo é 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

Então o pedido fica para sempre e nunca termina. Minha expectativa dos documentos acima mencionados era de que quando euerror função dentrofold de um Iteratee o processamento deve ser interrompido. O que está acontecendo aqui é que o método fold do Iteratee é chamado várias vezes depoiserror foi chamado - bem e, em seguida, o pedido trava.

Quando mudo para o estado pronto antes de ler todas as entradas, o comportamento é bastante semelhante. Alterando a linha 15 para:

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

e linha 17 para:

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

produz a seguinte saída:

'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)

e novamente o pedido fica para sempre.

Minha principal questão é por que o pedido está pendente nos casos acima mencionados. Se alguém pudesse esclarecer isso, eu agradeceria muito!

questionAnswers(2)

yourAnswerToTheQuestion