Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Servlet mixes header and content and writing twice same in output?

I have implemented servlet which behaves not stable, sometimes it mixes header in content and writing same twice.

and sometimes it is returning file which contains response header mixed by content like this:

Server: Apache-Coyote/1.1
: W/"43-1353687036000"
DatCCoonntenntt--DDiissppoosittiioonn: : atatatacehnmte;n tf;i lfenlaemnea=m20=12201112211127325421_4W1_Wirnkgi_nSgc_Seern.xnlsx
sx
Content-Typ-eT: ype: applaipcatciaoti/on/toctestt-rstare
am
ConCtoententy-pTeype: appalicatcion/oon/octet-setarm
m
CCoonntent-Lnegtht h: 4199

Date: te: FriF,r i2,3  2No vNo2v0 120162: 215:25 :G4M2T 
....
File content bytes ...

And again same header and content

UPDATE *This situation happens on Tomcat7*

I have tested also on Tomcat6 and Jetty, in both cases there is no injection of HTTP-Header to response content but HTTP-Header is wrong and returns wrong file name, the file content is correct file. I have noticed that wrong return from servlet happens when returns transfer-encoding is chunked.

When I am removing header stuff, and second part of bytes, it is valid file. Is it possible that is synchronization issue ?

UPDATE Here is full source of servlet :

public class ExcelDownloadServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger
            .getLogger (ExcelDownloadServlet.class);


    @Override
    protected void doGet (HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        try
        {
            TransactionId transactionId = getTransactionId (request);
            String fileName =
                    request.getParameter (GlobalConstants.EXCEL_FILE);
            ExcelDownloadType downloadType =
                    ExcelDownloadType
                            .valueOf (request
                                    .getParameter (GlobalConstants.EXCEL_DOWNLOAD_TYPE));
            ActionContextFactory actionContextFactory =
                    ApplicationContext.getContext ()
                            .getActionContextFactory ();
            //suppress warning. HttpServletRequest.getLocales does not support generics
            @SuppressWarnings("unchecked")
            ActionContext actionContext =
                    actionContextFactory.create (request.getSession ()
                            .getId (), Collections.<Locale> list (request
                            .getLocales ()));
            GetExcelDataResponse dataResponse =
                    new GetExcelData (transactionId, fileName, downloadType)
                            .execute (actionContext);
            writeToResponse (response, dataResponse.getFileName (),
                    dataResponse.getData ());
        }
        catch (InvalidSessionException e)
        {
            LOG.error ("Invalid session in Excel download", e);
            throw new ServletException (e);
        }
        catch (ActionException e)
        {
            LOG.error ("Could not download into excel.", e);
            throw new ServletException (e);
        }
    }

    protected TransactionId getTransactionId (HttpServletRequest request)
    {
        return RequestParameterDeserializer.<TransactionId> deserialize (
                request, GlobalConstants.TRANSACTION_ID);
    }

    protected void writeToResponse (HttpServletResponse response,
            String rawFileName, byte[] data) throws IOException
    {
        ServletOutputStream sout = null;
        try
        {            
            response.setContentType ("application/octet-stream");
            response.setContentLength (data.length);
            // removing blanks from the file name, since FF cuts file names
            // otherwise.
            String fileNameWithTime = rawFileName.replaceAll (" ", "_");
            response.setHeader ("Content-Disposition", "attachment; filename="
                    + fileNameWithTime);
            sout = response.getOutputStream ();
            sout.write (data, 0, data.length);
        }
        finally
        {
            if (sout != null)
            {
                sout.close ();
            }
        }
    }

UPDATE *The call comes from GWT application when is generating the URL of servlet with required parameters and sets in IFrame, then servlet calls and file is downloading. Are there any suggestions ?*

like image 530
Sergey Gazaryan Avatar asked Nov 30 '12 15:11

Sergey Gazaryan


Video Answer


1 Answers

I had a similar issue a long time ago. It turned out that closing the ServletOutputStream triggered an unexpected behaviour on the request flow.

Servlets are not supposed to close the container provided OutputStream. Another issue could be manually setting the content length, it is responsibility of the container producing the correct value.

To summarize, try removing out.close() and response.setContentLength()

like image 180
Carlo Pellegrini Avatar answered Sep 19 '22 12:09

Carlo Pellegrini