Skip to content

Download handler #21166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mshabarov opened this issue Mar 20, 2025 · 0 comments
Open

Download handler #21166

mshabarov opened this issue Mar 20, 2025 · 0 comments
Assignees

Comments

@mshabarov
Copy link
Contributor

mshabarov commented Mar 20, 2025

Describe your motivation

Using an OutputStream in API for downloads is preferable as this is more intuitive when your server-side code wants to downstream data to client, better aligned with the Servlet API.

Describe the solution you'd like

StreamResource is deprecated and a new DownloadHandler concept is introduced as a replacement:

@FunctionalInterface
public interface DownloadHandler {
  void handleDownloadRequest(DownloadEvent event);

  default String getUrlPostfix() {
    return null;
  }
}

This is a layer on top of the generic element-scoped request handler with helpers to give easy access to file reference, class-path resource, servlet context resource or arbitrary input stream.

The optional URL postfix allows appending an application-controlled string, e.g. the logical name of the target file, to the end of the otherwise random-looking download URL. If defined, requests that would otherwise be routable are still rejected if the postfix is missing or invalid.

Just like with StreamResource, the framework should do the regular security checks before invoking the handler. The session is not locked while the handler is run. The handler may lock the session if necessary but it's not recommended to hold the lock while writing data to the response.

All the magic is in the event object. It gives direct access to the underlying request, response and session as well as various helpers specifically for handling downloads.

// Shown as an interface to focus on the API. The actual type should probably be a class.
public interface DownloadEvent {
  // Also sets Content-Disposition to "attachment"
  void setFileName(String fileName);
  void setContentType(String contentType);
  void setFileSize(long fileSize);
   
  OutputStream getOutputStream();
  PrintWriter getWriter();

  // The component to which the download handler is bound
  Component getComponent();

  // The UI that getComponent() is attached to, provided for use with UI:access.
  UI getUI();

  VaadinRequest getRequest();
  VaadinResponse getResponse();
  VaadinSession getSession();
}

DownloadHandler can be used with various component, e.g. Anchor, Image and others:

Image image = new Image((DownloadEvent event) -> { ... }, "Alt text");
Anchor downloadLink = new Anchor((DownloadEvent event) -> { ... }, "Download report");

In addition to the callback method, the DownloadHandler interface also defines factory methods for creating a download handler instance for various common use cases.

public interface DownloadHandler {
  static DownloadHandler forFile(File file);
  static DownloadHandler forClassResource(Class<?> class, String name);
  static DownloadHandler forServletResource(String path);
  static DownloadHandler fromInputStream(Function<DownloadEvent, DownloadResponse> handler);
}

The DownloadResponse return type allows providing an InputStream to read from or a Consumer<OutputStream> to acquire a stream to write to.

@mshabarov mshabarov moved this to 🪵Product backlog in Vaadin Flow ongoing work (Vaadin 10+) Mar 20, 2025
@mshabarov mshabarov changed the title [Draft] Download handler Download handler Mar 24, 2025
@mshabarov mshabarov moved this from 🪵Product backlog to 🟢Ready to Go in Vaadin Flow ongoing work (Vaadin 10+) Apr 2, 2025
@caalador caalador self-assigned this Apr 7, 2025
@mshabarov mshabarov moved this from 🟢Ready to Go to ⚒️ In progress in Vaadin Flow ongoing work (Vaadin 10+) Apr 8, 2025
caalador added a commit that referenced this issue Apr 11, 2025
Add DownloadHandler interface and
factory methods.

Closes #21166
caalador added a commit that referenced this issue Apr 11, 2025
Add DownloadHandler interface and
factory methods.

Closes #21166
caalador added a commit that referenced this issue Apr 11, 2025
Add DownloadHandler interface and
factory methods.

Closes #21166
caalador added a commit that referenced this issue Apr 14, 2025
Add DownloadHandler interface and
factory methods.

Closes #21166
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: ⚒️ In progress
Development

No branches or pull requests

2 participants