FarmHand
FarmHand

Reputation: 771

ResponseEntity with HTTP Location header not causing redirect

A Spring MVC controller needs to redirect the control flow of an app to a different url endpoint within the same app. But the current code is returning a blank page along with response headers that include the intended destination url as the forward header. When the contents of the forward header is pasted into the web browser, the intended endpoint is successfully called. What specific changes need to be made to the code below in order for the POST controller to successfully redirect the control flow to the intended destination endpoint instead of returning a blank page?

Here is the code for the Controller method:

@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<?> auth(FormData formData, HttpServletRequest req, HttpServletResponse resp) {
    System.out.println("11111111111111 inside POST");
    HttpHeaders responseHeaders = new HttpHeaders();
    boolean passedTheTest = true;//ACTUAL LOGIC IS OMITTED HERE FOR SIMPLICITY
    if (passedTheTest) {
        //SOME OFF TOPIC LOGIC HERE IS OMITTED
        CsrfToken csrf = (CsrfToken) req.getAttribute(CsrfToken.class.getName());
        String updateCsrf = csrf.getToken();
        responseHeaders.set("XSRF-TOKEN", updateCsrf);
        if(resp.getHeaders("Cache-Control")!=null){responseHeaders.put("Cache-Control" , new ArrayList<String>(resp.getHeaders("Cache-Control")));}
        if(resp.getHeader("Content-Language")!=null){responseHeaders.set("Content-Language" , resp.getHeader("Content-Language"));}
        if(resp.getHeader("Content-Length")!=null){responseHeaders.set("Content-Length" , resp.getHeader("Content-Length"));}
        if(resp.getHeader("Date")!=null){responseHeaders.set("Date" , resp.getHeader("Date"));}
        if(resp.getHeader("Expires")!=null){responseHeaders.set("Expires" , resp.getHeader("Expires"));}
        if(resp.getHeader("Pragma")!=null){responseHeaders.set("Pragma" , resp.getHeader("Pragma"));}
        if(resp.getHeader("Server")!=null){responseHeaders.set("Server" , resp.getHeader("Server"));}
        if(resp.getHeader("X-Application-Context")!=null){responseHeaders.set("X-Application-Context" , resp.getHeader("X-Application-Context"));}
        if(resp.getHeader("X-Frame-Options")!=null){responseHeaders.set("X-Frame-Options" , resp.getHeader("X-Frame-Options"));}
        if(resp.getHeader("X-XSS-Protection")!=null){responseHeaders.set("X-XSS-Protection" , resp.getHeader("X-XSS-Protection"));}
        if(resp.getHeader("x-content-type-options")!=null){responseHeaders.set("x-content-type-options" , resp.getHeader("x-content-type-options"));}
        if(req.getSession().getAttribute("forwardTo")!=null){
            String redirectTo = getValidUriFromAnotherFunction();
            try {
                URI location = new URI(redirectTo);
                responseHeaders.setLocation(location);
            } catch (URISyntaxException e) {e.printStackTrace();}
            ResponseEntity<Void> forwardResponseEntity = new ResponseEntity<Void>(responseHeaders, HttpStatus.CREATED);                 
            return forwardResponseEntity;
        }
    };
    return new ResponseEntity<String>("aDifferentViewTemplateName", responseHeaders, HttpStatus.CREATED);
}

The request headers in the browser's developer tools are:

Host: localhost:7777
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:7777/path/to/controller_method
Cookie: JSESSIONID=911B34457B69F7729091DD97A160AD79; JSESSIONID=95AA730306330CF15E3776C495807354; XSRF-TOKEN=04ae2a0c-3c58-4e85-88bd-3818bb10402a
Connection: keep-alive

The response headers for the same POST are:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate, no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Sun, 29 May 2016 21:48:24 GMT
Expires: 0, 0
Location: http://localhost:7777/path/to/forward_destination?long_querystring
Pragma: no-cache, no-cache
Server: Apache-Coyote/1.1
X-Application-Context: application:7777, application:7777
X-Content-Type-Options: nosniff, nosniff
X-Frame-Options: DENY, DENY
X-XSS-Protection: 1; mode=block, 1; mode=block
XSRF-TOKEN: 04ae2a0c-3c58-4e85-88bd-3818bb10402a

The Spring Boot debug log for the same POST includes three sections, which have been separated as follows for improved readability:

Section of debug log that shows the SYSO inside the controller:

11111111111111 inside POST
redirectTo is: http://localhost:7777/path/to/forward_destination?long_querystring

Section of debug log AFTER the controller (most important?):

2016-05-29 14:48:24.489 DEBUG 5533 --- [io-7777-exec-10] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
2016-05-29 14:48:24.489 DEBUG 5533 --- [io-7777-exec-10] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@42259e42: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@42259e42: Principal: org.springframework.security.core.userdetails.User@40fecce: Username: SomeUser; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ONE,ROLE_TWO; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffe3f86: RemoteIpAddress: 127.0.0.1; SessionId: 02A95844E8A829868542290D471503F5; Granted Authorities: ROLE_ONE, ROLE_TWO, ROLE_THREE' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@64307ead
2016-05-29 14:48:24.489 DEBUG 5533 --- [io-7777-exec-10] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

Upvotes: 3

Views: 5319

Answers (1)

notImportant
notImportant

Reputation: 66

Instead of returning the 201 Created status code you should return a 3XX status code to ask the user agent to load a different web page. Otherwise the Location header has no "special" meaning.

So for example you can write:

ResponseEntity<Void> forwardResponseEntity = new ResponseEntity<Void>(responseHeaders, HttpStatus.MOVED_PERMANENTLY);

Upvotes: 5

Related Questions