Async filters

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Async filters

Nils Kilden-Pedersen
I can't seem to find much information on how to code async filters.

Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

Thanks,

_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
Reply | Threaded
Open this post in threaded view
|

Re: Async filters

Simone Bordet-3
Hi,

On Mon, Nov 11, 2019 at 5:25 PM Nils Kilden-Pedersen <[hidden email]> wrote:
>
> I can't seem to find much information on how to code async filters.
>
> Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

You use Servlet's AsyncListener and implement onComplete().

--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
Reply | Threaded
Open this post in threaded view
|

Re: Async filters

Nils Kilden-Pedersen

I did try that, but it failed:

java.lang.IllegalStateException: s=HANDLING rs=BLOCKING os=OPEN is=READY awp=false se=false i=true al=0
        at org.eclipse.jetty.server.Request.getAsyncContext(Request.java:592)

I didn’t pursue this much further, because it seemed to be fundamentally brittle.

Also, isn’t the response fully committed when AsyncContext.complete() is called, i.e. it’s too late to set headers, such as cookies?



On Mon, Nov 11, 2019 at 4:42 PM Simone Bordet <[hidden email]> wrote:
Hi,

On Mon, Nov 11, 2019 at 5:25 PM Nils Kilden-Pedersen <[hidden email]> wrote:
>
> I can't seem to find much information on how to code async filters.
>
> Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

You use Servlet's AsyncListener and implement onComplete().

--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users

_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
Reply | Threaded
Open this post in threaded view
|

Re: Async filters

Simone Bordet-3
Hi,

On Tue, Nov 12, 2019 at 3:26 PM Nils Kilden-Pedersen <[hidden email]> wrote:
>
> I did try that, but it failed:
>
> java.lang.IllegalStateException: s=HANDLING rs=BLOCKING os=OPEN is=READY awp=false se=false i=true al=0
>         at org.eclipse.jetty.server.Request.getAsyncContext(Request.java:592)

This is probably because you did not call request.startAsync().

> I didn’t pursue this much further, because it seemed to be fundamentally brittle.

It's not brittle, it's defined by the Servlet Specification and it's
the standard way to go.
Very likely your code is not correct.

> Also, isn’t the response fully committed when AsyncContext.complete() is called, i.e. it’s too late to set headers, such as cookies?

It's the application that calls AsyncContext.complete(), so you are in control.

Perhaps you should detail more your use case. If the cookie depends on
what the rest of the application does, then kind of seems wrong to set
it in a filter.

--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
Reply | Threaded
Open this post in threaded view
|

Re: Async filters

Joakim Erdfelt-8
In reply to this post by Nils Kilden-Pedersen
AsyncContext within a Filter is not brittle.

We have a DoSFilter that uses it just fine.
 https://github.com/eclipse/jetty.project/blob/jetty-9.4.x/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java

AsyncContext itself has many rules that you have to follow.

Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

"At the very end of the request" would be well after the committed state has been reached.
Once you have a committed response you cannot change the headers any more as the response headers have been sent already, this is normal servlet behavior, and applies to all usages (async or not).

Unfortunately, there's no servlet mechanism to hook into the "about to go committed" event.

Cookies are special and will be applied regardless of the dispatch (normal, async, error, include, forward, etc).
They will never be cleared / rewritten by servlet container behaviors once set.
Why do you want to wait till the end of the request to set it?
Why not set the Cookie before you execute the filter chain?

While the HTTP spec has a concept of Trailers, which would allow for setting Cookies after the request, using Trailers from within the Servlet spec isn't easy.
And not all HTTP clients (some browsers included) support Trailers.

Joakim Erdfelt / [hidden email]


On Tue, Nov 12, 2019 at 8:26 AM Nils Kilden-Pedersen <[hidden email]> wrote:

I did try that, but it failed:

java.lang.IllegalStateException: s=HANDLING rs=BLOCKING os=OPEN is=READY awp=false se=false i=true al=0
        at org.eclipse.jetty.server.Request.getAsyncContext(Request.java:592)

I didn’t pursue this much further, because it seemed to be fundamentally brittle.

Also, isn’t the response fully committed when AsyncContext.complete() is called, i.e. it’s too late to set headers, such as cookies?



On Mon, Nov 11, 2019 at 4:42 PM Simone Bordet <[hidden email]> wrote:
Hi,

On Mon, Nov 11, 2019 at 5:25 PM Nils Kilden-Pedersen <[hidden email]> wrote:
>
> I can't seem to find much information on how to code async filters.
>
> Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

You use Servlet's AsyncListener and implement onComplete().

--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users

