2014-05-08 3 views
3

Jusqu'à présent, nous utilisions JBoss AS 7.1 qui avait un tomcat en tant que serveur frontal. Nous avons maintenant mis à niveau vers Wildfly (JBoss 8.0) qui est livré avec des fonds de rechange comme un remplacement Tomcat.Wildfly: org.xnio.channels.FixedLengthOverflowException

Pour nos téléchargements téléchargés, nous lisons le flux d'entrée du fichier et l'écrivons dans le flux de sortie de réponse du contexte externe. Cela a bien fonctionné dans JBoss AS 7.1 - même pour les gros fichiers. En Undertow Nous recevons l'exception suivante, même pour de jolis fichiers « petits »:

13:04:43,292 ERROR [io.undertow.request] (default task-15) Blocking request failed HttpServerExchange{ GET /project/getFile.xhtml}: java.lang.RuntimeException: org.xnio.channels.FixedLengthOverflowException 
    at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpServletResponseImpl.java:527) 
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:287) 
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) 
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) 
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) 
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) 
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_51] 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_51] 
    at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51] 
Caused by: org.xnio.channels.FixedLengthOverflowException 
    at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.write(AbstractFixedLengthStreamSinkConduit.java:97) 
    at org.xnio.conduits.Conduits.writeFinalBasic(Conduits.java:132) [xnio-api-3.2.0.Final.jar:3.2.0.Final] 
    at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.writeFinal(AbstractFixedLengthStreamSinkConduit.java:137) 
    at org.xnio.conduits.ConduitStreamSinkChannel.writeFinal(ConduitStreamSinkChannel.java:104) [xnio-api-3.2.0.Final.jar:3.2.0.Final] 
    at io.undertow.channels.DetachableStreamSinkChannel.writeFinal(DetachableStreamSinkChannel.java:172) 
    at io.undertow.servlet.spec.ServletOutputStreamImpl.writeBufferBlocking(ServletOutputStreamImpl.java:580) 
    at io.undertow.servlet.spec.ServletOutputStreamImpl.close(ServletOutputStreamImpl.java:614) 
    at io.undertow.servlet.spec.HttpServletResponseImpl.closeStreamAndWriter(HttpServletResponseImpl.java:451) 
    at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpServletResponseImpl.java:525) 
    ... 9 more 

Le getFile.xhtml invoque le téléchargement et le code suivant est utilisé pour copier le flux:

(try, catch, journaux et la gestion des erreurs enlevée pour économiser de l'espace)

public void downloadFile(FileEntity fileEntity) { 
     FacesContext fc = FacesContext.getCurrentInstance(); 
     ExternalContext ec = fc.getExternalContext(); 

     ec.responseReset(); 
     ec.setResponseContentType(getMimeType(fileEntity.getFile())); 
     ec.setResponseContentLength(new Long(fileEntity.getFile().length()).intValue()); 
     ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + ConversionHelper.validateFilename(fileEntity.getDisplayFileName()) + "\""); 

     OutputStream output = ec.getResponseOutputStream(); 
     FileInputStream fis = new FileInputStream(fileEntity.getFile()); 

     IOUtils.copy(fis, output); 

     fc.responseComplete(); 
    } 

Je remarqué que la suppression de la ligne

ec.setResponseContentLength(new Long(fileEntity.getFile().length()).intValue()); 

le fait fonctionner à nouveau. Cependant ResponseConentLength est "correct". L'utilisation de

ec.setResponseContentLength(new Long(fileEntity.getFile().length()).intValue() + 9); 

(notez le +9) résout ce problème. En utilisant +8 ->FixedLengthOverflow, en utilisant +10 ->FixedLengthUnderflow

Le +9 est indépendant de la taille du fichier. Une idée? Attend étrange pour moi ...


Mise à jour:

trouvé le problème.

Cela a à voir avec le changement du moteur du serveur. Juste ne sais pas si elle est directement liée à undertow, ou plus une erreur avec wildfly/JSF (ou si c'était une erreur dans Jboss et maintenant fonctionne correctement):

Pour invoquer le téléchargement, nous avons utilisé quelque chose comme ça dans le getFile.xhtml:

<f:metadata> 
     <f:viewParam name="fileId" required="true" 
      value="#{getFileController.fileId}"></f:viewParam> 
    </f:metadata> 

    <h:outputLabel value="#{getFileController.download()}" /> 

ceci produirait habituellement:

<label>value</label> 

si la valeur de l'étiquette serait une chaîne.

puisque nous réinitialisons la réponse à l'intérieur download(), <label> est à nouveau supprimé. Ensuite, en utilisant une taille de réponse fixe qui est égale à la longueur du fichier et en appelant responseComplete(), le fichier </label> final est ignoré. Undertow semble cependant ignorer le responseComplete() -Call et tente d'ajouter </label> à la réponse, remarque, que la fin du flux de réponse (fixe) est atteinte, et renvoie donc l'exception mentionnée. C'est pourquoi fournir une taille de +9 résout cette erreur - mais provoque des fichiers corrompus, cause </label>\n sera ajouté au fichier. Évidemment, l'utilisation d'une étiquette de sortie était une mauvaise pratique dans ce cas. Mais puisque nous avons remis à zéro et rempli manuellement le flux de réponse et appelé responseComplete() qui fonctionnait bien.

le correctif est évidemment de ne pas produire un (non requis) balises html sur cette page:

<f:metadata> 
     <f:viewParam name="fileId" required="true" 
      value="#{getFileController.fileId}"></f:viewParam> 
     <f:event listener="#{getFileController.dlNow()}" type="preRenderView"></f:event> 
    </f:metadata> 

A côté de la mauvaise conception il - ne devrait pas appeler responseComplete() OMMISSIONS une écriture supplémentaire à la réponse flux, y compris toute tentative d'écriture ATTEMPTS?

Le docu dit:

Signal JavaServer Faces mise en œuvre que la réponse HTTP pour cette demande a déjà été généré (par exemple une redirection HTTP), et que le cycle de vie du traitement des demandes doivent être serties comme bientôt lorsque la phase en cours est terminée.

Ainsi, si la mise en œuvre des visages est dit que la réponse a été envoyée - pourquoi serait-il essayer d'ajouter quelque chose?

+1

mettre une solution pour répondre à cette question ne semble pas manquer une réponse –

+0

@ LeosLiterak pourrait refactoriser en fonction d'autres réponses. Pour l'instant j'ai encore des questions en suspens et peut-être quelqu'un pourrait fournir une réponse qui le mérite. (Signification: Je connais la cause et je l'ai corrigée, mais je ne connais pas la "cause première": P) – dognose

Répondre

2

Si vous appelez output.close(), cela devrait avoir l'effet que vous recherchez. Cela ressemble à un problème avec JSF, et non lié à Undertow.

+0

En fait, cela ressemble à un bug Undertow, parce que vous avez défini la longueur du contenu que la vapeur de sortie devrait fermer automatiquement la longueur du contenu a été atteinte. C'est probablement parce que les choses sont écrites et ensuite réinitialisées avant que la vraie réponse ait été écrite. J'ai déposé https://issues.jboss.org/browse/UNDERTOW-236. –

+0

thx pour remplir le ticket. Surveiller et fournir des informations supplémentaires si nécessaire - mais devrait être facile à reproduire je dirais. – dognose

+0

+1 pour le réparer :) – dognose