HDFS-1575. Viewing block from web UI is broken. Contributed by Aaron T. Myers.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/hdfs/trunk@1124575 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index 8d7231a..04aadb6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1021,6 +1021,8 @@
HDFS-1925. SafeModeInfo should use the correct constant instead of a
hard-coded value for its default. (Joey Echeverria via todd)
+ HDFS-1575. Viewing block from web UI is broken. (Aaron T. Myers via todd)
+
Release 0.21.1 - Unreleased
HDFS-1466. TestFcHdfsSymlink relies on /tmp/test not existing. (eli)
diff --git a/src/java/org/apache/hadoop/hdfs/server/common/JspHelper.java b/src/java/org/apache/hadoop/hdfs/server/common/JspHelper.java
index a41789f..704b4d7 100644
--- a/src/java/org/apache/hadoop/hdfs/server/common/JspHelper.java
+++ b/src/java/org/apache/hadoop/hdfs/server/common/JspHelper.java
@@ -586,12 +586,39 @@
}
/**
- * Returns the url parameter for the given bpid string.
+ * Returns the url parameter for the given string, prefixed with
+ * paramSeparator.
+ *
+ * @param name parameter name
+ * @param val parameter value
+ * @param paramSeparator URL parameter prefix, i.e. either '?' or '&'
+ * @return url parameter
+ */
+ public static String getUrlParam(String name, String val, String paramSeparator) {
+ return val == null ? "" : paramSeparator + name + "=" + val;
+ }
+
+ /**
+ * Returns the url parameter for the given string, prefixed with '?' if
+ * firstParam is true, prefixed with '&' if firstParam is false.
+ *
+ * @param name parameter name
+ * @param val parameter value
+ * @param firstParam true if this is the first parameter in the list, false otherwise
+ * @return url parameter
+ */
+ public static String getUrlParam(String name, String val, boolean firstParam) {
+ return getUrlParam(name, val, firstParam ? "?" : "&");
+ }
+
+ /**
+ * Returns the url parameter for the given string, prefixed with '&'.
+ *
* @param name parameter name
* @param val parameter value
* @return url parameter
*/
public static String getUrlParam(String name, String val) {
- return val == null ? "" : "&" + name + "=" + val;
+ return getUrlParam(name, val, false);
}
}
diff --git a/src/java/org/apache/hadoop/hdfs/server/datanode/DatanodeJspHelper.java b/src/java/org/apache/hadoop/hdfs/server/datanode/DatanodeJspHelper.java
index af1f907..15ac0f7 100644
--- a/src/java/org/apache/hadoop/hdfs/server/datanode/DatanodeJspHelper.java
+++ b/src/java/org/apache/hadoop/hdfs/server/datanode/DatanodeJspHelper.java
@@ -31,6 +31,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;
+import org.apache.commons.lang.StringEscapeUtils;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.DFSClient;
@@ -47,6 +48,7 @@
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.util.StringUtils;
+import org.mortbay.util.URIUtil;
@InterfaceAudience.Private
public class DatanodeJspHelper {
@@ -82,7 +84,8 @@
Configuration conf
) throws IOException,
InterruptedException {
- final String dir = JspHelper.validatePath(req.getParameter("dir"));
+ final String dir = StringEscapeUtils.unescapeHtml(
+ JspHelper.validatePath(req.getParameter("dir")));
if (dir == null) {
out.print("Invalid input");
return;
@@ -257,9 +260,11 @@
else
startOffset = Long.parseLong(startOffsetStr);
- final String filename=JspHelper.validatePath(
- req.getPathInfo() == null ?
- "/" : req.getPathInfo());
+ String path = StringEscapeUtils.unescapeHtml(req.getParameter("filename"));
+ if (path == null) {
+ path = req.getPathInfo() == null ? "/" : req.getPathInfo();
+ }
+ final String filename = JspHelper.validatePath(path);
if (filename == null) {
out.print("Invalid input");
return;
@@ -279,10 +284,9 @@
// Add the various links for looking at the file contents
// URL for downloading the full file
String downloadUrl = "http://" + req.getServerName() + ":"
- + req.getServerPort() + "/streamFile?" + "filename="
- + URLEncoder.encode(filename, "UTF-8")
- + JspHelper.getDelegationTokenUrlParam(tokenString)
- + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr);
+ + req.getServerPort() + "/streamFile" + URIUtil.encodePath(filename)
+ + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr, true)
+ + JspHelper.getDelegationTokenUrlParam(tokenString);
out.print("<a name=\"viewOptions\"></a>");
out.print("<a href=\"" + downloadUrl + "\">Download this file</a><br>");
@@ -396,7 +400,7 @@
namenodeInfoPort = Integer.parseInt(namenodeInfoPortStr);
final String filename = JspHelper
- .validatePath(req.getParameter("filename"));
+ .validatePath(StringEscapeUtils.unescapeHtml(req.getParameter("filename")));
if (filename == null) {
out.print("Invalid input (filename absent)");
return;
@@ -413,22 +417,25 @@
String bpid = null;
Token<BlockTokenIdentifier> blockToken = BlockTokenSecretManager.DUMMY_TOKEN;
- if (conf.getBoolean(
- DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY,
- DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_DEFAULT)) {
- List<LocatedBlock> blks = dfs.getNamenode().getBlockLocations(filename, 0,
- Long.MAX_VALUE).getLocatedBlocks();
- if (blks == null || blks.size() == 0) {
- out.print("Can't locate file blocks");
- dfs.close();
- return;
- }
- for (int i = 0; i < blks.size(); i++) {
- if (blks.get(i).getBlock().getBlockId() == blockId) {
- bpid = blks.get(i).getBlock().getBlockPoolId();
+ List<LocatedBlock> blks = dfs.getNamenode().getBlockLocations(filename, 0,
+ Long.MAX_VALUE).getLocatedBlocks();
+ if (blks == null || blks.size() == 0) {
+ out.print("Can't locate file blocks");
+ dfs.close();
+ return;
+ }
+
+ boolean needBlockToken = conf.getBoolean(
+ DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY,
+ DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_DEFAULT);
+
+ for (int i = 0; i < blks.size(); i++) {
+ if (blks.get(i).getBlock().getBlockId() == blockId) {
+ bpid = blks.get(i).getBlock().getBlockPoolId();
+ if (needBlockToken) {
blockToken = blks.get(i).getBlockToken();
- break;
}
+ break;
}
}
@@ -614,7 +621,7 @@
}
final String filename = JspHelper
- .validatePath(req.getParameter("filename"));
+ .validatePath(req.getParameter(StringEscapeUtils.unescapeHtml("filename")));
if (filename == null) {
out.print("Invalid input (file name absent)");
return;
diff --git a/src/test/hdfs/org/apache/hadoop/hdfs/server/datanode/TestDatanodeJsp.java b/src/test/hdfs/org/apache/hadoop/hdfs/server/datanode/TestDatanodeJsp.java
new file mode 100644
index 0000000..8926d90
--- /dev/null
+++ b/src/test/hdfs/org/apache/hadoop/hdfs/server/datanode/TestDatanodeJsp.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hdfs.server.datanode;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.URLEncoder;
+
+import org.apache.commons.httpclient.util.URIUtil;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hdfs.DFSTestUtil;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
+import org.apache.hadoop.hdfs.server.common.JspHelper;
+import org.junit.Test;
+
+public class TestDatanodeJsp {
+
+ private static final String FILE_DATA = "foo bar baz biz buz";
+
+ private static void testViewingFile(MiniDFSCluster cluster, String filePath) throws IOException {
+ FileSystem fs = cluster.getFileSystem();
+
+ Path testPath = new Path(filePath);
+ DFSTestUtil.writeFile(fs, testPath, FILE_DATA);
+
+ InetSocketAddress nnIpcAddress = cluster.getNameNode().getNameNodeAddress();
+ InetSocketAddress nnHttpAddress = cluster.getNameNode().getHttpAddress();
+ int dnInfoPort = cluster.getDataNodes().get(0).getInfoPort();
+
+ URL url = new URL("http://localhost:" + dnInfoPort + "/browseDirectory.jsp" +
+ JspHelper.getUrlParam("dir", URLEncoder.encode(testPath.toString(), "UTF-8"), true) +
+ JspHelper.getUrlParam("namenodeInfoPort", nnHttpAddress.getPort() +
+ JspHelper.getUrlParam("nnaddr", "localhost:" + nnIpcAddress.getPort())));
+
+ String viewFilePage = DFSTestUtil.urlGet(url);
+
+ assertTrue("page should show preview of file contents", viewFilePage.contains(FILE_DATA));
+ assertTrue("page should show link to download file", viewFilePage
+ .contains("/streamFile" + URIUtil.encodePath(testPath.toString()) +
+ "?nnaddr=localhost:" + nnIpcAddress.getPort()));
+ }
+
+ @Test
+ public void testViewFileJsp() throws IOException {
+ MiniDFSCluster cluster = null;
+ try {
+ Configuration conf = new HdfsConfiguration();
+ cluster = new MiniDFSCluster.Builder(conf).build();
+ cluster.waitActive();
+
+ testViewingFile(cluster, "/test-file");
+ testViewingFile(cluster, "/tmp/test-file");
+ testViewingFile(cluster, "/tmp/test-file%with goofy&characters");
+
+ } finally {
+ if (cluster != null) {
+ cluster.shutdown();
+ }
+ }
+ }
+
+}