Skip to content
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

Simpler & more robust model for getting the share data clientside #84

Open
jakearchibald opened this issue Jul 31, 2019 · 16 comments
Open

Comments

@jakearchibald
Copy link

Right now, if you want to handle the share data on the client, you need to add a service worker, redirect the response, serve the response, then postmessage the shared data to the page.

This is a little cumbersome, but will also totally fail if the browser has cleared the service worker away (to regain space, or due to corruption).

It feels like there should be a way to specify that the share shouldn't happen via GET/POST, but instead the page should load as a simple navigation, and the share data is available via the DOM.

Eg:

if (shareTarget.shareData) {
  // shareData is a FormData object.
}

Now, if the service worker has vanished for whatever reason, the page will load over the network, but the operation will still work if the user is online.

@raymeskhoury
Copy link
Collaborator

@fallaciousreasoning and @mgiuca have been thinking about how to make this easier

@fallaciousreasoning
Copy link

We've been considering a window.launchParams.request proposal, which would be more general than just shareData. launchParams would also give us somewhere sane to attach files that a PWA might have been launched with (and potentially other launchy data, in future).

@mgiuca
Copy link
Collaborator

mgiuca commented Aug 1, 2019

Yeah we got this feedback from elsewhere and it's definitely an issue. However, I feel like the cleanest solution is not to have a separate mode where you expose the share data via the DOM (instead of POST), but rather (as @fallaciousreasoning mentions), to expose the POST data through the DOM.

I prefer to use POST for share target since it's the simplest way to transfer data to a web page. The problem is that POST is designed for Web 1.0 where the data is transferred to the server, and not really applicable to a modern single-page app / service worker world. But if there was a DOM API to expose the POST data to the page, we could have the service worker respond to a POST request from cache (discarding the POST data) but then expose the POST data to the page's DOM. Seems like a very elegant design, with a handful of small isolated features that can be used together, rather than the "heavy hammer" of making Share Target expose its data through a DOM API.

This is currently mentioned off-hand in the file handler explainer (see LaunchParams), but I'd like to spin it off into a separate proposal.

@jakearchibald
Copy link
Author

I prefer to use POST for share target since it's the simplest way to transfer data to a web page.

It's ideal if the intent is to handle it on the server. But if the intent is to always handle it client side, transferring large files to the server is just a waste of time and bandwidth.

Also, some static hosts error on POST.

@mgiuca
Copy link
Collaborator

mgiuca commented Aug 2, 2019

Both of those issues can be solved by having the service worker either serve the page from cache, or proxy the request to the server as a GET request.

I wanted this to be designed as simple, composable building blocks. What I like about service workers is that they allow us to design APIs with the simple state model of HTTP / Web 1.0 (data is transferred via HTTP requests and responses) but gives developers an optional way to abstract that away from actual network data transfers. That's what allowed us to design WST as the more primitive building block of "it just makes a POST request", rather than coupling it with the DOM and JavaScript environment, knowing that sites would have the option of composing the building block we created with service workers to get client-side access to that data. The only missing bit is that it's very hard to get that data from the SW through to the foreground page.

If there is a real pushback on the idea of having to write a SW in order to stop the data from being transferred to the server, we can do as you suggest and make a binary flag in the manifest to say "don't put the data in a POST request, expose it to the DOM instead". But I figured that the design of the web platform is such that all information uploaded by the user into a site gets sent to the server unless a service worker says not to.

@jakearchibald
Copy link
Author

From the OP:

will also totally fail if the browser has cleared the service worker away (to regain space, or due to corruption).

The lifecycle of the service worker and share target are independent

@fallaciousreasoning
Copy link

I agree that is a Not Good Thing, but I think it would be solved by providing access to the request in the document.

Interestingly, the way WebShareTarget is currently written, it doesn't depend at all on ServiceWorkers existing, or being implemented (though the way we're recommending it be used does). Without them, a POST would be sent to the server, which could dump the data straight into the page.

@jakearchibald
Copy link
Author

As I said above:

But if the intent is to always handle it client side, transferring large files to the server is just a waste of time and bandwidth.

Also, some static hosts error on POST.

@mgiuca
Copy link
Collaborator

mgiuca commented Aug 8, 2019

FYI, a Chrome issue about this: https://crbug.com/983591

@mgiuca
Copy link
Collaborator

mgiuca commented Sep 19, 2019

