TransportHttp: resolve redirect URIs from the "Location" header

The "Location" header in a redirect response may contain a relative
URI. Resolve it against the URI the request was made.

Bug: 550033
Change-Id: I29de07dfbbbc794090821b7c190cb2cf662c5a60
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
Thomas Wolf 2019-08-13 23:59:50 +02:00 committed by Matthias Sohn
parent 39e83a6583
commit 8c7f1a699a
2 changed files with 53 additions and 9 deletions

View File

@ -56,6 +56,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.Arrays;
@ -340,6 +341,23 @@ public void init(FilterConfig filterConfig)
// empty
}
private String local(String url, boolean toLocal) {
if (!toLocal) {
return url;
}
try {
URI u = new URI(url);
String fragment = u.getRawFragment();
if (fragment != null) {
return u.getRawPath() + '#' + fragment;
} else {
return u.getRawPath();
}
} catch (URISyntaxException e) {
return url;
}
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
@ -352,6 +370,11 @@ public void doFilter(ServletRequest request,
.append(httpServletRequest.getQueryString());
}
String urlString = fullUrl.toString();
boolean localRedirect = false;
if (urlString.contains("/local")) {
urlString = urlString.replace("/local", "");
localRedirect = true;
}
if (urlString.contains("/loop/")) {
urlString = urlString.replace("/loop/", "/loop/x/");
if (urlString.contains("/loop/x/x/x/x/x/x/x/x/")) {
@ -362,7 +385,7 @@ public void doFilter(ServletRequest request,
httpServletResponse.setStatus(
HttpServletResponse.SC_MOVED_TEMPORARILY);
httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
urlString);
local(urlString, localRedirect));
return;
}
int responseCode = HttpServletResponse.SC_MOVED_PERMANENTLY;
@ -392,9 +415,10 @@ public void doFilter(ServletRequest request,
targetContext = matcher.group(1);
}
urlString = urlString.replace("/redirect", targetContext);
}
httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
urlString);
local(urlString, localRedirect));
}
@Override
@ -561,7 +585,15 @@ public void testInitialClone_Small() throws Exception {
private void initialClone_Redirect(int nofRedirects, int code)
throws Exception {
initialClone_Redirect(nofRedirects, code, false);
}
private void initialClone_Redirect(int nofRedirects, int code,
boolean localRedirect) throws Exception {
URIish cloneFrom = redirectURI;
if (localRedirect) {
cloneFrom = extendPath(cloneFrom, "/local");
}
if (code != 301 || nofRedirects > 1) {
cloneFrom = extendPath(cloneFrom,
"/response/" + nofRedirects + "/" + code);
@ -614,6 +646,11 @@ public void testInitialClone_Redirect301Small() throws Exception {
initialClone_Redirect(1, 301);
}
@Test
public void testInitialClone_Redirect301Local() throws Exception {
initialClone_Redirect(1, 301, true);
}
@Test
public void testInitialClone_Redirect302Small() throws Exception {
initialClone_Redirect(1, 302);

View File

@ -77,6 +77,7 @@
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.InvalidPathException;
@ -593,7 +594,8 @@ private HttpConnection connect(String service)
JGitText.get().redirectsOff,
Integer.valueOf(status)));
}
URIish newUri = redirect(conn.getHeaderField(HDR_LOCATION),
URIish newUri = redirect(u,
conn.getHeaderField(HDR_LOCATION),
Constants.INFO_REFS, redirects++);
setURI(newUri);
u = getServiceURL(service);
@ -804,7 +806,8 @@ private void updateSslVerifyUser(boolean value) {
}
}
private URIish redirect(String location, String checkFor, int redirects)
private URIish redirect(URL currentUrl, String location, String checkFor,
int redirects)
throws TransportException {
if (location == null || location.isEmpty()) {
throw new TransportException(uri,
@ -818,13 +821,16 @@ private URIish redirect(String location, String checkFor, int redirects)
location));
}
try {
if (!isValidRedirect(baseUrl, location, checkFor)) {
URI redirectTo = new URI(location);
redirectTo = currentUrl.toURI().resolve(redirectTo);
String redirected = redirectTo.toASCIIString();
if (!isValidRedirect(baseUrl, redirected, checkFor)) {
throw new TransportException(uri,
MessageFormat.format(JGitText.get().redirectBlocked,
baseUrl, location));
baseUrl, redirected));
}
location = location.substring(0, location.indexOf(checkFor));
URIish result = new URIish(location);
redirected = redirected.substring(0, redirected.indexOf(checkFor));
URIish result = new URIish(redirected);
if (LOG.isInfoEnabled()) {
LOG.info(MessageFormat.format(JGitText.get().redirectHttp,
uri.setPass(null),
@ -1454,7 +1460,8 @@ void sendRequest() throws IOException {
// Let openResponse() issue an error
return;
}
currentUri = redirect(conn.getHeaderField(HDR_LOCATION),
currentUri = redirect(conn.getURL(),
conn.getHeaderField(HDR_LOCATION),
'/' + serviceName, redirects++);
try {
baseUrl = toURL(currentUri);