summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/distrib/data/gitblit.properties14
-rw-r--r--src/main/java/com/gitblit/manager/ProjectManager.java15
-rw-r--r--src/main/java/com/gitblit/manager/RepositoryManager.java100
-rw-r--r--src/main/java/com/gitblit/servlet/RawServlet.java12
-rw-r--r--src/main/java/com/gitblit/tickets/TicketIndexer.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobPage.java5
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html8
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoryPage.java16
-rw-r--r--src/main/java/com/gitblit/wicket/panels/BasePanel.java11
-rw-r--r--src/main/java/com/gitblit/wicket/panels/HistoryPanel.java6
-rw-r--r--src/site/rpc.mkd2
-rw-r--r--src/site/siteindex.mkd2
12 files changed, 141 insertions, 52 deletions
diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties
index 65fe41e5..d8ddc285 100644
--- a/src/main/distrib/data/gitblit.properties
+++ b/src/main/distrib/data/gitblit.properties
@@ -844,8 +844,18 @@ realm.minPasswordLength = 5
# SINCE 0.5.0
web.siteName =
-# The canonical url of your Gitblit server to bs used in email notifications.
-# e.g. web.canonicalUrl = https://demo-gitblit.rhcloud.com
+# The canonical url of your Gitblit server to be used in repository url generation,
+# RSS feeds, and all embedded links in email and plugin-based notifications.
+#
+# If you are running Gitblit on a non-standard http port (i.e. not 80 and not 443)
+# then you must specify that port in this url otherwise your generated urls will be
+# incorrect.
+#
+# The hostname of this url will be extracted for SSH and GIT protocol repository
+# url generation.
+#
+# e.g. web.canonicalUrl = https://dev.gitblit.com
+# web.canonicalUrl = https://dev.gitblit.com:8443
#
# SINCE 1.4.0
web.canonicalUrl =
diff --git a/src/main/java/com/gitblit/manager/ProjectManager.java b/src/main/java/com/gitblit/manager/ProjectManager.java
index b30f4f17..666f5210 100644
--- a/src/main/java/com/gitblit/manager/ProjectManager.java
+++ b/src/main/java/com/gitblit/manager/ProjectManager.java
@@ -178,19 +178,20 @@ public class ProjectManager implements IProjectManager {
map.put("", configs.get(""));
for (RepositoryModel model : repositoryManager.getRepositoryModels(user)) {
- String rootPath = StringUtils.getRootPath(model.name).toLowerCase();
- if (!map.containsKey(rootPath)) {
+ String projectPath = StringUtils.getRootPath(model.name);
+ String projectKey = projectPath.toLowerCase();
+ if (!map.containsKey(projectKey)) {
ProjectModel project;
- if (configs.containsKey(rootPath)) {
+ if (configs.containsKey(projectKey)) {
// clone the project model because it's repository list will
// be tailored for the requesting user
- project = DeepCopier.copy(configs.get(rootPath));
+ project = DeepCopier.copy(configs.get(projectKey));
} else {
- project = new ProjectModel(rootPath);
+ project = new ProjectModel(projectPath);
}
- map.put(rootPath, project);
+ map.put(projectKey, project);
}
- map.get(rootPath).addRepository(model);
+ map.get(projectKey).addRepository(model);
}
// sort projects, root project first
diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java
index e0721c7c..0160363e 100644
--- a/src/main/java/com/gitblit/manager/RepositoryManager.java
+++ b/src/main/java/com/gitblit/manager/RepositoryManager.java
@@ -422,11 +422,12 @@ public class RepositoryManager implements IRepositoryManager {
@Override
public void addToCachedRepositoryList(RepositoryModel model) {
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
- repositoryListCache.put(model.name.toLowerCase(), model);
+ String key = getRepositoryKey(model.name);
+ repositoryListCache.put(key, model);
// update the fork origin repository with this repository clone
if (!StringUtils.isEmpty(model.originRepository)) {
- String originKey = model.originRepository.toLowerCase();
+ String originKey = getRepositoryKey(model.originRepository);
if (repositoryListCache.containsKey(originKey)) {
RepositoryModel origin = repositoryListCache.get(originKey);
origin.addFork(model.name);
@@ -445,7 +446,8 @@ public class RepositoryManager implements IRepositoryManager {
if (StringUtils.isEmpty(name)) {
return null;
}
- return repositoryListCache.remove(name.toLowerCase());
+ String key = getRepositoryKey(name);
+ return repositoryListCache.remove(key);
}
/**
@@ -554,7 +556,7 @@ public class RepositoryManager implements IRepositoryManager {
// rebuild fork networks
for (RepositoryModel model : repositoryListCache.values()) {
if (!StringUtils.isEmpty(model.originRepository)) {
- String originKey = model.originRepository.toLowerCase();
+ String originKey = getRepositoryKey(model.originRepository);
if (repositoryListCache.containsKey(originKey)) {
RepositoryModel origin = repositoryListCache.get(originKey);
origin.addFork(model.name);
@@ -590,15 +592,13 @@ public class RepositoryManager implements IRepositoryManager {
/**
* Returns the JGit repository for the specified name.
*
- * @param repositoryName
+ * @param name
* @param logError
* @return repository or null
*/
@Override
- public Repository getRepository(String repositoryName, boolean logError) {
- // Decode url-encoded repository name (issue-278)
- // http://stackoverflow.com/questions/17183110
- repositoryName = repositoryName.replace("%7E", "~").replace("%7e", "~");
+ public Repository getRepository(String name, boolean logError) {
+ String repositoryName = fixRepositoryName(name);
if (isCollectingGarbage(repositoryName)) {
logger.warn(MessageFormat.format("Rejecting request for {0}, busy collecting garbage!", repositoryName));
@@ -680,16 +680,14 @@ public class RepositoryManager implements IRepositoryManager {
* Returns the repository model for the specified repository. This method
* does not consider user access permissions.
*
- * @param repositoryName
+ * @param name
* @return repository model or null
*/
@Override
- public RepositoryModel getRepositoryModel(String repositoryName) {
- // Decode url-encoded repository name (issue-278)
- // http://stackoverflow.com/questions/17183110
- repositoryName = repositoryName.replace("%7E", "~").replace("%7e", "~");
+ public RepositoryModel getRepositoryModel(String name) {
+ String repositoryName = fixRepositoryName(name);
- String repositoryKey = repositoryName.toLowerCase();
+ String repositoryKey = getRepositoryKey(repositoryName);
if (!repositoryListCache.containsKey(repositoryKey)) {
RepositoryModel model = loadRepositoryModel(repositoryName);
if (model == null) {
@@ -702,7 +700,7 @@ public class RepositoryManager implements IRepositoryManager {
// cached model
RepositoryModel model = repositoryListCache.get(repositoryKey);
- if (gcExecutor.isCollectingGarbage(model.name)) {
+ if (isCollectingGarbage(model.name)) {
// Gitblit is busy collecting garbage, use our cached model
RepositoryModel rm = DeepCopier.copy(model);
rm.isCollectingGarbage = true;
@@ -758,6 +756,52 @@ public class RepositoryManager implements IRepositoryManager {
}
/**
+ * Replaces illegal character patterns in a repository name.
+ *
+ * @param repositoryName
+ * @return a corrected name
+ */
+ private String fixRepositoryName(String repositoryName) {
+ if (StringUtils.isEmpty(repositoryName)) {
+ return repositoryName;
+ }
+
+ // Decode url-encoded repository name (issue-278)
+ // http://stackoverflow.com/questions/17183110
+ String name = repositoryName.replace("%7E", "~").replace("%7e", "~");
+ name = name.replace("%2F", "/").replace("%2f", "/");
+
+ if (name.charAt(name.length() - 1) == '/') {
+ name = name.substring(0, name.length() - 1);
+ }
+
+ // strip duplicate-slashes from requests for repositoryName (ticket-117, issue-454)
+ // specify first char as slash so we strip leading slashes
+ char lastChar = '/';
+ StringBuilder sb = new StringBuilder();
+ for (char c : name.toCharArray()) {
+ if (c == '/' && lastChar == c) {
+ continue;
+ }
+ sb.append(c);
+ lastChar = c;
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the cache key for the repository name.
+ *
+ * @param repositoryName
+ * @return the cache key for the repository
+ */
+ private String getRepositoryKey(String repositoryName) {
+ String name = fixRepositoryName(repositoryName);
+ return StringUtils.stripDotGit(name).toLowerCase();
+ }
+
+ /**
* Workaround JGit. I need to access the raw config object directly in order
* to see if the config is dirty so that I can reload a repository model.
* If I use the stock JGit method to get the config it already reloads the
@@ -932,7 +976,8 @@ public class RepositoryManager implements IRepositoryManager {
if (!caseSensitiveCheck && settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
// if we are caching use the cache to determine availability
// otherwise we end up adding a phantom repository to the cache
- return repositoryListCache.containsKey(repositoryName.toLowerCase());
+ String key = getRepositoryKey(repositoryName);
+ return repositoryListCache.containsKey(key);
}
Repository r = getRepository(repositoryName, false);
if (r == null) {
@@ -970,7 +1015,7 @@ public class RepositoryManager implements IRepositoryManager {
}
String userProject = ModelUtils.getPersonalPath(username);
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
- String originKey = origin.toLowerCase();
+ String originKey = getRepositoryKey(origin);
String userPath = userProject + "/";
// collect all origin nodes in fork network
@@ -987,7 +1032,7 @@ public class RepositoryManager implements IRepositoryManager {
}
if (originModel.originRepository != null) {
- String ooKey = originModel.originRepository.toLowerCase();
+ String ooKey = getRepositoryKey(originModel.originRepository);
roots.add(ooKey);
originModel = repositoryListCache.get(ooKey);
} else {
@@ -1000,7 +1045,8 @@ public class RepositoryManager implements IRepositoryManager {
if (repository.startsWith(userPath)) {
RepositoryModel model = repositoryListCache.get(repository);
if (!StringUtils.isEmpty(model.originRepository)) {
- if (roots.contains(model.originRepository.toLowerCase())) {
+ String ooKey = getRepositoryKey(model.originRepository);
+ if (roots.contains(ooKey)) {
// user has a fork in this graph
return model.name;
}
@@ -1038,9 +1084,11 @@ public class RepositoryManager implements IRepositoryManager {
public ForkModel getForkNetwork(String repository) {
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
// find the root, cached
- RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
+ String key = getRepositoryKey(repository);
+ RepositoryModel model = repositoryListCache.get(key);
while (model.originRepository != null) {
- model = repositoryListCache.get(model.originRepository.toLowerCase());
+ String originKey = getRepositoryKey(model.originRepository);
+ model = repositoryListCache.get(originKey);
}
ForkModel root = getForkModelFromCache(model.name);
return root;
@@ -1056,7 +1104,8 @@ public class RepositoryManager implements IRepositoryManager {
}
private ForkModel getForkModelFromCache(String repository) {
- RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
+ String key = getRepositoryKey(repository);
+ RepositoryModel model = repositoryListCache.get(key);
if (model == null) {
return null;
}
@@ -1287,7 +1336,7 @@ public class RepositoryManager implements IRepositoryManager {
@Override
public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
boolean isCreate) throws GitBlitException {
- if (gcExecutor.isCollectingGarbage(repositoryName)) {
+ if (isCollectingGarbage(repositoryName)) {
throw new GitBlitException(MessageFormat.format("sorry, Gitblit is busy collecting garbage in {0}",
repositoryName));
}
@@ -1371,7 +1420,8 @@ public class RepositoryManager implements IRepositoryManager {
// update this repository's origin's fork list
if (!StringUtils.isEmpty(repository.originRepository)) {
- RepositoryModel origin = repositoryListCache.get(repository.originRepository.toLowerCase());
+ String originKey = getRepositoryKey(repository.originRepository);
+ RepositoryModel origin = repositoryListCache.get(originKey);
if (origin != null && !ArrayUtils.isEmpty(origin.forks)) {
origin.forks.remove(repositoryName);
origin.forks.add(repository.name);
diff --git a/src/main/java/com/gitblit/servlet/RawServlet.java b/src/main/java/com/gitblit/servlet/RawServlet.java
index ff3f7359..a9e58202 100644
--- a/src/main/java/com/gitblit/servlet/RawServlet.java
+++ b/src/main/java/com/gitblit/servlet/RawServlet.java
@@ -173,6 +173,9 @@ public class RawServlet extends DaggerServlet {
repository = path.substring(0, slash);
}
offset += slash;
+ if (offset == 0) {
+ offset++;
+ }
r = repositoryManager.getRepository(repository, false);
if (repository.equals(path)) {
// either only repository in url or no repository found
@@ -252,6 +255,15 @@ public class RawServlet extends DaggerServlet {
// load, interpret, and serve text content as UTF-8
String [] encodings = runtimeManager.getSettings().getStrings(Keys.web.blobEncodings).toArray(new String[0]);
String content = JGitUtils.getStringContent(r, commit.getTree(), requestedPath, encodings);
+ if (content == null) {
+ logger.error("RawServlet Failed to load {} {} {}", repository, commit.getName(), path);
+ String str = MessageFormat.format(
+ "# Error\nSorry, the requested resource **{0}** was not found.",
+ requestedPath);
+ response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ error(response, str);
+ return;
+ }
byte [] bytes = content.getBytes(Constants.ENCODING);
response.setContentLength(bytes.length);
diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java
index 3929a000..98fe6977 100644
--- a/src/main/java/com/gitblit/tickets/TicketIndexer.java
+++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java
@@ -143,7 +143,7 @@ public class TicketIndexer {
private String escape(String value) {
if (value.charAt(0) != '"') {
- if (value.indexOf('/') > -1) {
+ if (value.indexOf('/') > -1 || value.indexOf('-') > -1) {
return "\"" + value + "\"";
}
}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.java b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
index f3d0bc92..0938fcde 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
+import org.apache.wicket.RedirectException;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
@@ -52,6 +53,10 @@ public class BlobPage extends RepositoryPage {
final String blobPath = WicketUtils.getPath(params);
String [] encodings = getEncodings();
+ if (StringUtils.isEmpty(objectId) && StringUtils.isEmpty(blobPath)) {
+ throw new RedirectException(TreePage.class, WicketUtils.newRepositoryParameter(repositoryName));
+ }
+
if (StringUtils.isEmpty(blobPath)) {
// blob by objectid
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html
index 0ecb54d5..cd777b4b 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html
@@ -30,7 +30,7 @@
<div class="span8 offset1">
<h2><center>Git 배우기</center></h2>
<p>만약 사용법에 자신이 없다면, Git 사용법을 더 잘 이해하기 위해
- <a href="http://book.git-scm.com/ko">Git Community Book</a> 을 볼 것을 고려해 보세요.</p>
+ <a href="http://git-scm.com/book/ko">Pro Git</a> 을 볼 것을 고려해 보세요.</p>
<h4>오픈 소스 Git 클라이언트</h4>
<table>
@@ -43,11 +43,11 @@
</tbody>
</table>
- <h4>유료/클로즈드 소스 Git 클라이언트</h4>
+ <h4>유료/비공개 소스 Git 클라이언트</h4>
<table>
<tbody>
<tr><td><a href="http://www.syntevo.com/smartgithg">SmartGit/Hg</a></td><td>자바 어플리케이션 (명령어 기반 공식 Git 필요)</td></tr>
- <tr><td><a href="http://www.sourcetreeapp.com/">SourceTree</a></td><td>윈도와 맥에서 가능한 Git 과 Mercurial용 무료 클라이언트</td></tr>
+ <tr><td><a href="http://www.sourcetreeapp.com/">SourceTree</a></td><td>윈도와 맥에서 사용 가능한 Git 과 Mercurial용 무료 클라이언트</td></tr>
<tr><td><a href="http://www.git-tower.com/">Tower</a></td><td>맥 OS X 용 Git 클라이언트</td></tr>
</tbody>
</table>
@@ -58,4 +58,4 @@
</div>
</wicket:extend>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
index fcf659af..253c4fe4 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -166,10 +166,10 @@ public abstract class RepositoryPage extends RootPage {
add(navigationPanel);
add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
- .getRelativePathPrefixToContextRoot(), repositoryName, null, 0)));
+ .getRelativePathPrefixToContextRoot(), getRepositoryName(), null, 0)));
// add floating search form
- SearchForm searchForm = new SearchForm("searchForm", repositoryName);
+ SearchForm searchForm = new SearchForm("searchForm", getRepositoryName());
add(searchForm);
searchForm.setTranslatedAttributes();
@@ -193,7 +193,7 @@ public abstract class RepositoryPage extends RootPage {
private List<NavLink> registerNavLinks() {
PageParameters params = null;
if (!StringUtils.isEmpty(repositoryName)) {
- params = WicketUtils.newRepositoryParameter(repositoryName);
+ params = WicketUtils.newRepositoryParameter(getRepositoryName());
}
List<NavLink> navLinks = new ArrayList<NavLink>();
@@ -216,7 +216,7 @@ public abstract class RepositoryPage extends RootPage {
navLinks.add(new PageNavLink("gb.commits", LogPage.class, params));
navLinks.add(new PageNavLink("gb.tree", TreePage.class, params));
if (app().tickets().isReady() && (app().tickets().isAcceptingNewTickets(model) || app().tickets().hasTickets(model))) {
- PageParameters tParams = WicketUtils.newOpenTicketsParameter(repositoryName);
+ PageParameters tParams = WicketUtils.newOpenTicketsParameter(getRepositoryName());
navLinks.add(new PageNavLink("gb.tickets", TicketsPage.class, tParams));
}
navLinks.add(new PageNavLink("gb.docs", DocsPage.class, params, true));
@@ -229,7 +229,7 @@ public abstract class RepositoryPage extends RootPage {
// per-repository extra navlinks
if (JGitUtils.getPagesBranch(r) != null) {
ExternalNavLink pagesLink = new ExternalNavLink("gb.pages", PagesServlet.asLink(
- getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null), true);
+ getRequest().getRelativePathPrefixToContextRoot(), getRepositoryName(), null), true);
navLinks.add(pagesLink);
}
@@ -422,6 +422,10 @@ public abstract class RepositoryPage extends RootPage {
return m;
}
+ protected String getRepositoryName() {
+ return getRepositoryModel().name;
+ }
+
protected RevCommit getCommit() {
RevCommit commit = JGitUtils.getCommit(r, objectId);
if (commit == null) {
@@ -630,7 +634,7 @@ public abstract class RepositoryPage extends RootPage {
r = null;
}
// setup page header and footer
- setupPage(repositoryName, "/ " + getPageName());
+ setupPage(getRepositoryName(), "/ " + getPageName());
super.onBeforeRender();
}
diff --git a/src/main/java/com/gitblit/wicket/panels/BasePanel.java b/src/main/java/com/gitblit/wicket/panels/BasePanel.java
index e8f8f6f2..73f8e471 100644
--- a/src/main/java/com/gitblit/wicket/panels/BasePanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/BasePanel.java
@@ -22,6 +22,8 @@ import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
import com.gitblit.Keys;
@@ -36,6 +38,8 @@ public abstract class BasePanel extends Panel {
private transient TimeUtils timeUtils;
+ private transient Logger logger;
+
public BasePanel(String wicketId) {
super(wicketId);
}
@@ -44,6 +48,13 @@ public abstract class BasePanel extends Panel {
return GitBlitWebApp.get();
}
+ protected Logger logger() {
+ if (logger == null) {
+ logger = LoggerFactory.getLogger(getClass());
+ }
+ return logger;
+ }
+
protected String getContextUrl() {
return getRequest().getRelativePathPrefixToContextRoot();
}
diff --git a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
index 21f38388..e1706a09 100644
--- a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
@@ -38,8 +38,6 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
import com.gitblit.Keys;
@@ -63,8 +61,6 @@ public class HistoryPanel extends BasePanel {
private static final long serialVersionUID = 1L;
- private final Logger log = LoggerFactory.getLogger(getClass());
-
private boolean hasMore;
public HistoryPanel(String wicketId, final String repositoryName, final String objectId,
@@ -84,7 +80,7 @@ public class HistoryPanel extends BasePanel {
// commit missing
String msg = MessageFormat.format("Failed to find history of **{0}** *{1}*",
path, objectId);
- log.error(msg + " " + repositoryName);
+ logger().error(msg + " " + repositoryName);
add(new Label("commitHeader", MarkdownUtils.transformMarkdown(msg)).setEscapeModelStrings(false));
add(new Label("breadcrumbs"));
} else {
diff --git a/src/site/rpc.mkd b/src/site/rpc.mkd
index 302084fb..de4ed471 100644
--- a/src/site/rpc.mkd
+++ b/src/site/rpc.mkd
@@ -14,7 +14,7 @@ The Gitblit JSON RPC mechanism, like the Gitblit JGit servlet, syndication/feed
### Gitblit Manager
-[Gitblit Manager](http://code.google.com/p/gitblit/downloads/detail?name=%MANAGER%) is an example Java/Swing application that allows remote management (repository and user objects) and administration (server settings) of a Gitblit server.
+The Gitblit Manager is an example Java/Swing application that allows remote management (repository and user objects) and administration (server settings) of a Gitblit server.
This application uses a combination of RSS feeds and the JSON RPC interface, both of which are part of the [Gitblit API](http://code.google.com/p/gitblit/downloads/detail?name=%API%) library, to present live information from a Gitblit server. Some JSON RPC methods from the utility class `com.gitblit.utils.RpcUtils` are not currently used by the Gitblit Manager.
diff --git a/src/site/siteindex.mkd b/src/site/siteindex.mkd
index 58e18af1..aae25c89 100644
--- a/src/site/siteindex.mkd
+++ b/src/site/siteindex.mkd
@@ -83,7 +83,7 @@ Administrators can create and manage all repositories, user accounts, and teams
- Custom authentication, authorization, and user management
- Rich RSS feeds
- JSON-based RPC mechanism
-- [Java Client RSS/JSON API library](http://code.google.com/p/gitblit/downloads/detail?name=%API%) for custom integration
+- Java Client RSS/JSON API library for custom integration
### Backup Strategy