From 8c7f1a699a65738220dd08a130295804cad32a32 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Tue, 13 Aug 2019 23:59:50 +0200 Subject: [PATCH] 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 --- .../http/test/SmartClientSmartServerTest.java | 41 ++++++++++++++++++- .../eclipse/jgit/transport/TransportHttp.java | 21 ++++++---- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 54c1c03b5..32fc677fb 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -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); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java index d5b06c1f6..c523cbf05 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -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);