_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
Reply | Threaded
Open this post in threaded view
|

Re: Async filters

Nils Kilden-Pedersen
In reply to this post by Simone Bordet-3
On Tue, Nov 12, 2019 at 8:44 AM Simone Bordet <[hidden email]> wrote:
Hi,

On Tue, Nov 12, 2019 at 3:26 PM Nils Kilden-Pedersen <[hidden email]> wrote:
>
> I did try that, but it failed:
>
> java.lang.IllegalStateException: s=HANDLING rs=BLOCKING os=OPEN is=READY awp=false se=false i=true al=0
>         at org.eclipse.jetty.server.Request.getAsyncContext(Request.java:592)

This is probably because you did not call request.startAsync().

Correct.
 

> I didn’t pursue this much further, because it seemed to be fundamentally brittle.

It's not brittle, it's defined by the Servlet Specification and it's
the standard way to go.
Very likely your code is not correct.

> Also, isn’t the response fully committed when AsyncContext.complete() is called, i.e. it’s too late to set headers, such as cookies?

It's the application that calls AsyncContext.complete(), so you are in control.

Well, yes :-)

It’s about separation of concerns. The purpose of the filter is to do certain behavior across a number of servlets. If I have to implement the filter code inside each servlet, when complete() is called, then it sort of defeats the purpose, no?


 

Perhaps you should detail more your use case. If the cookie depends on
what the rest of the application does, then kind of seems wrong to set
it in a filter.

Why? The cookie contains information that depends on the outcome of various requests and in multiple steps. I started out setting it in the servlet(s), but ended up with multiple Set-Cookie. The filter is to ensure a single point of setting the cookie, which is easy in a sync servlet, but problematic (it seems) with async.


 

--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users

_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
Reply | Threaded
Open this post in threaded view
|

Re: Async filters

Nils Kilden-Pedersen
In reply to this post by Joakim Erdfelt-8

On Tue, Nov 12, 2019 at 8:44 AM Joakim Erdfelt <[hidden email]> wrote:
AsyncContext within a Filter is not brittle.

We have a DoSFilter that uses it just fine.
 https://github.com/eclipse/jetty.project/blob/jetty-9.4.x/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java

AsyncContext itself has many rules that you have to follow.

Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

"At the very end of the request" would be well after the committed state has been reached.
Once you have a committed response you cannot change the headers any more as the response headers have been sent already, this is normal servlet behavior, and applies to all usages (async or not).

I wasn't clear enough, before committing obviously.
 

Unfortunately, there's no servlet mechanism to hook into the "about to go committed" event.

My solution, which may fail in certain edge cases, was to wrap the response and set the cookie when `setStatus` is called, which generally only happens when result is about to be committed. This works fine (for now), but obviously is also a little brittle, as it relies on assumptions that doesn't always hold.
 
Cookies are special and will be applied regardless of the dispatch (normal, async, error, include, forward, etc).
They will never be cleared / rewritten by servlet container behaviors once set.
Why do you want to wait till the end of the request to set it?
Why not set the Cookie before you execute the filter chain?

The content is dependent on what happens in multiple steps in the servlet(s), as I explained in my response to Simon.
 

While the HTTP spec has a concept of Trailers, which would allow for setting Cookies after the request, using Trailers from within the Servlet spec isn't easy.
And not all HTTP clients (some browsers included) support Trailers.

Right, isn't that the problem with getting gRPC to work natively in browsers?


 

Joakim Erdfelt / [hidden email]


On Tue, Nov 12, 2019 at 8:26 AM Nils Kilden-Pedersen <[hidden email]> wrote:

I did try that, but it failed:

java.lang.IllegalStateException: s=HANDLING rs=BLOCKING os=OPEN is=READY awp=false se=false i=true al=0
        at org.eclipse.jetty.server.Request.getAsyncContext(Request.java:592)

I didn’t pursue this much further, because it seemed to be fundamentally brittle.

Also, isn’t the response fully committed when AsyncContext.complete() is called, i.e. it’s too late to set headers, such as cookies?



On Mon, Nov 11, 2019 at 4:42 PM Simone Bordet <[hidden email]> wrote:
Hi,

On Mon, Nov 11, 2019 at 5:25 PM Nils Kilden-Pedersen <[hidden email]> wrote:
>
> I can't seem to find much information on how to code async filters.
>
> Basically, how do I know when the filter chain has completed? I need to set a cookie, but only at the very end of the request.

You use Servlet's AsyncListener and implement onComplete().

--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users
_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users

_______________________________________________
jetty-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://www.eclipse.org/mailman/listinfo/jetty-users