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:
parent
39e83a6583
commit
8c7f1a699a
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue