Subject: [Webpush] Time to live for push messages

From: Martin Thomson <[email-masked]>
Date: Fri, 20 Feb 2015 20:11:56 +1300

A common problem with push message delivery services looks like this:

1. A push is requested by an application server.
2. The user agent is offline temporarily, so the push service stores
the message.
3. The user agent returns long after the event is interesting, but the
message is delivered anyway.
4. The user agent acts on a message that is now useless, and which
could be harmful.

This is particularly annoying for something like a call notification,
which might be delivered well after the caller gives up on the call.
For these, an application can add its own suppression mechanisms.
Though manual suppression introduces a trade-off between risk of
showing a dead alert and added latency.  Also, there isn't anything
that can be done about the battery power that was spent in delivering
the useless message.

So, most systems implement a suppression system at the push service,
where an application server can indicate that a message should not be
delivered after some point in time.  (I've seen one with suppression
that occurs only at the client, but that was spectacularly
unsuccessful.)

The trick here is in working out how to express this.  I see a few options:

A. RFC 4918 describes a Timeout header field, which has semantics that
apply only to the LOCK method.  That could be extended to apply to
PUT.

B. A new header field could be defined to carry the information.  This
would have the same semantics as the above.

C. We could start to explore message payloads.

I prefer the header field options, with a slight preference for
reusing Timeout (even if that means updating RFC 4918).   The precise
semantics would need a little work, but here's a straw man outline:

   The Timeout header field applies to unsafe requests only.  The
client indicates that changes to the state of a resource as a result
of processing the request are to be reset after the described interval
elapses.  The state that the resource is reset *to* is undefined, for
a number of reasons: not all resources will know and support this
header field, some changes might be irreversible, servers are always
free to set the state of a resource to whatever they like, and it
would be nice to avoid the complexity of having multiple interacting
layers of timeout.

You will note that this is compatible with the definition of Timeout
as defined in RFC 4918, including the fact that the server can do
nothing with the lock at the timeout expiration time.

The final consideration here is whether this is something that needs
to enter the core specification, or whether it would be better as a
separate specification.  I have no opinion on that.

---

From: Costin Manolache <[email-masked]>
Date: Sat, 21 Feb 2015 09:53:05 -0800

For option A: the format in RFC4918 is "Infinite | Second-1234".
Unless 'infinite' is defined to be few weeks - it is going to be hard to
support.
I think using seconds instead of absolute value is very good.

RFC3261 (SIP) uses ';ttl=12' as a URI parameter - without the constant
"Second-".
I would personally prefer this option.

"Expires" header is another option.

Going into payload is interesting as well - we need to start discussing the
actual
format of the payload, but it seems pretty likely that a part will be
encrypted, and some part will be
clear text but signed. It's a tricky subject - but if Jose/JWE or something
similar is
used, we will may want to have any parameters that the push server needs to
interpret
into the signed/authenticated portion of the payload - otherwise we would
need to worry about
signing some headers or the URI.  An important decision is if the ttl (and
other timestamps)
need to be sent to the device and authenticated or it is going to be
dropped or modified
during transport.

Another complication may be the case the message is forwarded multiple
times, there
are few cases where this may become necessary.

Other things to consider are:
- how to deal with servers that don't support a particular ttl value
- how to discover max value for a push provider

I think the core specification needs to define at least how to encode
parameters that are used by
the push server (== clear text).

Costin

On Thu, Feb 19, 2015 at 11:11 PM, Martin Thomson <[email-masked]>
wrote:

> _______________________________________________
> Webpush mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/webpush
>

---

From: Martin Thomson <[email-masked]>
Date: Sun, 22 Feb 2015 11:33:02 +1300

> I think using seconds instead of absolute value is very good.

It is customary for the server to have the ultimate authority on what
the timeout actually is.  A requested timeout of Infinite is always
going to be shorter anyway, and if the client asks for a month and the
server can only do a minute, then it will be a minute.

The only question there is how much value there is in having the
server notify the client about the actual timeout.  I guess if a
server refuses to store for a particular duration, a client could be
forced to retry for that duration.

> I would personally prefer this option.

The format is unnecessarily clunky, I agree.

> "Expires" header is another option.

I considered that at some length and rejected it for two reasons:

Expires only has defined semantics related to the cacheability of HTTP
responses.  Using Expires in a request context, even for a PUT (maybe
even especially for a PUT) is well outside its original definition.

Also, Expires uses an absolute time and clock skew has proven to be a
major issue.  In theory, an absolute time can be more precise, but
most uses for a TTL are on short timescales where clock skew can
dominate.  At least with a relative time, transit times can be
accounted for.

> An important decision is if the ttl (and other timestamps)
> need to be sent to the device and authenticated or it is going to
> be dropped or modified during transport.

As I alluded to in my first email, I think that the primary value of a
TTL parameter is where the push service uses the value.  Once the push
hits the user agent, it's value is greatly diminished.

Of course, there is nothing wrong with having the push message itself
contain time-based information that is consumed by the application.

> Another complication may be the case the message is
> forwarded multiple times, there are few cases where
> this may become necessary.

If you are required to forward the message, that's an internal detail
of the push service and I'd expect that you would account for any
elapsed time there.  You could, for instance, convert a relative time
into an absolute time for internal consumption, knowing that your
servers have good time synchronization.

---

From: Costin Manolache <[email-masked]>
Date: Sat, 21 Feb 2015 15:26:31 -0800

> server can only do a minute, then it will be a minute.

I agree - my comment was more on the slightly strange syntax - "Second-"
prefix and "Infinite" constant are a bit odd compared with other ways
to represent time.

> forced to retry for that duration.

Server can include 'max ttl' in the response if it rejects too long time,
so client can use max ttl. Or accept it with a shorter ttl, but include the
shorter ttl in response.

> The format is unnecessarily clunky, I agree.

Another benefit of having ttl as URL param - or in payload - is for the
case message needs to go trough multiple servers.

> dominate.  At least with a relative time, transit times can be

Agreed - relative time in seconds sounds good, just
URL param vs Header vs payload.

> contain time-based information that is consumed by the application.

One use case is a message that goes trough multiple servers - and may
be gated on the client as well. For example message is for a multi-profile
UA - and it gets delivered to the client machine but it can't be delivered
to
the intended profile ( stopped users on android for example ). Or in
some cases the UA may display a notification before delivering the message
to the app - if TTL expires it may drop the notification and message.

The sender would include ttl=60, push server stores the
message and delivers it after 20 seconds - than the forwarded message would
have the remaining ttl=40 (or ttl=60, 'delay=20'). The message may have
to wait on either client or intermediary  server.

> servers have good time synchronization.

That's easy if it's internal forwarding, I was thinking of the case of
forwarding to
a different push provider. We should consider the case - given the
complicated
world of mobile.

Costin