diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java index e15051f16c3..03588f146bf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java @@ -23,12 +23,14 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Evolving; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.http.HtmlQuoting; import org.apache.hadoop.http.HttpConfig.Policy; import org.apache.hadoop.http.HttpServer2; import org.apache.hadoop.net.NetUtils; @@ -40,6 +42,10 @@ import org.apache.hadoop.yarn.util.RMHAUtils; import org.apache.hadoop.yarn.webapp.BadRequestException; import org.apache.hadoop.yarn.webapp.NotFoundException; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; + +import javax.servlet.http.HttpServletRequest; @Private @Evolving @@ -399,4 +405,49 @@ public static ApplicationId parseApplicationId(RecordFactory recordFactory, } return aid; } + + private static String getURLEncodedQueryString(HttpServletRequest request) { + String queryString = request.getQueryString(); + if (queryString != null && !queryString.isEmpty()) { + String reqEncoding = request.getCharacterEncoding(); + if (reqEncoding == null || reqEncoding.isEmpty()) { + reqEncoding = "ISO-8859-1"; + } + Charset encoding = Charset.forName(reqEncoding); + List params = URLEncodedUtils.parse(queryString, encoding); + return URLEncodedUtils.format(params, encoding); + } + return null; + } + + /** + * Get a HTML escaped uri with the query parameters of the request. + * @param request HttpServletRequest with the request details + * @return HTML escaped uri with the query paramters + */ + public static String getHtmlEscapedURIWithQueryString( + HttpServletRequest request) { + String urlEncodedQueryString = getURLEncodedQueryString(request); + if (urlEncodedQueryString != null) { + return HtmlQuoting.quoteHtmlChars( + request.getRequestURI() + "?" + urlEncodedQueryString); + } + return HtmlQuoting.quoteHtmlChars(request.getRequestURI()); + } + + /** + * Add the query params from a HttpServletRequest to the target uri passed. + * @param request HttpServletRequest with the request details + * @param targetUri the uri to which the query params must be added + * @return URL encoded string containing the targetUri + "?" + query string + */ + public static String appendQueryParams(HttpServletRequest request, + String targetUri) { + String ret = targetUri; + String urlEncodedQueryString = getURLEncodedQueryString(request); + if (urlEncodedQueryString != null) { + ret += "?" + urlEncodedQueryString; + } + return ret; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java index dcc8ba4a8af..d6f78b18c1b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java @@ -39,6 +39,9 @@ import org.junit.BeforeClass; import org.junit.Assert; import org.junit.Test; +import org.mockito.Mockito; + +import javax.servlet.http.HttpServletRequest; public class TestWebAppUtils { private static final String RM1_NODE_ID = "rm1"; @@ -176,6 +179,45 @@ protected Configuration provisionCredentialsForSSL() throws IOException, return conf; } + @Test + public void testAppendQueryParams() throws Exception { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + String targetUri = "/test/path"; + Mockito.when(request.getCharacterEncoding()).thenReturn(null); + Map paramResultMap = new HashMap<>(); + paramResultMap.put("param1=x", targetUri + "?" + "param1=x"); + paramResultMap + .put("param1=x¶m2=y", targetUri + "?" + "param1=x¶m2=y"); + paramResultMap.put("param1=x¶m2=y¶m3=x+y", + targetUri + "?" + "param1=x¶m2=y¶m3=x+y"); + + for (Map.Entry entry : paramResultMap.entrySet()) { + Mockito.when(request.getQueryString()).thenReturn(entry.getKey()); + String uri = WebAppUtils.appendQueryParams(request, targetUri); + Assert.assertEquals(entry.getValue(), uri); + } + } + + @Test + public void testGetHtmlEscapedURIWithQueryString() throws Exception { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + String targetUri = "/test/path"; + Mockito.when(request.getCharacterEncoding()).thenReturn(null); + Mockito.when(request.getRequestURI()).thenReturn(targetUri); + Map paramResultMap = new HashMap<>(); + paramResultMap.put("param1=x", targetUri + "?" + "param1=x"); + paramResultMap + .put("param1=x¶m2=y", targetUri + "?" + "param1=x&param2=y"); + paramResultMap.put("param1=x¶m2=y¶m3=x+y", + targetUri + "?" + "param1=x&param2=y&param3=x+y"); + + for (Map.Entry entry : paramResultMap.entrySet()) { + Mockito.when(request.getQueryString()).thenReturn(entry.getKey()); + String uri = WebAppUtils.getHtmlEscapedURIWithQueryString(request); + Assert.assertEquals(entry.getValue(), uri); + } + } + public class TestBuilder extends HttpServer2.Builder { public String keypass; public String keystorePassword; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java index 63fe6ea75b2..d2f5849f32b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java @@ -38,6 +38,7 @@ import org.apache.hadoop.yarn.webapp.Controller.RequestContext; import com.google.inject.Injector; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; +import org.apache.hadoop.yarn.webapp.util.WebAppUtils; @Singleton public class NMWebAppFilter extends GuiceContainer{ @@ -58,8 +59,7 @@ public NMWebAppFilter(Injector injector, Context nmContext) { public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { - String uri = HtmlQuoting.quoteHtmlChars(request.getRequestURI()); - String redirectPath = containerLogPageRedirectPath(uri); + String redirectPath = containerLogPageRedirectPath(request); if (redirectPath != null) { String redirectMsg = "Redirecting to log server" + " : " + redirectPath; @@ -72,7 +72,8 @@ public void doFilter(HttpServletRequest request, super.doFilter(request, response, chain); } - private String containerLogPageRedirectPath(String uri) { + private String containerLogPageRedirectPath(HttpServletRequest request) { + String uri = HtmlQuoting.quoteHtmlChars(request.getRequestURI()); String redirectPath = null; if (!uri.contains("/ws/v1/node") && uri.contains("/containerlogs")) { String[] parts = uri.split("/"); @@ -105,7 +106,8 @@ private String containerLogPageRedirectPath(String uri) { sb.append(containerIdStr); sb.append("/"); sb.append(appOwner); - redirectPath = sb.toString(); + redirectPath = + WebAppUtils.appendQueryParams(request, sb.toString()); } else { injector.getInstance(RequestContext.class).set( ContainerLogsPage.REDIRECT_URL, "false"); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppFilter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppFilter.java index 0f1a590dfbe..1e4caba2ff9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppFilter.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppFilter.java @@ -25,8 +25,6 @@ import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.util.List; import java.util.Random; import java.util.Set; @@ -50,8 +48,6 @@ import org.apache.hadoop.yarn.util.ConverterUtils; import org.apache.hadoop.yarn.webapp.YarnWebParams; import org.apache.hadoop.yarn.webapp.util.WebAppUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URLEncodedUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,22 +112,10 @@ public void doFilter(HttpServletRequest request, htmlEscapedUri = "/"; } - String uriWithQueryString = htmlEscapedUri; - String htmlEscapedUriWithQueryString = htmlEscapedUri; - - String queryString = request.getQueryString(); - if (queryString != null && !queryString.isEmpty()) { - String reqEncoding = request.getCharacterEncoding(); - if (reqEncoding == null || reqEncoding.isEmpty()) { - reqEncoding = "ISO-8859-1"; - } - Charset encoding = Charset.forName(reqEncoding); - List params = URLEncodedUtils.parse(queryString, encoding); - String urlEncodedQueryString = URLEncodedUtils.format(params, encoding); - uriWithQueryString += "?" + urlEncodedQueryString; - htmlEscapedUriWithQueryString = HtmlQuoting.quoteHtmlChars( - request.getRequestURI() + "?" + urlEncodedQueryString); - } + String uriWithQueryString = + WebAppUtils.appendQueryParams(request, htmlEscapedUri); + String htmlEscapedUriWithQueryString = + WebAppUtils.getHtmlEscapedURIWithQueryString(request); RMWebApp rmWebApp = injector.getInstance(RMWebApp.class); rmWebApp.checkIfStandbyRM();