cptdanko
cptdanko

Reputation: 842

Error delivering a csv file through the browser

What my application is doing is creating a large csv file (its a report) and the idea is to deliver the contents of the csv file without actually saving a file for it. Here's my code

String csvData; //this is the string that contains the csv contents
byte[] csvContents = csvData.getBytes();
response.contentType = "text/csv";
response.headers.put("Content-Disposition", new Header(
            "Content-Disposition", "attachment;" + "test.csv"));
response.headers.put("Cache-Control", new Header("Cache-Control",
            "max-age=0"));
response.out.write(csvContents);
ok();

The csv files that are being generated are rather large and the error i am getting is

org.jboss.netty.handler.codec.frame.TooLongFrameException: An HTTP line is larger than 4096 bytes.

Whats the best way to overcome this issue?

My tech stack is java 6 with play framework 1.2.5.

Note: the origin of the response object is play.mvc.Controller.response

Upvotes: 0

Views: 717

Answers (3)

Notalifeform
Notalifeform

Reputation: 194

Apparently netty complains that the http-header is too long - maybe it somehow thinks that your file is part of the header, see also

http://lists.jboss.org/pipermail/netty-users/2010-November/003596.html

as nylund states, using renderBinary should do the trick.

We use writeChunk oursleves to output large reports on the fly, like:

Controller:

public static void getReport() {

        final Report report = new Report(code, from, to );
        try {

            while (report.hasMoreData()) {
                final String data = await(report.getData());
                response.writeChunk(data);
            }
        } catch (final Exception e) {
            final Throwable cause = e.getCause();
            if (cause != null && cause.getMessage().contains("HTTP output stream closed")) {
                logger.warn(e, "user cancelled download");
            } else {
                logger.error(e, "error retrieving  data");
            }
        }
    }

in report code

 public  class Report {
    public Report(final String code, final Date from, final Date to) {
    }
    public boolean hasMoreData() {
        // find out if there is more data        
    }
    public Future<String> getData() {
        final Job<String> queryJob = new Job<String>() {
            @Override
            public String doJobWithResult() throws Exception {
               // grab data (e.g read form db) and return it               
                return data;
            }
        };
        return queryJob.now();
    }
}

Upvotes: 0

nylund
nylund

Reputation: 1105

We use this to show the results of an action directly in the browser,

window.location='data:text/csv;charset=utf8,' + encodeURIComponent(your-csv-data);

I am not sure about the out of memory error but I would at least try this:

request.format = "csv";
renderBinary(new ByteArrayInputStream(csvContents));

Upvotes: 1

laksys
laksys

Reputation: 3237

Please use

ServletOutputStream

like

String csvData; //this is the string that contains the csv contents
byte[] csvContents = csvData.getBytes();
ServletOutputStream sos = response.getOutputStream();
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=test.csv");
sos.write(csvContents);

Upvotes: 1

Related Questions