From 7e5ee5a454ec396b5dc2f00e89adeca84d6ef683 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Mon, 18 Jul 2011 18:10:34 -0400
Subject: [PATCH] Allow specification of forward-slash character in urls (issue 11)

---
 src/com/gitblit/GitBlit.java                              |   14 ++++
 docs/04_releases.mkd                                      |    1 
 src/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java |   83 +++++++++++++++++++++++++++
 distrib/gitblit.properties                                |   16 ++++
 src/com/gitblit/IStoredSettings.java                      |   20 ++++++
 src/com/gitblit/wicket/GitBlitWebApp.java                 |    2 
 docs/00_index.mkd                                         |    1 
 docs/02_faq.mkd                                           |    3 +
 8 files changed, 137 insertions(+), 3 deletions(-)

diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties
index 2ae3d01..73a1747 100644
--- a/distrib/gitblit.properties
+++ b/distrib/gitblit.properties
@@ -135,13 +135,25 @@
 # Mount URL parameters
 # This setting controls if pretty or parameter URLs are used.
 # i.e.
-# if true: http://localhost/commit/myrepo/abcdef
-# if false: http://localhost/commit/?r=myrepo&h=abcdef
+# if true:
+#     http://localhost/commit/myrepo/abcdef
+# if false:
+#     http://localhost/commit/?r=myrepo&h=abcdef
 #
 # SINCE 0.5.0
 # RESTART REQUIRED
 web.mountParameters = true
 
+# Some servlet containers (e.g. Tomcat >= 6.0.10) disallow '/' (%2F) encoding
+# in URLs as a security precaution for proxies.  This setting tells Gitblit
+# to preemptively replace '/' with '*' or '!' for url string parameters.
+#
+# <https://issues.apache.org/jira/browse/WICKET-1303>
+# <http://tomcat.apache.org/security-6.html>
+#
+# SINCE 0.5.2
+web.forwardSlashCharacter = /
+
 # Show other URLs on the summary page for accessing your git repositories
 # Use spaces to separate urls. {0} is the token for the repository name.
 # e.g.