OK I just had a F2F with @raymeskhoury and @jakearchibald .

On the issue of service worker being deleted when the app is installed: we think regardless of WST, we this is a concern. You don't expect your installed native apps to suddenly disappear (or be unavailable offline) just because you haven't used them in awhile. Jake suggested that there's the Persistent Storage API, which is available to installed apps to "pin" the service worker so it doesn't get cleared due to storage pressure. We could automatically activate this API when you install an app.

The other use cases for clearing a SW (corruption, or user choice) are less important to deal with because they're edge cases. Corruption should be rare. User choice, well we could ask user agents to uninstall the apps associated with the SW if the user is clearing the SW.

Having said that, there is still a usability issue with the Web Share Target API receiving data through POST. Even if we make POST data available through a JavaScript API on the document, it would be destroyed by redirecting (which is something you almost always want to do --- nobody wants to be asked to resubmit POST data when refreshing the page). So if you redirect to another page, you wouldn't be able to access the POST data any more. So it's likely we just want to add an alternative mode to Web Share Target which says "actually don't put the data in a form submission; store it in a special object in the document". We should ensure that we're making this alternative as close as possible to the way file-handling works, since they will end up looking fairly similar.

@mgiuca
Copy link
Collaborator

mgiuca commented Jun 22, 2021

I just wrote a comment relating to this on WICG/file-handling#63 (see this).

I won't repeat myself too much (see that post for context), but I still think the last sentence from my above comment from 2019 is the way we should go:

@mgiuca :

So it's likely we just want to add an alternative mode to Web Share Target which says "actually don't put the data in a form submission; store it in a special object in the document". We should ensure that we're making this alternative as close as possible to the way file-handling works, since they will end up looking fairly similar.

That should be easier to design now that file handling is a thing. It should not replace GET and POST, but be an additional option for developers, perhaps a pseudo-method called EVENT. So the manifest could look like this:

{
  "share_target": {
    "method": "EVENT",
    "url": "/share-target",
    "params": {
      "files": [...]
    }
  }
}

So if you used "method": "POST", you'd get the contents of those files delivered in the body of the HTTP request to the share target URL. But with "method": "EVENT", the share target URL is navigated using a GET request, then the launchQueue is pushed with an object containing the contents of the files. Very similar to how file handling works.

@alancutter
Copy link

As discussed offline:

  • "method": "EVENT" is very awkward as a non HTTP method keyword.
  • "method": "EVENT" is not a backwards compatible change to the spec if you want to fallback to "method": "GET".
  • We can just enqueue the launch event always without any manifest API changes.

@fallaciousreasoning
Copy link

fallaciousreasoning commented Jun 22, 2021

We can just enqueue the launch event always without any manifest API changes.

Doesn't this mean developers would still have to handle the HTTP request (either in their ServiceWorker or on their server)? I think it would be preferable if we could opt out of that.

What about omitting the method property (assuming that it's currently required). This would make handling events via the launchQueue the default, while still letting developers opt into the request style shares. You could even always add the share to the launchQueue, but only send a request if the method property is specified?

@alancutter
Copy link

alancutter commented Jun 22, 2021

Doesn't this mean developers would still have to handle the HTTP request (either in their ServiceWorker or on their server)? I think it would be preferable if we could opt out of that.

"capture_links": "existing-client-event" would prevent the POST navigation.
It would make sense to include "new-client-event" as an option as well.

Side note: I'm going to plug WICG/web-app-launch#31 as I think the behavioural connection between share target and capture_links isn't very obvious just from the name.

@mgiuca
Copy link
Collaborator

mgiuca commented Jun 22, 2021

Yep, I think @alancutter is totally right here. We shouldn't add a new method. We should just retroactively always fire the event (whether it's GET or POST). That's backwards-compatible and doesn't require us to introduce "methods" that aren't really HTTP methods.

This would mean you can share files with "method": "GET"; the files wouldn't appear in the URL, but they would appear in the event object.

There's a small backwards compat problem with this, namely, any site that relies on file sharing with "method": "GET" would not be able to get those files on an older browser that doesn't support event-based share targeting. So for backwards compat, you would still need to use "method": "POST", but you could switch to "GET" as enough browser share supports the event-based approach.

@fallaciousreasoning
Copy link

"capture_links": "existing-client-event" would prevent the POST navigation.

Awesome! Sorry for the noise, I'm pretty out of the loop but I'm really excited you guys are working on this 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants