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

Redirect from HTTP filter does not work #6

Closed
mknauer opened this issue Apr 28, 2022 · 12 comments
Closed

Redirect from HTTP filter does not work #6

mknauer opened this issue Apr 28, 2022 · 12 comments

Comments

@mknauer
Copy link
Contributor

mknauer commented Apr 28, 2022

Copy of Bugzilla bug 579790

Example project showing the issue: example.redirect.zip (@mknauer: added target definition, launch configuration, modified dependencies)

When trying to redirect from an HTTP filter (extension org.eclipse.equinox.http.registry.filters), it fails with the following details:

Error: SyntaxError: Unexpected end of JSON input

  Stack: SyntaxError: Unexpected end of JSON input
    at JSON.parse ()
    at Object._handleSuccess (http://vm-uablochberg2:8080/rwt-resources/3180/rap-client.js:230:3602)
    at rwt.remote.Request._success (http://vm-uablochberg2:8080/rwt-resources/3180/rap-client.js:98:925)
    at rwt.remote.Request._onReadyStateChange (http://vm-uablochberg2:8080/rwt-resources/3180/rap-client.js:98:1596)
    at XMLHttpRequest. (http://vm-uablochberg2:8080/rwt-resources/3180/rap-client.js:7:219)
  Debug: off
  Request: {"head":{"requestCounter":3},"operations":[["notify","w6","FocusOut",{}],["set","w2",{"activeControl":"w2"}],["set","w1",{"cursorLocation":[394,277],"focusControl":"w2"}]]}

In the attached example project, there are four different methods for redirecting. But when called in the filter handler, even the JSON redirect does not work.

Is there some other way to make the redirect work from filter code (because this is needed for openID connect authentication)?

It would be best if HttpServletResponse.sendRedirect() would work in any circumstance.

@ablochberger
Copy link

RAP version used: 3.18

@mknauer
Copy link
Contributor Author

mknauer commented Apr 29, 2022

Thanks, RAP 3.18, or to be more precise, RAP <3.21 reflects my theory, because with 3.21 M1 we changed the implementation from XHR to fetch in order to support such use cases.

I'll discuss this with @ifurnadjiev next week before building our M2.

@ifurnadjiev
Copy link
Contributor

Please try the latest stable build 3.21 M1 from our download page [1] and let us know if it's working for you.

[1] https://www.eclipse.org/rap/downloads/

@ablochberger
Copy link

I've tested with target platform https://download.eclipse.org/rt/rap/3.21/M1-20220415-1308/

The redirect with sendResponse now seems to do nothing (no error message)
The redirect from the filter class now shows the message: The application terminated unexpectedly with the following details:

Error: SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data

  Stack: _handleSuccess@http://localhost:8080/rwt-resources/3210/rap-client.js:230:3729
setSuccessHandler/this._success@http://localhost:8080/rwt-resources/3210/rap-client.js:98:784
_sendWithFetch/

@ifurnadjiev
Copy link
Contributor

ifurnadjiev commented May 2, 2022

Try:

public class RedirectFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest r = (HttpServletRequest) request;
    HttpSession session = r.getSession();
    String url = (String) session.getAttribute("redirect");
    Display display = (Display) session.getAttribute("display");
    if (display != null && url != null) {
      session.removeAttribute("redirect");
      session.removeAttribute("display");
      ProtocolMessageWriter messageWriter = new ProtocolMessageWriter();
      messageWriter.appendHead("redirect", url);
      messageWriter.createMessage().toJson().writeTo( response.getWriter() );
    } else {
      chain.doFilter(request, response);
    }
  }
}

@ifurnadjiev
Copy link
Contributor

In your example response.sendRedirect(url) is not working because of CORS.

@ablochberger
Copy link

Thanks Ivan, the method with the ProtocolMessageWriter is working fine. But it does not work in the UI thread. Something like this works in any circumstance:

    public static void redirect( ServletResponse response, String url )
        throws IOException
    {
        if( Display.getCurrent() == null )
        {
            ProtocolMessageWriter messageWriter = new ProtocolMessageWriter();
            messageWriter.appendHead( "redirect", url );
            messageWriter.createMessage()
                .toJson()
                .writeTo( response.getWriter() );
        }
        else
        {
            ContextProvider.getProtocolWriter()
                .appendHead( "redirect", url );
        }
    }

@ablochberger
Copy link

The above code also works in RAP 3.18

@ablochberger
Copy link

But still there is one problem, when RAP is not yet loaded, the redirect does not work, because there is no script yet to execute the redirect. In this case I need to redirect with HttpServletRespone.sendRedirect

There are this three situations:

  1. RAP not yet loaded, filter must redirect with HttpServletRespone.sendRedirect
  2. RAP loaded, code in UI-Thread must redirect with ContextProvider
  3. RAP loaded, code in non UI-Thread must redirect with ProtocolMessageWriter

I can detect 2 and 3, but not 1. Is there a way to tell, that RAP has not yet loaded on the client from a server side filter?
In the first case, a redirect with ProtocolMessageWriter would then only show the JSON in the browser

@ablochberger
Copy link

In this example, the first redirect then fails (Redirect.to contains the code from above):

    @Override
    public void doFilter( ServletRequest request, ServletResponse response,
        FilterChain chain ) throws IOException, ServletException
    {
        HttpServletRequest r = (HttpServletRequest)request;
        HttpSession session = r.getSession();
        Boolean first = (Boolean)session.getAttribute( "first" );
        if( first == null )
        {
            session.setAttribute( "first", true );
            Redirect.to( response, "http://some-auth-server:8080" );
        }
        else
        {
            String url = (String)session.getAttribute( "redirect" );
            if( url != null )
            {
                session.removeAttribute( "redirect" );

                Redirect.to( response, url );
            }
            else
                chain.doFilter( request, response );
        }
    }

Resulting with the page showing
{"head":{"redirect":"http://some-auth-server:8080"},"operations":[]}

@ifurnadjiev
Copy link
Contributor

ifurnadjiev commented May 2, 2022

Usually the first request is a GET request, the other (after UI session is initialized) are POST. You could try to build something around it. Please note that ServerPush requests are also GET requests and you have to recognize them by "servicehandler" property.

@ablochberger
Copy link

So I can use HttpServletResponse.sendRedirect on GET requests that do not have the parameter servicehandler set.
The GET criteria works in my sample, I'll fix my redirect in my actual code (that uses ServerPushes) next then. Thanks for the heads up for the server push, I would have certainly missed that

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

3 participants