From 9186cf7f1196aacce486558b5b18751b548aea17 Mon Sep 17 00:00:00 2001 From: Jan Vanhercke Date: Sun, 30 Jul 2017 00:03:05 +0200 Subject: [PATCH] Add wrapper class to return a default encoding Unknown encodings may cause gitblit to fail to start. This modification injects a wrapper class in the JGit internal to fake a valid return value. --- .../gitblit/manager/RepositoryManager.java | 31 ++++- src/main/java/com/gitblit/utils/MapUtils.java | 116 ++++++++++++++++++ 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/gitblit/utils/MapUtils.java diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java index 2be65873..efbdef6a 100644 --- a/src/main/java/com/gitblit/manager/RepositoryManager.java +++ b/src/main/java/com/gitblit/manager/RepositoryManager.java @@ -19,9 +19,11 @@ import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -87,6 +89,7 @@ import com.gitblit.utils.CommitCache; import com.gitblit.utils.DeepCopier; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.JGitUtils.LastChange; +import com.gitblit.utils.MapUtils; import com.gitblit.utils.MetricUtils; import com.gitblit.utils.ModelUtils; import com.gitblit.utils.ObjectCache; @@ -1924,6 +1927,7 @@ public class RepositoryManager implements IRepositoryManager { } } + @SuppressWarnings("unchecked") protected void configureJGit() { // Configure JGit WindowCacheConfig cfg = new WindowCacheConfig(); @@ -1944,16 +1948,39 @@ public class RepositoryManager implements IRepositoryManager { } catch (IllegalArgumentException e) { logger.error("Failed to configure JGit parameters!", e); } - + try { // issue-486/ticket-151: UTF-9 & UTF-18 // issue-560/ticket-237: 'UTF8' Field field = RawParseUtils.class.getDeclaredField("encodingAliases"); field.setAccessible(true); - Map encodingAliases = (Map) field.get(null); + + Map encodingAliases; + + try { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + // Since unknown encodingAliases cause GitBlit to crash we replace the + // map by a wrapper class that always returns a value. ISO-8859-1 seems + // appropriate since it is a fixed 8-bit encoding. + encodingAliases = (Map) field.get(null); + encodingAliases = MapUtils.defaultMap(encodingAliases, StandardCharsets.ISO_8859_1); + field.set(null, encodingAliases); + + modifiersField.setInt(field, field.getModifiers() | Modifier.FINAL); + modifiersField.setAccessible(false); + } catch(Throwable t) { + logger.error("Failed to inject wrapper class for encoding Aliases", t); + encodingAliases = (Map) field.get(null); + } + + // Provided sensible default mappings encodingAliases.put("'utf8'", RawParseUtils.UTF8_CHARSET); encodingAliases.put("utf-9", RawParseUtils.UTF8_CHARSET); encodingAliases.put("utf-18", RawParseUtils.UTF8_CHARSET); + logger.info("Alias 'UTF8', UTF-9 & UTF-18 encodings as UTF-8 in JGit"); } catch (Throwable t) { logger.error("Failed to inject UTF-9 & UTF-18 encoding aliases into JGit", t); diff --git a/src/main/java/com/gitblit/utils/MapUtils.java b/src/main/java/com/gitblit/utils/MapUtils.java new file mode 100644 index 00000000..98568780 --- /dev/null +++ b/src/main/java/com/gitblit/utils/MapUtils.java @@ -0,0 +1,116 @@ +package com.gitblit.utils; + +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.mina.util.ConcurrentHashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A utility wrapper class to generate a default value over an existing map + * + * @author Jan Vanhercke + * + */ +public class MapUtils { + + private static final Logger logger = LoggerFactory.getLogger(MapUtils.class); + + public static Map defaultMap(Map delegate, V value) { + return new Wrap<>(delegate, value); + } + + private static class Wrap implements Map { + + private Map delegate; + + // HashSet is only used to reduce logging + + private Set unknownKeys = new ConcurrentHashSet<>(); + + private V value; + + private Wrap(Map delegate, V value) { + this.delegate = delegate; + this.value = value; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return true; + } + + @Override + public boolean containsValue(Object value) { + return true; + } + + @SuppressWarnings("unchecked") + @Override + public V get(Object key) { + V retv = delegate.get(key); + + if (retv == null) { + if (unknownKeys.add((K) key)) + logger.error(MessageFormat.format("Default value {0} generated for key {1}", value, key)); + + return value; + } + + return retv; + } + + @Override + public V put(K key, V value) { + return delegate.put(key, value); + } + + @Override + public V remove(Object key) { + V retv = delegate.remove(key); + + if (retv == null) + return value; + + return value; + } + + @Override + public void putAll(Map m) { + delegate.putAll(m); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Set keySet() { + return delegate.keySet(); + } + + @Override + public Collection values() { + return delegate.values(); + } + + @Override + public Set> entrySet() { + return delegate.entrySet(); + } + } +} -- 2.39.5