FileResourceFactory to generate stable file names for the same request Id and entity tag
This commit is contained in:
parent
d787637e6e
commit
f4f5f73be2
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue