This is an automated email from the ASF dual-hosted git repository.
lewismc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nutch.git
The following commit(s) were added to refs/heads/master by this push:
new 44583888f NUTCH-3209 Replace SHA-1 URL fingerprints in dump tools with
SHA-256 (#964)
44583888f is described below
commit 44583888f0946ff80cba1f06ddc1761ba19d6344
Author: Lewis John McGibbney <[email protected]>
AuthorDate: Sun Sep 13 04:35:32 2026 -0700
NUTCH-3209 Replace SHA-1 URL fingerprints in dump tools with SHA-256 (#964)
---
.../apache/nutch/tools/CommonCrawlDataDumper.java | 2 +-
src/java/org/apache/nutch/util/DumpFileUtil.java | 42 +++---
.../org/apache/nutch/util/DumpFileUtilTest.java | 145 +++++++++++++++------
3 files changed, 127 insertions(+), 62 deletions(-)
diff --git a/src/java/org/apache/nutch/tools/CommonCrawlDataDumper.java
b/src/java/org/apache/nutch/tools/CommonCrawlDataDumper.java
index fe714218e..e97fac03b 100644
--- a/src/java/org/apache/nutch/tools/CommonCrawlDataDumper.java
+++ b/src/java/org/apache/nutch/tools/CommonCrawlDataDumper.java
@@ -324,7 +324,7 @@ public class CommonCrawlDataDumper extends NutchTool
implements Tool {
reverseKey = reverseUrl(url);
config.setReverseKeyValue(
- reverseKey.replace("/", "_") + "_" + DigestUtils.sha1Hex(url)
+ reverseKey.replace("/", "_") + "_" +
DigestUtils.sha256Hex(url)
+ "_" + timestamp);
}
diff --git a/src/java/org/apache/nutch/util/DumpFileUtil.java
b/src/java/org/apache/nutch/util/DumpFileUtil.java
index d664ac571..9461a0177 100644
--- a/src/java/org/apache/nutch/util/DumpFileUtil.java
+++ b/src/java/org/apache/nutch/util/DumpFileUtil.java
@@ -91,27 +91,33 @@ public class DumpFileUtil {
fileExtension);
}
- public static String createFileNameFromUrl(String basePath, String
reverseKey, String urlString, String epochScrapeTime, String fileExtension,
boolean makeDir) {
- String fullDirPath = basePath + File.separator + reverseKey +
File.separator + DigestUtils.sha1Hex(urlString);
-
- if (makeDir) {
- try {
- FileUtils.forceMkdir(new File(fullDirPath));
- } catch (IOException e) {
- LOG.error("Failed to create dir: {}", fullDirPath);
- fullDirPath = null;
- }
- }
+ public static String createFileNameFromUrl(String basePath,
+ String reverseKey, String urlString, String epochScrapeTime,
+ String fileExtension, boolean makeDir) {
+ String fullDirPath = basePath + File.separator + reverseKey
+ + File.separator + DigestUtils.sha256Hex(urlString);
+
+ if (makeDir) {
+ try {
+ FileUtils.forceMkdir(new File(fullDirPath));
+ } catch (IOException e) {
+ LOG.error("Failed to create dir: {}", fullDirPath);
+ fullDirPath = null;
+ }
+ }
- if (fileExtension.length() > MAX_LENGTH_OF_EXTENSION) {
- LOG.info("File extension is too long. Truncated to {}
characters.", MAX_LENGTH_OF_EXTENSION);
- fileExtension = StringUtils.substring(fileExtension, 0,
MAX_LENGTH_OF_EXTENSION);
- }
+ if (fileExtension.length() > MAX_LENGTH_OF_EXTENSION) {
+ LOG.info("File extension is too long. Truncated to {} characters.",
+ MAX_LENGTH_OF_EXTENSION);
+ fileExtension = StringUtils.substring(fileExtension, 0,
+ MAX_LENGTH_OF_EXTENSION);
+ }
- String outputFullPath = fullDirPath + File.separator +
epochScrapeTime + "." + fileExtension;
+ String outputFullPath = fullDirPath + File.separator + epochScrapeTime
+ + "." + fileExtension;
- return outputFullPath;
- }
+ return outputFullPath;
+ }
public static String displayFileTypes(Map<String, Integer> typeCounts,
Map<String, Integer> filteredCounts) {
StringBuilder builder = new StringBuilder();
diff --git a/src/test/org/apache/nutch/util/DumpFileUtilTest.java
b/src/test/org/apache/nutch/util/DumpFileUtilTest.java
index 546ea7e6b..5916901bf 100644
--- a/src/test/org/apache/nutch/util/DumpFileUtilTest.java
+++ b/src/test/org/apache/nutch/util/DumpFileUtilTest.java
@@ -16,6 +16,9 @@
*/
package org.apache.nutch.util;
+import java.io.File;
+
+import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
@@ -24,47 +27,103 @@ import static org.hamcrest.MatcherAssert.assertThat;
public class DumpFileUtilTest {
- @Test
- public void testGetUrlMD5() throws Exception {
- String testUrl = "http://apache.org";
-
- String result = DumpFileUtil.getUrlMD5(testUrl);
-
- assertThat(result, is("991e599262e04ea2ec76b6c5aed499a7"));
- }
-
- @Test
- public void testCreateTwoLevelsDirectory() throws Exception {
- String testUrl = "http://apache.org";
- String basePath = "/tmp";
- String fullDir = DumpFileUtil.createTwoLevelsDirectory(basePath,
DumpFileUtil.getUrlMD5(testUrl));
-
- assertThat(fullDir, is("/tmp/96/ea"));
-
- String basePath2 = "/this/path/is/not/existed/just/for/testing";
- String fullDir2 = DumpFileUtil.createTwoLevelsDirectory(basePath2,
DumpFileUtil.getUrlMD5(testUrl));
-
- assertThat(fullDir2, nullValue());
- }
-
- @Test
- public void testCreateFileName() throws Exception {
- String testUrl = "http://apache.org";
- String baseName = "test";
- String extension = "html";
- String fullDir =
DumpFileUtil.createFileName(DumpFileUtil.getUrlMD5(testUrl), baseName,
extension);
-
- assertThat(fullDir, is("991e599262e04ea2ec76b6c5aed499a7_test.html"));
-
- String tooLongBaseName =
"testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
- String fullDir2 =
DumpFileUtil.createFileName(DumpFileUtil.getUrlMD5(testUrl), tooLongBaseName,
extension);
-
- assertThat(fullDir2,
-
is("991e599262e04ea2ec76b6c5aed499a7_testtesttesttesttesttesttesttest.html"));
-
- String tooLongExtension =
"testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
- String fullDir3 =
DumpFileUtil.createFileName(DumpFileUtil.getUrlMD5(testUrl), baseName,
tooLongExtension);
-
- assertThat(fullDir3,
is("991e599262e04ea2ec76b6c5aed499a7_test.testt"));
- }
+ /**
+ * Verifies that {@link DumpFileUtil#getUrlMD5} returns the lowercase hex MD5
+ * digest of a URL.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testGetUrlMD5() throws Exception {
+ String testUrl = "http://apache.org";
+
+ String result = DumpFileUtil.getUrlMD5(testUrl);
+
+ assertThat(result, is("991e599262e04ea2ec76b6c5aed499a7"));
+ }
+
+ /**
+ * Verifies that {@link DumpFileUtil#createTwoLevelsDirectory} builds a
+ * two-level dump directory from selected characters of the URL MD5, and
+ * returns {@code null} when the directory cannot be created.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateTwoLevelsDirectory() throws Exception {
+ String testUrl = "http://apache.org";
+ String basePath = "/tmp";
+ String fullDir = DumpFileUtil.createTwoLevelsDirectory(basePath,
+ DumpFileUtil.getUrlMD5(testUrl));
+
+ assertThat(fullDir, is("/tmp/96/ea"));
+
+ String basePath2 = "/this/path/is/not/existed/just/for/testing";
+ String fullDir2 = DumpFileUtil.createTwoLevelsDirectory(basePath2,
+ DumpFileUtil.getUrlMD5(testUrl));
+
+ assertThat(fullDir2, nullValue());
+ }
+
+ /**
+ * Verifies that {@link DumpFileUtil#createFileName} formats
+ * {@code md5_basename.extension} and truncates a too-long base name or
+ * extension.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateFileName() throws Exception {
+ String testUrl = "http://apache.org";
+ String baseName = "test";
+ String extension = "html";
+ String fullDir = DumpFileUtil.createFileName(
+ DumpFileUtil.getUrlMD5(testUrl), baseName, extension);
+
+ assertThat(fullDir, is("991e599262e04ea2ec76b6c5aed499a7_test.html"));
+
+ String tooLongBaseName =
"testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
+ String fullDir2 = DumpFileUtil.createFileName(
+ DumpFileUtil.getUrlMD5(testUrl), tooLongBaseName, extension);
+
+ assertThat(fullDir2, is(
+
"991e599262e04ea2ec76b6c5aed499a7_testtesttesttesttesttesttesttest.html"));
+
+ String tooLongExtension =
"testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
+ String fullDir3 = DumpFileUtil.createFileName(
+ DumpFileUtil.getUrlMD5(testUrl), baseName, tooLongExtension);
+
+ assertThat(fullDir3, is("991e599262e04ea2ec76b6c5aed499a7_test.testt"));
+ }
+
+ /**
+ * Verifies that {@link DumpFileUtil#createFileNameFromUrl} fingerprints the
+ * URL with SHA-256 (not SHA-1) in the dump path, and truncates a too-long
+ * file extension.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCreateFileNameFromUrl() throws Exception {
+ String testUrl = "http://apache.org";
+ String reverseKey = "org.apache.http";
+ String epoch = "1234567890";
+ String sha256 = DigestUtils.sha256Hex(testUrl);
+ String sha1 = DigestUtils.sha1Hex(testUrl);
+
+ String path = DumpFileUtil.createFileNameFromUrl("/tmp", reverseKey,
+ testUrl, epoch, "html", false);
+
+ assertThat(path, is("/tmp" + File.separator + reverseKey + File.separator
+ + sha256 + File.separator + epoch + ".html"));
+ assertThat(path.contains(sha1), is(false));
+
+ String tooLongExtension = "htmlhtmlhtml";
+ String pathTruncated = DumpFileUtil.createFileNameFromUrl("/tmp",
+ reverseKey, testUrl, epoch, tooLongExtension, false);
+
+ assertThat(pathTruncated,
+ is("/tmp" + File.separator + reverseKey + File.separator + sha256
+ + File.separator + epoch + ".htmlh"));
+ }
}