diff --git a/scm-core/src/main/java/sonia/scm/net/HttpClient.java b/scm-core/src/main/java/sonia/scm/net/HttpClient.java index 5878df1e1c..590f682e14 100644 --- a/scm-core/src/main/java/sonia/scm/net/HttpClient.java +++ b/scm-core/src/main/java/sonia/scm/net/HttpClient.java @@ -59,6 +59,19 @@ public interface HttpClient */ public HttpResponse post(String url) throws IOException; + /** + * Method description + * + * + * @param request + * + * @return + * @since 1.9 + * + * @throws IOException + */ + public HttpResponse post(HttpRequest request) throws IOException; + /** * Method description * @@ -87,6 +100,19 @@ public interface HttpClient */ public HttpResponse get(String url) throws IOException; + /** + * Method description + * + * + * @param request + * + * @return + * @since 1.9 + * + * @throws IOException + */ + public HttpResponse get(HttpRequest request) throws IOException; + /** * Method description * diff --git a/scm-core/src/main/java/sonia/scm/net/HttpRequest.java b/scm-core/src/main/java/sonia/scm/net/HttpRequest.java new file mode 100644 index 0000000000..7bd99abc9c --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/net/HttpRequest.java @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.net; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.util.AssertUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author Sebastian Sdorra + * @since 1.9 + */ +public class HttpRequest +{ + + /** + * Constructs ... + * + * + * @param url + */ + public HttpRequest(String url) + { + this.url = url; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param name + * @param values + * + * @return + */ + public HttpRequest addHeader(String name, String... values) + { + AssertUtil.assertIsNotNull(name); + + if (headers == null) + { + headers = new HashMap>(); + } + + appendValues(headers, name, values); + + return this; + } + + /** + * Method description + * + * + * @param name + * @param values + * + * @return + */ + public HttpRequest addParameters(String name, String... values) + { + AssertUtil.assertIsNotNull(name); + + if (parameters == null) + { + parameters = new HashMap>(); + } + + appendValues(parameters, name, values); + + return this; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public Map> getHeaders() + { + return headers; + } + + /** + * Method description + * + * + * @return + */ + public Map> getParameters() + { + return parameters; + } + + /** + * Method description + * + * + * @return + */ + public String getPassword() + { + return password; + } + + /** + * Method description + * + * + * @return + */ + public String getUrl() + { + return url; + } + + /** + * Method description + * + * + * @return + */ + public String getUsername() + { + return username; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param username + * @param password + * + * @return + */ + public HttpRequest setBasicAuthentication(String username, String password) + { + this.username = username; + this.password = password; + + return this; + } + + /** + * Method description + * + * + * @param headers + * + * @return + */ + public HttpRequest setHeaders(Map> headers) + { + this.headers = headers; + + return this; + } + + /** + * Method description + * + * + * @param parameters + * + * @return + */ + public HttpRequest setParameters(Map> parameters) + { + this.parameters = parameters; + + return this; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param map + * @param name + * @param values + */ + private void appendValues(Map> map, String name, + String[] values) + { + List valueList = map.get(name); + + if (valueList == null) + { + valueList = new ArrayList(); + map.put(name, valueList); + } + + if (values != null) + { + valueList.addAll(Arrays.asList(values)); + } + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private Map> headers; + + /** Field description */ + private Map> parameters; + + /** Field description */ + private String password; + + /** Field description */ + private String url; + + /** Field description */ + private String username; +} diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 3fad0c31dc..5d8010314a 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -20,7 +20,7 @@ commons-daemon commons-daemon - 1.0.5 + 1.0.8 @@ -75,6 +75,7 @@ scm-server + 1.0.8 sonia.scm.server.ScmServerDaemon commons-daemon diff --git a/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java b/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java index 3f298fe6cc..0c91afac1f 100644 --- a/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java +++ b/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java @@ -83,6 +83,9 @@ public class URLHttpClient implements HttpClient /** Field description */ public static final String HEADER_ACCEPT_ENCODING_VALUE = "gzip"; + /** Field description */ + public static final String HEADER_AUTHORIZATION = "Authorization"; + /** Field description */ public static final String HEADER_PROXY_AUTHORIZATION = "Proxy-Authorization"; @@ -141,7 +144,8 @@ public class URLHttpClient implements HttpClient @Override public HttpResponse post(String url) throws IOException { - HttpURLConnection connection = (HttpURLConnection) openConnection(url); + HttpURLConnection connection = (HttpURLConnection) openConnection(null, + url); connection.setRequestMethod(METHOD_POST); @@ -163,10 +167,180 @@ public class URLHttpClient implements HttpClient public HttpResponse post(String url, Map> parameters) throws IOException { - HttpURLConnection connection = (HttpURLConnection) openConnection(url); + HttpURLConnection connection = (HttpURLConnection) openConnection(null, + url); connection.setRequestMethod(METHOD_POST); + appendPostParameter(connection, parameters); + return new URLHttpResponse(connection); + } + + /** + * Method description + * + * + * @param request + * + * @return + * + * @throws IOException + */ + @Override + public HttpResponse post(HttpRequest request) throws IOException + { + HttpURLConnection connection = (HttpURLConnection) openConnection(request, + request.getUrl()); + + connection.setRequestMethod(METHOD_POST); + appendPostParameter(connection, request.getParameters()); + + return new URLHttpResponse(connection); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param spec + * + * @return + * + * @throws IOException + */ + @Override + public HttpResponse get(String spec) throws IOException + { + return new URLHttpResponse(openConnection(null, spec)); + } + + /** + * Method description + * + * + * @param url + * @param parameters + * + * @return + * + * @throws IOException + */ + @Override + public HttpResponse get(String url, Map> parameters) + throws IOException + { + url = createGetUrl(url, parameters); + + return new URLHttpResponse(openConnection(null, url)); + } + + /** + * Method description + * + * + * @param request + * + * @return + * + * @throws IOException + */ + @Override + public HttpResponse get(HttpRequest request) throws IOException + { + String url = createGetUrl(request.getUrl(), request.getParameters()); + + return new URLHttpResponse(openConnection(request, url)); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param connection + * @param header + * @param username + * @param password + */ + private void appendBasicAuthHeader(HttpURLConnection connection, + String header, String username, + String password) + { + if (Util.isNotEmpty(username) || Util.isNotEmpty(password)) + { + username = Util.nonNull(username); + password = Util.nonNull(password); + + if (logger.isDebugEnabled()) + { + logger.debug("append {} header for user {}", header, username); + } + + String auth = username.concat(CREDENTIAL_SEPARATOR).concat(password); + + auth = new String(Base64.encode(auth.getBytes())); + connection.addRequestProperty(header, + PREFIX_BASIC_AUTHENTICATION.concat(auth)); + } + } + + /** + * Method description + * + * + * @param headers + * @param connection + */ + private void appendHeaders(Map> headers, + URLConnection connection) + { + if (Util.isNotEmpty(headers)) + { + for (Map.Entry> e : headers.entrySet()) + { + String name = e.getKey(); + List values = e.getValue(); + + if (Util.isNotEmpty(name) && Util.isNotEmpty(values)) + { + for (String value : values) + { + if (logger.isTraceEnabled()) + { + logger.trace("append header {}:{}", name, value); + } + + connection.setRequestProperty(name, value); + } + } + else if (logger.isWarnEnabled()) + { + logger.warn("value of {} header is empty", name); + } + } + } + else if (logger.isTraceEnabled()) + { + logger.trace("header map is emtpy"); + } + } + + /** + * Method description + * + * + * @param connection + * @param parameters + * + * @throws IOException + */ + private void appendPostParameter(HttpURLConnection connection, + Map> parameters) + throws IOException + { if (Util.isNotEmpty(parameters)) { connection.setDoOutput(true); @@ -206,26 +380,6 @@ public class URLHttpClient implements HttpClient IOUtil.close(writer); } } - - return new URLHttpResponse(connection); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param spec - * - * @return - * - * @throws IOException - */ - @Override - public HttpResponse get(String spec) throws IOException - { - return new URLHttpResponse(openConnection(spec)); } /** @@ -236,12 +390,8 @@ public class URLHttpClient implements HttpClient * @param parameters * * @return - * - * @throws IOException */ - @Override - public HttpResponse get(String url, Map> parameters) - throws IOException + private String createGetUrl(String url, Map> parameters) { if (Util.isNotEmpty(parameters)) { @@ -275,11 +425,9 @@ public class URLHttpClient implements HttpClient url = ub.toString(); } - return new URLHttpResponse(openConnection(url)); + return url; } - //~--- methods -------------------------------------------------------------- - /** * Method description * @@ -306,30 +454,36 @@ public class URLHttpClient implements HttpClient * Method description * * + * + * @param request * @param spec * * @return * * @throws IOException */ - private URLConnection openConnection(String spec) throws IOException + private HttpURLConnection openConnection(HttpRequest request, String spec) + throws IOException { - return openConnection(new URL(spec)); + return openConnection(request, new URL(spec)); } /** * Method description * * + * + * @param request * @param url * * @return * * @throws IOException */ - private URLConnection openConnection(URL url) throws IOException + private HttpURLConnection openConnection(HttpRequest request, URL url) + throws IOException { - URLConnection connection = null; + HttpURLConnection connection = null; if (configuration.isEnableProxy()) { @@ -345,7 +499,9 @@ public class URLHttpClient implements HttpClient new InetSocketAddress(configuration.getProxyServer(), configuration.getProxyPort()); - connection = url.openConnection(new Proxy(Proxy.Type.HTTP, address)); + connection = + (HttpURLConnection) url.openConnection(new Proxy(Proxy.Type.HTTP, + address)); } else { @@ -354,11 +510,25 @@ public class URLHttpClient implements HttpClient logger.debug("fetch '{}'", url.toExternalForm()); } - connection = url.openConnection(); + connection = (HttpURLConnection) url.openConnection(); } connection.setReadTimeout(TIMEOUT_RAED); connection.setConnectTimeout(TIMEOUT_CONNECTION); + + if (request != null) + { + Map> headers = request.getHeaders(); + + appendHeaders(headers, connection); + + String username = request.getUsername(); + String password = request.getPassword(); + + appendBasicAuthHeader(connection, HEADER_AUTHORIZATION, username, + password); + } + connection.setRequestProperty(HEADER_ACCEPT_ENCODING, HEADER_ACCEPT_ENCODING_VALUE); connection.setRequestProperty( @@ -367,21 +537,8 @@ public class URLHttpClient implements HttpClient String username = configuration.getProxyUser(); String password = configuration.getProxyPassword(); - if (Util.isNotEmpty(username) || Util.isNotEmpty(password)) - { - if (logger.isDebugEnabled()) - { - logger.debug("enable proxy authentication for user '{}'", - Util.nonNull(username)); - } - - String auth = Util.nonNull(username).concat(CREDENTIAL_SEPARATOR).concat( - Util.nonNull(password)); - - auth = PREFIX_BASIC_AUTHENTICATION.concat( - new String(Base64.encode(auth.getBytes()))); - connection.setRequestProperty(HEADER_PROXY_AUTHORIZATION, auth); - } + appendBasicAuthHeader(connection, HEADER_PROXY_AUTHORIZATION, username, + password); return connection; }