James Moger
2011-10-28 565ee056cd74a119b6b7c108239a6470976d02b7
Bug fix to rss feed. Unit test for rss feed. Refactor ssl connection.
1 files added
4 files modified
295 ■■■■■ changed files
src/com/gitblit/SyndicationFilter.java 3 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/ConnectionUtils.java 126 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/JsonUtils.java 103 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/SyndicationUtils.java 53 ●●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/SyndicationUtilsTest.java 10 ●●●●● patch | view | raw | blame | history
src/com/gitblit/SyndicationFilter.java
@@ -37,6 +37,9 @@
     */
    @Override
    protected String extractRepositoryName(String url) {
        if (url.indexOf('?') > -1) {
            return url.substring(0, url.indexOf('?'));
        }
        return url;
    }
src/com/gitblit/utils/ConnectionUtils.java
New file
@@ -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;
        }
    }
}
src/com/gitblit/utils/JsonUtils.java
@@ -22,11 +22,7 @@
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;
@@ -35,15 +31,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;
@@ -70,30 +57,11 @@
 */
public class JsonUtils {
    public static final String CHARSET;
    public static final Type REPOSITORIES_TYPE = new TypeToken<Map<String, RepositoryModel>>() {
    }.getType();
    public static final Type USERS_TYPE = new TypeToken<Collection<UserModel>>() {
    }.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 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 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();
@@ -293,15 +242,6 @@
                throw new UnknownRequestException(url);
            }
            throw e;
        }
    }
    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()));
        }
    }
@@ -341,37 +281,6 @@
            } catch (ParseException e) {
                throw new JsonSyntaxException(jsonElement.getAsString(), e);
            }
        }
    }
    /**
     * 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;
        }
    }
}
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.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 @@
        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;
    }
}
tests/com/gitblit/tests/SyndicationUtilsTest.java
@@ -23,8 +23,10 @@
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 @@
        assertTrue(feed.indexOf("<title>Title</title>") > -1);
        assertTrue(feed.indexOf("<description>Description</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());
    }
}