diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicIdGenerator.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicIdGenerator.java
deleted file mode 100644
index d81b66e19..000000000
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicIdGenerator.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * ====================================================================
- * 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- *
- */
-package org.apache.hc.client5.http.impl.cache;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Formatter;
-import java.util.Locale;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Should produce reasonably unique tokens.
- */
-class BasicIdGenerator {
-
- private final String hostname;
- private final SecureRandom rnd;
-
- private long count;
-
- private final ReentrantLock lock;
-
- public BasicIdGenerator() {
- super();
- String hostname;
- try {
- hostname = InetAddress.getLocalHost().getHostName();
- } catch (final UnknownHostException ex) {
- hostname = "localhost";
- }
- this.hostname = hostname;
- try {
- this.rnd = SecureRandom.getInstance("SHA1PRNG");
- } catch (final NoSuchAlgorithmException ex) {
- throw new Error(ex);
- }
- this.rnd.setSeed(System.currentTimeMillis());
- this.lock = new ReentrantLock();
- }
-
- public void generate(final StringBuilder buffer) {
- lock.lock();
- try {
- this.count++;
- final int rndnum = this.rnd.nextInt();
- buffer.append(System.currentTimeMillis());
- buffer.append('.');
- try (Formatter formatter = new Formatter(buffer, Locale.ROOT)) {
- formatter.format("%1$016x-%2$08x", this.count, rndnum);
- }
- buffer.append('.');
- buffer.append(this.hostname);
- } finally {
- lock.unlock();
- }
- }
-
- public String generate() {
- final StringBuilder buffer = new StringBuilder();
- generate(buffer);
- return buffer.toString();
- }
-
-}
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/FileResourceFactory.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/FileResourceFactory.java
index 22d2cae1d..e0842c992 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/FileResourceFactory.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/FileResourceFactory.java
@@ -29,13 +29,17 @@ package org.apache.hc.client5.http.impl.cache;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import org.apache.hc.client5.http.cache.Resource;
import org.apache.hc.client5.http.cache.ResourceFactory;
import org.apache.hc.client5.http.cache.ResourceIOException;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.net.PercentCodec;
import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.TextUtils;
/**
* Generates {@link Resource} instances whose body is stored in a temporary file.
@@ -46,37 +50,44 @@ import org.apache.hc.core5.util.Args;
public class FileResourceFactory implements ResourceFactory {
private final File cacheDir;
- private final BasicIdGenerator idgen;
public FileResourceFactory(final File cacheDir) {
super();
this.cacheDir = cacheDir;
- this.idgen = new BasicIdGenerator();
}
- private File generateUniqueCacheFile(final String requestId) {
- final StringBuilder buffer = new StringBuilder();
- this.idgen.generate(buffer);
- buffer.append('.');
- final int len = Math.min(requestId.length(), 100);
- for (int i = 0; i < len; i++) {
- final char ch = requestId.charAt(i);
- if (Character.isLetterOrDigit(ch) || ch == '.') {
- buffer.append(ch);
- } else {
- buffer.append('-');
+ static String generateUniqueCacheFileName(final String requestId, final String eTag, final byte[] content, final int off, final int len) {
+ final StringBuilder buf = new StringBuilder();
+ if (eTag != null) {
+ PercentCodec.RFC3986.encode(buf, eTag);
+ buf.append('@');
+ } else if (content != null) {
+ final MessageDigest sha256;
+ try {
+ sha256 = MessageDigest.getInstance("SHA-256");
+ } catch (final NoSuchAlgorithmException ex) {
+ throw new IllegalStateException(ex);
}
+ sha256.update(content, off, len);
+ buf.append(TextUtils.toHexString(sha256.digest()));
+ buf.append('@');
}
- return new File(this.cacheDir, buffer.toString());
+ PercentCodec.RFC3986.encode(buf, requestId);
+ return buf.toString();
}
+ /**
+ * @since 5.4
+ */
@Override
public Resource generate(
final String requestId,
+ final String eTag,
final byte[] content, final int off, final int len) throws ResourceIOException {
Args.notNull(requestId, "Request id");
- final File file = generateUniqueCacheFile(requestId);
- try (FileOutputStream outStream = new FileOutputStream(file)) {
+ final String filename = generateUniqueCacheFileName(requestId, eTag, content, off, len);
+ final File file = new File(cacheDir, filename);
+ try (FileOutputStream outStream = new FileOutputStream(file, false)) {
if (content != null) {
outStream.write(content, off, len);
}
@@ -86,10 +97,22 @@ public class FileResourceFactory implements ResourceFactory {
return new FileResource(file);
}
+ @Override
+ public Resource generate(final String requestId, final byte[] content, final int off, final int len) throws ResourceIOException {
+ if (content != null) {
+ return generate(requestId, null, content, off, len);
+ } else {
+ return generate(requestId, null, null, 0, 0);
+ }
+ }
+
@Override
public Resource generate(final String requestId, final byte[] content) throws ResourceIOException {
- Args.notNull(content, "Content");
- return generate(requestId, content, 0, content.length);
+ if (content != null) {
+ return generate(requestId, null, content, 0, content.length);
+ } else {
+ return generate(requestId, null, null, 0, 0);
+ }
}
/**
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestFileResourceFactory.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestFileResourceFactory.java
new file mode 100644
index 000000000..952f75712
--- /dev/null
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestFileResourceFactory.java
@@ -0,0 +1,69 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.hc.client5.http.impl.cache;
+
+
+import java.net.URI;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class TestFileResourceFactory {
+
+ CacheKeyGenerator keyGenerator;
+
+ @BeforeEach
+ public void setUp() {
+ keyGenerator = new CacheKeyGenerator();
+ }
+
+ @Test
+ public void testViaValueLookup() throws Exception {
+ final String requestId = keyGenerator.generateKey(new URI("http://localhost/stuff"));
+
+ Assertions.assertEquals(
+ "blah%20blah@http%3A%2F%2Flocalhost%3A80%2Fstuff",
+ FileResourceFactory.generateUniqueCacheFileName(requestId, "blah blah", null, 0, 0));
+ Assertions.assertEquals(
+ "blah-blah@http%3A%2F%2Flocalhost%3A80%2Fstuff",
+ FileResourceFactory.generateUniqueCacheFileName(requestId, "blah-blah", null, 0, 0));
+ Assertions.assertEquals(
+ "blah%40blah@http%3A%2F%2Flocalhost%3A80%2Fstuff",
+ FileResourceFactory.generateUniqueCacheFileName(requestId, "blah@blah", null, 0, 0));
+ Assertions.assertEquals(
+ "039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81@http%3A%2F%2Flocalhost%3A80%2Fstuff",
+ FileResourceFactory.generateUniqueCacheFileName(requestId, null, new byte[]{1, 2, 3}, 0, 3));
+ Assertions.assertEquals(
+ "039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81@http%3A%2F%2Flocalhost%3A80%2Fstuff",
+ FileResourceFactory.generateUniqueCacheFileName(requestId, null, new byte[]{1, 2, 3, 4, 5}, 0, 3));
+ Assertions.assertEquals(
+ "http%3A%2F%2Flocalhost%3A80%2Fstuff",
+ FileResourceFactory.generateUniqueCacheFileName(requestId, null, null, 0, 0));
+ }
+
+}