Supplementing redirect rules with RedirectUtil

+ Redirect rules should produce full URI for "Location" header
+ Redirect rules should produce no response body content
This commit is contained in:
Joakim Erdfelt 2015-07-23 13:27:43 -07:00
parent e24cc3ee5e
commit 0476d4d28d
5 changed files with 101 additions and 14 deletions

View File

@ -73,8 +73,11 @@ public class RedirectPatternRule extends PatternRule
@Override
public String apply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
{
response.setHeader("Location",response.encodeRedirectURL(_location));
response.sendError(_statusCode);
String location = response.encodeRedirectURL(_location);
response.setHeader("Location",RedirectUtil.toRedirectURL(request,location));
response.setStatus(_statusCode);
response.getOutputStream().flush(); // no output / content
response.getOutputStream().close();
return target;
}

View File

@ -83,9 +83,12 @@ public class RedirectRegexRule extends RegexRule
String group = matcher.group(g);
target=target.replaceAll("\\$"+g,group);
}
response.setHeader("Location",response.encodeRedirectURL(target));
response.sendError(_statusCode);
target = response.encodeRedirectURL(target);
response.setHeader("Location",RedirectUtil.toRedirectURL(request,target));
response.setStatus(_statusCode);
response.getOutputStream().flush(); // no output / content
response.getOutputStream().close();
return target;
}

View File

@ -0,0 +1,71 @@
//
// ========================================================================
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.rewrite.handler;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.util.URIUtil;
/**
* Utility for managing redirect based rules
*/
public final class RedirectUtil
{
/**
* Common point to generate a proper "Location" header for redirects.
*
* @param request
* the request the redirect should be based on (needed when relative locations are provided, so that
* server name, scheme, port can be built out properly)
* @param location
* the location URL to redirect to (can be a relative path)
* @return the full redirect "Location" URL (including scheme, host, port, path, etc...)
*/
public static String toRedirectURL(final HttpServletRequest request, String location)
{
if (!URIUtil.hasScheme(location))
{
StringBuilder url = new StringBuilder(128);
URIUtil.appendSchemeHostPort(url,request.getScheme(),request.getServerName(),request.getServerPort());
if (location.startsWith("/"))
{
// absolute in context
location = URIUtil.canonicalPath(location);
}
else
{
// relative to request
String path = request.getRequestURI();
String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path);
location = URIUtil.canonicalPath(URIUtil.addPaths(parent,location));
if (!location.startsWith("/"))
url.append('/');
}
if (location == null)
throw new IllegalStateException("path cannot be above root");
url.append(location);
location = url.toString();
}
return location;
}
}

View File

@ -53,6 +53,18 @@ public class RedirectRegexRuleTest extends AbstractRuleTestCase
rule.matchAndApply("/my/dir/file/", _request, _response);
assertRedirectResponse(HttpStatus.FOUND_302,"http://www.mortbay.org/");
}
@Test
public void testLocationWithPathReplacement() throws IOException
{
RedirectRegexRule rule = new RedirectRegexRule();
rule.setRegex("/documentation/(.*)$");
rule.setReplacement("/docs/$1");
// Resource is dir
rule.matchAndApply("/documentation/top.html", _request, _response);
assertRedirectResponse(HttpStatus.FOUND_302,"http://0.0.0.0/docs/top.html");
}
@Test
public void testLocationWithReplacmentGroupSimple() throws IOException

View File

@ -18,10 +18,8 @@
package org.eclipse.jetty.test.rfcs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
@ -1159,12 +1157,12 @@ public abstract class RFC2616BaseTest
req4.append("\n");
HttpTester.Response response = http.request(req4);
String specId = "10.3 Redirection HTTP/1.1 w/content";
assertEquals(specId,HttpStatus.FOUND_302, response.getStatus());
assertEquals(specId,server.getScheme() + "://localhost/tests/R2.txt", response.get("Location"));
assertEquals(specId,"close", response.get("Connection"));
assertTrue(specId,response.get("Content-Length") == null);
assertThat(specId + " [status]",response.getStatus(),is(HttpStatus.FOUND_302));
assertThat(specId + " [location]",response.get("Location"),is(server.getScheme() + "://localhost/tests/R2.txt"));
assertThat(specId + " [connection]",response.get("Connection"),is("close"));
assertThat(specId + " [content-length]",response.get("Content-Length"), nullValue());
}
/**