From 565ee056cd74a119b6b7c108239a6470976d02b7 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 28 Oct 2011 07:48:17 -0400 Subject: [PATCH] Bug fix to rss feed. Unit test for rss feed. Refactor ssl connection. --- src/com/gitblit/SyndicationFilter.java | 3 + src/com/gitblit/utils/ConnectionUtils.java | 126 ++++++++++++++++++ src/com/gitblit/utils/JsonUtils.java | 103 +------------- src/com/gitblit/utils/SyndicationUtils.java | 53 ++++++++ .../gitblit/tests/SyndicationUtilsTest.java | 10 ++ 5 files changed, 198 insertions(+), 97 deletions(-) create mode 100644 src/com/gitblit/utils/ConnectionUtils.java diff --git a/src/com/gitblit/SyndicationFilter.java b/src/com/gitblit/SyndicationFilter.java index e0424605..9c7a8630 100644 --- a/src/com/gitblit/SyndicationFilter.java +++ b/src/com/gitblit/SyndicationFilter.java @@ -37,6 +37,9 @@ public class SyndicationFilter extends AccessRestrictionFilter { */ @Override protected String extractRepositoryName(String url) { + if (url.indexOf('?') > -1) { + return url.substring(0, url.indexOf('?')); + } return url; } diff --git a/src/com/gitblit/utils/ConnectionUtils.java b/src/com/gitblit/utils/ConnectionUtils.java new file mode 100644 index 00000000..93693ab9 --- /dev/null +++ b/src/com/gitblit/utils/ConnectionUtils.java @@ -0,0 +1,126 @@ +/* + * 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.utils; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.eclipse.jgit.util.Base64; + +/** + * Utility class for establishing HTTP/HTTPS connections. + * + * @author James Moger + * + */ +public class ConnectionUtils { + + static final String CHARSET; + + private static final SSLContext SSL_CONTEXT; + + private static final DummyHostnameVerifier HOSTNAME_VERIFIER; + + static { + SSLContext context = null; + try { + context = SSLContext.getInstance("SSL"); + context.init(null, new TrustManager[] { new DummyTrustManager() }, new SecureRandom()); + } catch (Throwable t) { + t.printStackTrace(); + } + SSL_CONTEXT = context; + HOSTNAME_VERIFIER = new DummyHostnameVerifier(); + CHARSET = "UTF-8"; + } + + public static void setAuthorization(URLConnection conn, String username, char[] password) { + if (!StringUtils.isEmpty(username) && (password != null && password.length > 0)) { + conn.setRequestProperty( + "Authorization", + "Basic " + + Base64.encodeBytes((username + ":" + new String(password)).getBytes())); + } + } + + public static URLConnection openReadConnection(String url, String username, char[] password) + throws IOException { + URLConnection conn = openConnection(url, username, password); + conn.setRequestProperty("Accept-Charset", ConnectionUtils.CHARSET); + return conn; + } + + public static URLConnection openConnection(String url, String username, char[] password) + throws IOException { + URL urlObject = new URL(url); + URLConnection conn = urlObject.openConnection(); + setAuthorization(conn, username, password); + conn.setUseCaches(false); + conn.setDoOutput(true); + if (conn instanceof HttpsURLConnection) { + HttpsURLConnection secureConn = (HttpsURLConnection) conn; + secureConn.setSSLSocketFactory(SSL_CONTEXT.getSocketFactory()); + secureConn.setHostnameVerifier(HOSTNAME_VERIFIER); + } + return conn; + } + + /** + * DummyTrustManager trusts all certificates. + * + * @author James Moger + */ + private static class DummyTrustManager implements X509TrustManager { + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) + throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } + + /** + * Trusts all hostnames from a certificate, including self-signed certs. + * + * @author James Moger + */ + private static class DummyHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + } +} diff --git a/src/com/gitblit/utils/JsonUtils.java b/src/com/gitblit/utils/JsonUtils.java index 5b53bf46..3cb43eb1 100644 --- a/src/com/gitblit/utils/JsonUtils.java +++ b/src/com/gitblit/utils/JsonUtils.java @@ -22,11 +22,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; -import java.net.URL; import java.net.URLConnection; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -36,15 +32,6 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.eclipse.jgit.util.Base64; - import com.gitblit.GitBlitException.ForbiddenException; import com.gitblit.GitBlitException.NotAllowedException; import com.gitblit.GitBlitException.UnauthorizedException; @@ -70,31 +57,12 @@ import com.google.gson.reflect.TypeToken; */ public class JsonUtils { - public static final String CHARSET; - public static final Type REPOSITORIES_TYPE = new TypeToken>() { }.getType(); public static final Type USERS_TYPE = new TypeToken>() { }.getType(); - private static final SSLContext SSL_CONTEXT; - - private static final DummyHostnameVerifier HOSTNAME_VERIFIER; - - static { - SSLContext context = null; - try { - context = SSLContext.getInstance("SSL"); - context.init(null, new TrustManager[] { new DummyTrustManager() }, new SecureRandom()); - } catch (Throwable t) { - t.printStackTrace(); - } - SSL_CONTEXT = context; - HOSTNAME_VERIFIER = new DummyHostnameVerifier(); - CHARSET = "UTF-8"; - } - /** * Creates JSON from the specified object. * @@ -188,20 +156,10 @@ public class JsonUtils { */ public static String retrieveJsonString(String url, String username, char[] password) throws IOException { - try { - URL urlObject = new URL(url); - URLConnection conn = urlObject.openConnection(); - conn.setRequestProperty("Accept-Charset", CHARSET); - setAuthorization(conn, username, password); - conn.setUseCaches(false); - conn.setDoInput(true); - if (conn instanceof HttpsURLConnection) { - HttpsURLConnection secureConn = (HttpsURLConnection) conn; - secureConn.setSSLSocketFactory(SSL_CONTEXT.getSocketFactory()); - secureConn.setHostnameVerifier(HOSTNAME_VERIFIER); - } + try { + URLConnection conn = ConnectionUtils.openReadConnection(url, username, password); InputStream is = conn.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(is, CHARSET)); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, ConnectionUtils.CHARSET)); StringBuilder json = new StringBuilder(); char[] buffer = new char[4096]; int len = 0; @@ -257,19 +215,10 @@ public class JsonUtils { public static int sendJsonString(String url, String json, String username, char[] password) throws IOException { try { - byte[] jsonBytes = json.getBytes(CHARSET); - URL urlObject = new URL(url); - URLConnection conn = urlObject.openConnection(); - conn.setRequestProperty("Content-Type", "text/plain;charset=" + CHARSET); + byte[] jsonBytes = json.getBytes(ConnectionUtils.CHARSET); + URLConnection conn = ConnectionUtils.openConnection(url, username, password); + conn.setRequestProperty("Content-Type", "text/plain;charset=" + ConnectionUtils.CHARSET); conn.setRequestProperty("Content-Length", "" + jsonBytes.length); - setAuthorization(conn, username, password); - conn.setUseCaches(false); - conn.setDoOutput(true); - if (conn instanceof HttpsURLConnection) { - HttpsURLConnection secureConn = (HttpsURLConnection) conn; - secureConn.setSSLSocketFactory(SSL_CONTEXT.getSocketFactory()); - secureConn.setHostnameVerifier(HOSTNAME_VERIFIER); - } // write json body OutputStream os = conn.getOutputStream(); @@ -296,15 +245,6 @@ public class JsonUtils { } } - private static void setAuthorization(URLConnection conn, String username, char[] password) { - if (!StringUtils.isEmpty(username) && (password != null && password.length > 0)) { - conn.setRequestProperty( - "Authorization", - "Basic " - + Base64.encodeBytes((username + ":" + new String(password)).getBytes())); - } - } - // build custom gson instance with GMT date serializer/deserializer // http://code.google.com/p/google-gson/issues/detail?id=281 private static Gson gson() { @@ -343,35 +283,4 @@ public class JsonUtils { } } } - - /** - * DummyTrustManager trusts all certificates. - */ - private static class DummyTrustManager implements X509TrustManager { - - @Override - public void checkClientTrusted(X509Certificate[] certs, String authType) - throws CertificateException { - } - - @Override - public void checkServerTrusted(X509Certificate[] certs, String authType) - throws CertificateException { - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - - /** - * Trusts all hostnames from a certificate, including self-signed certs. - */ - private static class DummyHostnameVerifier implements HostnameVerifier { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - } } diff --git a/src/com/gitblit/utils/SyndicationUtils.java b/src/com/gitblit/utils/SyndicationUtils.java index fb40dd56..3664a181 100644 --- a/src/com/gitblit/utils/SyndicationUtils.java +++ b/src/com/gitblit/utils/SyndicationUtils.java @@ -16,8 +16,10 @@ package com.gitblit.utils; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.net.URLConnection; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; @@ -33,7 +35,9 @@ import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.feed.synd.SyndFeedImpl; import com.sun.syndication.feed.synd.SyndImageImpl; import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.SyndFeedInput; import com.sun.syndication.io.SyndFeedOutput; +import com.sun.syndication.io.XmlReader; /** * Utility class for RSS feeds. @@ -93,4 +97,53 @@ public class SyndicationUtils { output.output(feed, writer); writer.close(); } + + /** + * Reads a Gitblit RSS feed. + * + * @param url + * the url of the Gitblit server + * @param repository + * the repository name + * @param branch + * the branch name (optional) + * @param numberOfEntries + * the number of entries to retrieve. if <= 0 the server default + * is used. + * @param username + * @param password + * @return the JSON message as a string + * @throws {@link IOException} + */ + public static SyndFeed readFeed(String url, String repository, String branch, + int numberOfEntries, String username, char[] password) throws IOException, + FeedException { + String feedUrl; + if (StringUtils.isEmpty(branch)) { + // no branch specified + if (numberOfEntries > 0) { + // fixed number of entries + feedUrl = MessageFormat.format("{0}/feed/{1}?l={2,number,0}", url, repository); + } else { + // server default number of entries + feedUrl = MessageFormat.format("{0}/feed/{1}", url, repository); + } + } else { + // branch specified + if (numberOfEntries > 0) { + // fixed number of entries + feedUrl = MessageFormat.format("{0}/feed/{1}?h={2}&l={3,number,0}", url, + repository, branch, numberOfEntries); + } else { + // server default number of entries + feedUrl = MessageFormat.format("{0}/feed/{1}?h={2}", url, repository, branch); + } + } + URLConnection conn = ConnectionUtils.openReadConnection(feedUrl, username, password); + InputStream is = conn.getInputStream(); + SyndFeedInput input = new SyndFeedInput(); + SyndFeed feed = input.build(new XmlReader(is)); + is.close(); + return feed; + } } diff --git a/tests/com/gitblit/tests/SyndicationUtilsTest.java b/tests/com/gitblit/tests/SyndicationUtilsTest.java index 1fa21fc3..33d7dbd2 100644 --- a/tests/com/gitblit/tests/SyndicationUtilsTest.java +++ b/tests/com/gitblit/tests/SyndicationUtilsTest.java @@ -23,8 +23,10 @@ import junit.framework.TestCase; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import com.gitblit.client.GitblitFeed; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.SyndicationUtils; +import com.sun.syndication.feed.synd.SyndFeed; public class SyndicationUtilsTest extends TestCase { @@ -40,4 +42,12 @@ public class SyndicationUtilsTest extends TestCase { assertTrue(feed.indexOf("Title") > -1); assertTrue(feed.indexOf("Description") > -1); } + + public void testFeedRead() throws Exception { + GitblitFeed reader = new GitblitFeed("https://localhost:8443", "ticgit.git", "master"); + SyndFeed feed = reader.update(5, "admin", "admin".toCharArray()); + assertTrue(feed != null); + assertTrue(feed.getEntries().size() > 0); + assertEquals(5, feed.getEntries().size()); + } } \ No newline at end of file -- 2.39.5