YARN-5246. NMWebAppFilter web redirects drop query parameters. Contributed by Varun Vasudev.
This commit is contained in:
parent
0319d73c3b
commit
d0162f2040
|
@ -23,6 +23,7 @@ import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -30,6 +31,7 @@ import java.util.List;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience.Private;
|
import org.apache.hadoop.classification.InterfaceAudience.Private;
|
||||||
import org.apache.hadoop.classification.InterfaceStability.Evolving;
|
import org.apache.hadoop.classification.InterfaceStability.Evolving;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.http.HtmlQuoting;
|
||||||
import org.apache.hadoop.http.HttpConfig.Policy;
|
import org.apache.hadoop.http.HttpConfig.Policy;
|
||||||
import org.apache.hadoop.http.HttpServer2;
|
import org.apache.hadoop.http.HttpServer2;
|
||||||
import org.apache.hadoop.net.NetUtils;
|
import org.apache.hadoop.net.NetUtils;
|
||||||
|
@ -42,6 +44,10 @@ import org.apache.hadoop.yarn.util.ConverterUtils;
|
||||||
import org.apache.hadoop.yarn.util.RMHAUtils;
|
import org.apache.hadoop.yarn.util.RMHAUtils;
|
||||||
import org.apache.hadoop.yarn.webapp.BadRequestException;
|
import org.apache.hadoop.yarn.webapp.BadRequestException;
|
||||||
import org.apache.hadoop.yarn.webapp.NotFoundException;
|
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
|
@Private
|
||||||
@Evolving
|
@Evolving
|
||||||
|
@ -418,4 +424,49 @@ public class WebAppUtils {
|
||||||
public static List<String> listSupportedLogContentType() {
|
public static List<String> listSupportedLogContentType() {
|
||||||
return Arrays.asList("text", "octet-stream");
|
return Arrays.asList("text", "octet-stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<NameValuePair> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,9 @@ import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
public class TestWebAppUtils {
|
public class TestWebAppUtils {
|
||||||
private static final String RM1_NODE_ID = "rm1";
|
private static final String RM1_NODE_ID = "rm1";
|
||||||
|
@ -176,6 +179,45 @@ public class TestWebAppUtils {
|
||||||
return conf;
|
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<String, String> 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<String, String> 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<String, String> 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<String, String> 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 class TestBuilder extends HttpServer2.Builder {
|
||||||
public String keypass;
|
public String keypass;
|
||||||
public String keystorePassword;
|
public String keystorePassword;
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.application.Ap
|
||||||
import org.apache.hadoop.yarn.webapp.Controller.RequestContext;
|
import org.apache.hadoop.yarn.webapp.Controller.RequestContext;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
|
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
|
||||||
|
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class NMWebAppFilter extends GuiceContainer{
|
public class NMWebAppFilter extends GuiceContainer{
|
||||||
|
@ -58,8 +59,7 @@ public class NMWebAppFilter extends GuiceContainer{
|
||||||
public void doFilter(HttpServletRequest request,
|
public void doFilter(HttpServletRequest request,
|
||||||
HttpServletResponse response, FilterChain chain) throws IOException,
|
HttpServletResponse response, FilterChain chain) throws IOException,
|
||||||
ServletException {
|
ServletException {
|
||||||
String uri = HtmlQuoting.quoteHtmlChars(request.getRequestURI());
|
String redirectPath = containerLogPageRedirectPath(request);
|
||||||
String redirectPath = containerLogPageRedirectPath(uri);
|
|
||||||
if (redirectPath != null) {
|
if (redirectPath != null) {
|
||||||
String redirectMsg =
|
String redirectMsg =
|
||||||
"Redirecting to log server" + " : " + redirectPath;
|
"Redirecting to log server" + " : " + redirectPath;
|
||||||
|
@ -72,7 +72,8 @@ public class NMWebAppFilter extends GuiceContainer{
|
||||||
super.doFilter(request, response, chain);
|
super.doFilter(request, response, chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String containerLogPageRedirectPath(String uri) {
|
private String containerLogPageRedirectPath(HttpServletRequest request) {
|
||||||
|
String uri = HtmlQuoting.quoteHtmlChars(request.getRequestURI());
|
||||||
String redirectPath = null;
|
String redirectPath = null;
|
||||||
if (!uri.contains("/ws/v1/node") && uri.contains("/containerlogs")) {
|
if (!uri.contains("/ws/v1/node") && uri.contains("/containerlogs")) {
|
||||||
String[] parts = uri.split("/");
|
String[] parts = uri.split("/");
|
||||||
|
@ -105,7 +106,8 @@ public class NMWebAppFilter extends GuiceContainer{
|
||||||
sb.append(containerIdStr);
|
sb.append(containerIdStr);
|
||||||
sb.append("/");
|
sb.append("/");
|
||||||
sb.append(appOwner);
|
sb.append(appOwner);
|
||||||
redirectPath = sb.toString();
|
redirectPath =
|
||||||
|
WebAppUtils.appendQueryParams(request, sb.toString());
|
||||||
} else {
|
} else {
|
||||||
injector.getInstance(RequestContext.class).set(
|
injector.getInstance(RequestContext.class).set(
|
||||||
ContainerLogsPage.REDIRECT_URL, "false");
|
ContainerLogsPage.REDIRECT_URL, "false");
|
||||||
|
|
|
@ -25,8 +25,6 @@ import java.io.PrintWriter;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -50,8 +48,6 @@ import org.apache.hadoop.yarn.util.Apps;
|
||||||
import org.apache.hadoop.yarn.util.ConverterUtils;
|
import org.apache.hadoop.yarn.util.ConverterUtils;
|
||||||
import org.apache.hadoop.yarn.webapp.YarnWebParams;
|
import org.apache.hadoop.yarn.webapp.YarnWebParams;
|
||||||
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -116,22 +112,10 @@ public class RMWebAppFilter extends GuiceContainer {
|
||||||
htmlEscapedUri = "/";
|
htmlEscapedUri = "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
String uriWithQueryString = htmlEscapedUri;
|
String uriWithQueryString =
|
||||||
String htmlEscapedUriWithQueryString = htmlEscapedUri;
|
WebAppUtils.appendQueryParams(request, htmlEscapedUri);
|
||||||
|
String htmlEscapedUriWithQueryString =
|
||||||
String queryString = request.getQueryString();
|
WebAppUtils.getHtmlEscapedURIWithQueryString(request);
|
||||||
if (queryString != null && !queryString.isEmpty()) {
|
|
||||||
String reqEncoding = request.getCharacterEncoding();
|
|
||||||
if (reqEncoding == null || reqEncoding.isEmpty()) {
|
|
||||||
reqEncoding = "ISO-8859-1";
|
|
||||||
}
|
|
||||||
Charset encoding = Charset.forName(reqEncoding);
|
|
||||||
List<NameValuePair> params = URLEncodedUtils.parse(queryString, encoding);
|
|
||||||
String urlEncodedQueryString = URLEncodedUtils.format(params, encoding);
|
|
||||||
uriWithQueryString += "?" + urlEncodedQueryString;
|
|
||||||
htmlEscapedUriWithQueryString = HtmlQuoting.quoteHtmlChars(
|
|
||||||
request.getRequestURI() + "?" + urlEncodedQueryString);
|
|
||||||
}
|
|
||||||
|
|
||||||
RMWebApp rmWebApp = injector.getInstance(RMWebApp.class);
|
RMWebApp rmWebApp = injector.getInstance(RMWebApp.class);
|
||||||
rmWebApp.checkIfStandbyRM();
|
rmWebApp.checkIfStandbyRM();
|
||||||
|
|
Loading…
Reference in New Issue