Hi Christopher, not sure what the OutputStreamResponse is, it's not a part of Tapestry. But we use a similar approach using Tapestry's StreamResponse interface.
We have a shared AbstractStreamResponse with dedicated subclasses for File/byte[]/JSONObject etc. to simplify the needed code. Our code is also quite "old", but I'm not aware of a better way. public abstract class AbstractStreamResponse implements StreamResponse { private final int size; private final String mimeType; private final String filename; public AbstractStreamResponse(String mimeType, int size, String filename) { super(); this.mimeType = mimeType; this.size = size; this.filename = filename; } public AbstractStreamResponse(String mimeType, int size) { this(mimeType, size, null); } public AbstractStreamResponse(String mimeType) { this(mimeType, 0, null); } public AbstractStreamResponse(String mimeType, String filename) { this(mimeType, 0, filename); } @Override public String getContentType() { return this.mimeType; } @Override public void prepareResponse(Response response) { if (StringUtils.isNotBlank(this.filename)) { String contentDisposition = String.format("attachment; filename=\"%s\"", this.filename); response.setHeader("Content-Disposition", contentDisposition); } if (this.size > 0) { response.setContentLength(this.size); } } } The subclass for sending a File: public class FileStreamResponse extends AbstractStreamResponse { private final File file; public FileStreamResponse(File file, String mimeType) { super(mimeType, (int) file.length(), file.getName()); this.file = file; } @Override public InputStream getStream() throws IOException { return new FileInputStream(this.file); } } The browser decides "download or display" with the help of the "Content-Disposition" header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition It isn't aware what Tapestry is actually sending back, it's all "just" an HTTP Response for it. Client settings might influence the decision, too. Cheers, Ben On Mon, Nov 15, 2021 at 2:28 PM Christopher Dodunski (Tapestry) < chrisfromtapes...@christopher.net.nz> wrote: > Hi all, > > Inserting a simple <a href="brochure.pdf" download="true"> type link in > a Tapestry template so visitors can download a PDF is straightforward > enough. > > I'd like to shift this to inside the controller, however, so that some > code for analytical purposes can be added. > > A quick Google search revealed the code example below, from around seven > years ago. Just wondering whether this is still the right approach. > Also, it's not clear how browsers might treat this 'stream response' - > download or display? > > Happy to see any better approaches. > > Regards, > > Chris. > > > public Object onBrochure(){ > final File getFile(); > final OutputStreamResponse response = new OutputStreamResponse() { > > public String getContentType() { > return "application/pdf"; > } > > public void prepareResponse(Response response) { > response.setHeader ("Content-Disposition", "attachment; > filename=\"" + file.getName() + "\""); > } > > @Override > public void writeToStream(OutputStream out) throws IOException { > try { > InputStream in = new FileInputStream(file); > IOUtils.copy(in,out); > in.close(); > } catch (Exception e) { > throw new RuntimeException(e); > } > } > }; > return response; > } > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org > For additional commands, e-mail: users-h...@tapestry.apache.org > >