diff --git a/docs/00_index.mkd b/docs/00_index.mkd
index edb058d..a2f8313 100644
--- a/docs/00_index.mkd
+++ b/docs/00_index.mkd
@@ -23,6 +23,7 @@
 
 **%VERSION%** ([go](http://code.google.com/p/gitblit/downloads/detail?name=%GO%)|[war](http://code.google.com/p/gitblit/downloads/detail?name=%WAR%)) based on [%JGIT%][jgit] &nbsp; *released %BUILDDATE%*
 
+- forward-slashes ('/', %2F) can be encoded using a custom character to workaround some servlet container default security measures for proxy servers<br/>**New:** *web.forwardSlashCharacter = /*
 - optionally display repository on-disk size on repositories page<br/>**New:** *web.showRepositorySizes = true*
 - tone-down repository group header color
 
diff --git a/docs/02_faq.mkd b/docs/02_faq.mkd
index e160773..a1fcf13 100644
--- a/docs/02_faq.mkd
+++ b/docs/02_faq.mkd
@@ -36,6 +36,9 @@
 ### Gitblit WAR will not authenticate any users?!
 Confirm that the &lt;context-param&gt; *realm.userService* value in your `web.xml` file actually points to a `users.properties` file.
 
+### Gitblit won't open my grouped repository (/group/myrepo.git) or browse my branch/tag/ref?!
+This is likely an url encoding/decoding problem.  In `gitblit.properties` or `web.xml`, try setting *web.mountParameters* to *false*.
+
 ## General Interest Questions
 
 ### Gitblit?  What kind of name is that?
diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd
index 94aaa1a..559b132 100644
--- a/docs/04_releases.mkd
+++ b/docs/04_releases.mkd
@@ -3,6 +3,7 @@
 ### Current Release
 **%VERSION%** ([go](http://code.google.com/p/gitblit/downloads/detail?name=%GO%)|[war](http://code.google.com/p/gitblit/downloads/detail?name=%WAR%)) based on [%JGIT%][jgit] &nbsp; *released %BUILDDATE%*
 
+- forward-slashes ('/', %2F) can be encoded using a custom character to workaround some servlet container default security measures for proxy servers<br/>**New:** *web.forwardSlashCharacter = /*
 - optionally display repository on-disk size on repositories page<br/>**New:** *web.showRepositorySizes = true*
 - tone-down repository group header color
 
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index 968034d..e570e7b 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -129,6 +129,20 @@
 	}
 
 	/**
+	 * Returns the char value for the specified key. If the key does not exist
+	 * or the value for the key can not be interpreted as a character, the
+	 * defaultValue is returned.
+	 * 
+	 * @see IStoredSettings.getChar(String key, char defaultValue)
+	 * @param key
+	 * @param defaultValue
+	 * @return key value or defaultValue
+	 */
+	public static char getChar(String key, char defaultValue) {
+		return self().settings.getChar(key, defaultValue);
+	}
+	
+	/**
 	 * Returns the string value for the specified key. If the key does not exist
 	 * or the value for the key can not be interpreted as a string, the
 	 * defaultValue is returned.
diff --git a/src/com/gitblit/IStoredSettings.java b/src/com/gitblit/IStoredSettings.java
index b380c63..0cc4bb4 100644
--- a/src/com/gitblit/IStoredSettings.java
+++ b/src/com/gitblit/IStoredSettings.java
@@ -116,6 +116,26 @@
 		}
 		return defaultValue;
 	}
+	
+	/**
+	 * Returns the char value for the specified key. If the key does not exist
+	 * or the value for the key can not be interpreted as a char, the
+	 * defaultValue is returned.
+	 * 
+	 * @param key
+	 * @param defaultValue
+	 * @return key value or defaultValue
+	 */
+	public char getChar(String name, char defaultValue) {
+		Properties props = getSettings();
+		if (props.containsKey(name)) {
+			String value = props.getProperty(name);
+			if (!StringUtils.isEmpty(value)) {
+				return value.charAt(0);
+			}
+		}
+		return defaultValue;
+	}
 
 	/**
 	 * Returns the string value for the specified key. If the key does not exist
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.java b/src/com/gitblit/wicket/GitBlitWebApp.java
index 1b13ea3..4b5e660 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/com/gitblit/wicket/GitBlitWebApp.java
@@ -110,7 +110,7 @@
 		if (!GitBlit.getBoolean(Keys.web.mountParameters, true)) {
 			parameters = new String[] {};
 		}
-		mount(new MixedParamUrlCodingStrategy(location, clazz, parameters));
+		mount(new GitblitParamUrlCodingStrategy(location, clazz, parameters));
 	}
 
 	@Override
diff --git a/src/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java b/src/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java
new file mode 100644
index 0000000..c30b9c3
--- /dev/null
+++ b/src/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed 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 com.gitblit.wicket;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.protocol.http.WicketURLDecoder;
+import org.apache.wicket.protocol.http.WicketURLEncoder;
+import org.apache.wicket.request.target.coding.MixedParamUrlCodingStrategy;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+
+/**
+ * Simple subclass of mixed parameter url coding strategy that works around the
+ * encoded forward-slash issue that is present in some servlet containers.
+ * 
+ * https://issues.apache.org/jira/browse/WICKET-1303
+ * http://tomcat.apache.org/security-6.html
+ * 
+ * @author James Moger
+ * 
+ */
+public class GitblitParamUrlCodingStrategy extends MixedParamUrlCodingStrategy {
+
+	/**
+	 * Construct.
+	 * 
+	 * @param <C>
+	 * @param mountPath
+	 *            mount path (not empty)
+	 * @param bookmarkablePageClass
+	 *            class of mounted page (not null)
+	 * @param parameterNames
+	 *            the parameter names (not null)
+	 */
+	public <C extends Page> GitblitParamUrlCodingStrategy(String mountPath,
+			Class<C> bookmarkablePageClass, String[] parameterNames) {
+		super(mountPath, bookmarkablePageClass, parameterNames);
+	}
+
+	/**
+	 * Url encodes a string that is mean for a URL path (e.g., between slashes)
+	 * 
+	 * @param string
+	 *            string to be encoded
+	 * @return encoded string
+	 */
+	protected String urlEncodePathComponent(String string) {
+		char altChar = GitBlit.getChar(Keys.web.forwardSlashCharacter, '/');
+		if (altChar != '/') {
+			string = string.replace('/', altChar);
+		}
+		return super.urlEncodePathComponent(string);
+	}
+
+	/**
+	 * Returns a decoded value of the given value (taken from a URL path
+	 * section)
+	 * 
+	 * @param value
+	 * @return Decodes the value
+	 */
+	protected String urlDecodePathComponent(String value) {
+		char altChar = GitBlit.getChar(Keys.web.forwardSlashCharacter, '/');
+		if (altChar != '/') {
+			value = value.replace(altChar, '/');
+		}
+		return super.urlDecodePathComponent(value);
+	}
+}
\ No newline at end of file

--
Gitblit v1.9.1