diff --git a/pom.xml b/pom.xml index edfb4cf3..119cc98e 100644 --- a/pom.xml +++ b/pom.xml @@ -61,16 +61,6 @@ - - commons-httpclient - commons-httpclient - 3.1 - - - commons-codec - commons-codec - 1.10 - org.jenkins-ci.plugins jackson2-api @@ -131,23 +121,6 @@ - - - - org.codehaus.mojo - findbugs-maven-plugin - - ${basedir}/src/findbugs-exclude.xml - - - - maven-javadoc-plugin - - stashpullrequestbuilder.stashpullrequestbuilder.repackage.* - - - - com.github.ekryd.sortpom diff --git a/src/findbugs-exclude.xml b/src/findbugs-exclude.xml deleted file mode 100644 index 2331a9a6..00000000 --- a/src/findbugs-exclude.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/repackage/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java b/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/repackage/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java deleted file mode 100644 index f85e6fef..00000000 --- a/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/repackage/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java,v 1.7 2004/06/11 19:26:27 olegk Exp $ - * $Revision: 480424 $ - * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ - * - * ==================================================================== - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package stashpullrequestbuilder.stashpullrequestbuilder.repackage.org.apache.commons.httpclient.contrib.ssl; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.HttpClientError; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s that accept self-signed - * certificates. - * - *

This socket factory SHOULD NOT be used for productive systems due to security reasons, unless - * it is a concious decision and you are perfectly aware of security implications of accepting - * self-signed certificates - * - *

Example of using custom protocol socket factory for a specific host: - * - *

- *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
- *
- *     HttpClient client = new HttpClient();
- *     client.getHostConfiguration().setHost("localhost", 443, easyhttps);
- *     // use relative url only
- *     GetMethod httpget = new GetMethod("/");
- *     client.executeMethod(httpget);
- *     
- * - *

Example of using custom protocol socket factory per default instead of the standard one: - * - *

- *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
- *     Protocol.registerProtocol("https", easyhttps);
- *
- *     HttpClient client = new HttpClient();
- *     GetMethod httpget = new GetMethod("https://localhost/");
- *     client.executeMethod(httpget);
- *     
- * - * @author Oleg Kalnichevski - *

DISCLAIMER: HttpClient developers DO NOT actively support this component. The component is - * provided as a reference material, which may be inappropriate for use without additional - * customization. - */ -public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { - - /** Log object for this class. */ - private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); - - private SSLContext sslcontext = null; - - /** Constructor for EasySSLProtocolSocketFactory. */ - public EasySSLProtocolSocketFactory() { - super(); - } - - private static SSLContext createEasySSLContext() { - try { - SSLContext context = SSLContext.getInstance("SSL"); - context.init(null, new TrustManager[] {new EasyX509TrustManager(null)}, null); - return context; - } catch (Exception e) { - LOG.error(e.getMessage(), e); - throw new HttpClientError(e.toString()); - } - } - - private SSLContext getSSLContext() { - if (this.sslcontext == null) { - this.sslcontext = createEasySSLContext(); - } - return this.sslcontext; - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) - */ - public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) - throws IOException, UnknownHostException { - - return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); - } - - /** - * Attempts to get a new socket connection to the given host within the given time limit. - * - *

To circumvent the limitations of older JREs that do not support connect timeout a controller - * thread is executed. The controller thread attempts to create a new socket within the given - * limit of time. If socket constructor does not return until the timeout expires, the controller - * terminates and throws an {@link ConnectTimeoutException} - * - * @param host the host name/IP - * @param port the port on the host - * @param clientHost the local host name/IP to bind the socket to - * @param clientPort the port on the local machine - * @param params {@link HttpConnectionParams Http connection parameters} - * @return Socket a new socket - * @throws IOException if an I/O error occurs while creating the socket - * @throws UnknownHostException if the IP address of the host cannot be determined - */ - public Socket createSocket( - final String host, - final int port, - final InetAddress localAddress, - final int localPort, - final HttpConnectionParams params) - throws IOException, UnknownHostException, ConnectTimeoutException { - if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); - } - int timeout = params.getConnectionTimeout(); - SocketFactory socketfactory = getSSLContext().getSocketFactory(); - if (timeout == 0) { - return socketfactory.createSocket(host, port, localAddress, localPort); - } else { - Socket socket = socketfactory.createSocket(); - SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); - SocketAddress remoteaddr = new InetSocketAddress(host, port); - socket.bind(localaddr); - socket.connect(remoteaddr, timeout); - return socket; - } - } - - /** @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) */ - public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(host, port); - } - - /** @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) */ - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) - throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); - } - - public boolean equals(Object obj) { - return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class)); - } - - public int hashCode() { - return EasySSLProtocolSocketFactory.class.hashCode(); - } -} diff --git a/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/repackage/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java b/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/repackage/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java deleted file mode 100644 index 6e413b8d..00000000 --- a/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/repackage/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * ==================================================================== - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package stashpullrequestbuilder.stashpullrequestbuilder.repackage.org.apache.commons.httpclient.contrib.ssl; - -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * EasyX509TrustManager unlike default {@link X509TrustManager} accepts self-signed certificates. - * - *

This trust manager SHOULD NOT be used for productive systems due to security reasons, unless - * it is a concious decision and you are perfectly aware of security implications of accepting - * self-signed certificates - * - * @author Adrian Sutton - * @author Oleg Kalnichevski - *

DISCLAIMER: HttpClient developers DO NOT actively support this component. The component is - * provided as a reference material, which may be inappropriate for use without additional - * customization. - */ -public class EasyX509TrustManager implements X509TrustManager { - private X509TrustManager standardTrustManager = null; - - /** Log object for this class. */ - private static final Log LOG = LogFactory.getLog(EasyX509TrustManager.class); - - /** Constructor for EasyX509TrustManager. */ - public EasyX509TrustManager(KeyStore keystore) - throws NoSuchAlgorithmException, KeyStoreException { - super(); - TrustManagerFactory factory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - factory.init(keystore); - TrustManager[] trustmanagers = factory.getTrustManagers(); - if (trustmanagers.length == 0) { - throw new NoSuchAlgorithmException("no trust manager found"); - } - this.standardTrustManager = (X509TrustManager) trustmanagers[0]; - } - - /** @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) */ - public void checkClientTrusted(X509Certificate[] certificates, String authType) - throws CertificateException { - standardTrustManager.checkClientTrusted(certificates, authType); - } - - /** @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType) */ - public void checkServerTrusted(X509Certificate[] certificates, String authType) - throws CertificateException { - if ((certificates != null) && LOG.isDebugEnabled()) { - LOG.debug("Server certificate chain:"); - for (int i = 0; i < certificates.length; i++) { - LOG.debug("X509Certificate[" + i + "]=" + certificates[i]); - } - } - if ((certificates != null) && (certificates.length == 1)) { - certificates[0].checkValidity(); - } else { - standardTrustManager.checkServerTrusted(certificates, authType); - } - } - - /** @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() */ - public X509Certificate[] getAcceptedIssuers() { - return this.standardTrustManager.getAcceptedIssuers(); - } -} diff --git a/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClient.java b/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClient.java index 7caaa583..f5e72fed 100644 --- a/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClient.java +++ b/src/main/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClient.java @@ -4,18 +4,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.lang.invoke.MethodHandles; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.UnknownHostException; import java.security.KeyManagementException; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -27,33 +22,27 @@ import java.util.logging.Logger; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.Credentials; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpClientError; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.methods.DeleteMethod; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.params.HttpParams; -import org.apache.commons.httpclient.protocol.Protocol; -import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthenticationException; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.ssl.SSLContextBuilder; /** Created by Nathan McCarthy */ -@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS") public class StashApiClient { // Request timeout: maximum time between sending an HTTP request and receiving @@ -76,6 +65,7 @@ public class StashApiClient { private String project; private String repositoryName; private Credentials credentials; + private boolean ignoreSsl; public StashApiClient( String stashHost, @@ -88,11 +78,7 @@ public StashApiClient( this.project = project; this.repositoryName = repositoryName; this.apiBaseUrl = stashHost.replaceAll("/$", "") + "/rest/api/1.0/projects/"; - if (ignoreSsl) { - Protocol easyhttps = - new Protocol("https", (ProtocolSocketFactory) new EasySSLProtocolSocketFactory(), 443); - Protocol.registerProtocol("https", easyhttps); - } + this.ignoreSsl = ignoreSsl; } @Nonnull @@ -191,47 +177,48 @@ public boolean mergePullRequest(String pullRequestId, String version) throws Sta return !response.equals(Integer.toString(HttpStatus.SC_CONFLICT)); } - private HttpClient getHttpClient() { - HttpClient client = new HttpClient(); - HttpParams httpParams = client.getParams(); - httpParams.setParameter( - CoreConnectionPNames.CONNECTION_TIMEOUT, HTTP_CONNECTION_TIMEOUT_SECONDS * 1000); - httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, HTTP_SOCKET_TIMEOUT_SECONDS * 1000); - - // if (Jenkins.getInstance() != null) { - // ProxyConfiguration proxy = Jenkins.getInstance().proxy; - // if (proxy != null) { - // logger.info("Jenkins proxy: " + proxy.name + ":" + proxy.port); - // client.getHostConfiguration().setProxy(proxy.name, proxy.port); - // String username = proxy.getUserName(); - // String password = proxy.getPassword(); - // // Consider it to be passed if username specified. Sufficient? - // if (username != null && !"".equals(username.trim())) { - // logger.info("Using proxy authentication (user=" + username + ")"); - // client.getState().setProxyCredentials(AuthScope.ANY, - // new UsernamePasswordCredentials(username, password)); - // } - // } - // } - return client; + private CloseableHttpClient getHttpClient() throws StashApiException { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().useSystemProperties(); + + if (this.ignoreSsl) { + try { + SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); + + sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + SSLConnectionSocketFactory sslConnectionSocketFactory = + new SSLConnectionSocketFactory( + sslContextBuilder.build(), NoopHostnameVerifier.INSTANCE); + httpClientBuilder.setSSLSocketFactory(sslConnectionSocketFactory); + } catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) { + throw new StashApiException("Failed to setup the SSLConnectionFactory", e); + } + } + + RequestConfig.Builder requestBuilder = + RequestConfig.custom() + .setConnectTimeout(HTTP_CONNECTION_TIMEOUT_SECONDS * 1000) + .setSocketTimeout(HTTP_SOCKET_TIMEOUT_SECONDS * 1000); + httpClientBuilder.setDefaultRequestConfig(requestBuilder.build()); + + return httpClientBuilder.build(); } private String getRequest(String path) throws StashApiException { logger.log(Level.FINEST, "PR-GET-REQUEST:" + path); - HttpClient client = getHttpClient(); - client.getState().setCredentials(AuthScope.ANY, credentials); + CloseableHttpClient client = getHttpClient(); - GetMethod request = new GetMethod(path); + HttpGet request = new HttpGet(path); // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html; section 14.10. // tells the server that we want it to close the connection when it has sent the response. // address large amount of close_wait sockets client and fin sockets server side - request.setRequestHeader("Connection", "close"); + request.addHeader("Connection", "close"); - client.getParams().setAuthenticationPreemptive(true); String response = null; FutureTask httpTask = null; Thread thread; try { + request.addHeader(new BasicScheme().authenticate(credentials, request, null)); + // Run the HTTP request in a future task so we have the opportunity // to cancel it if it gets hung up; which is possible if stuck at // socket native layer. see issue JENKINS-30558 @@ -239,25 +226,26 @@ private String getRequest(String path) throws StashApiException { new FutureTask( new Callable() { - private HttpClient client; - private GetMethod request; + private CloseableHttpClient client; + private HttpGet request; @Override public String call() throws StashApiException, IOException { String response = null; - int responseCode = HttpStatus.SC_INTERNAL_SERVER_ERROR; - responseCode = client.executeMethod(request); + HttpResponse httpResponse = client.execute(request); + int responseCode = httpResponse.getStatusLine().getStatusCode(); if (!validResponseCode(responseCode)) { logger.log( Level.SEVERE, - "Failing to get response from Stash PR GET" + request.getPath()); + "Failing to get response from Stash PR GET" + request.getURI()); throw new StashApiException( "Didn't get a 200 response from Stash PR GET! Response; '" - + HttpStatus.getStatusText(responseCode) + + responseCode + "' with message; " - + response); + + httpResponse.getStatusLine().getReasonPhrase()); } - InputStream responseBodyAsStream = request.getResponseBodyAsStream(); + + InputStream responseBodyAsStream = httpResponse.getEntity().getContent(); StringWriter stringWriter = new StringWriter(); IOUtils.copy(responseBodyAsStream, stringWriter, "UTF-8"); response = stringWriter.toString(); @@ -265,7 +253,7 @@ public String call() throws StashApiException, IOException { return response; } - public Callable init(HttpClient client, GetMethod request) { + public Callable init(CloseableHttpClient client, HttpGet request) { this.client = client; this.request = request; return this; @@ -278,7 +266,7 @@ public Callable init(HttpClient client, GetMethod request) { } catch (TimeoutException e) { request.abort(); throw new StashApiException("Timeout in GET request", e); - } catch (InterruptedException | ExecutionException e) { + } catch (AuthenticationException | ExecutionException | InterruptedException e) { throw new StashApiException("Exception in GET request", e); } finally { request.releaseConnection(); @@ -288,21 +276,21 @@ public Callable init(HttpClient client, GetMethod request) { } public void deleteRequest(String path) throws StashApiException { - HttpClient client = getHttpClient(); - client.getState().setCredentials(AuthScope.ANY, credentials); + CloseableHttpClient client = getHttpClient(); - DeleteMethod request = new DeleteMethod(path); + HttpDelete request = new HttpDelete(path); // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html; section 14.10. // tells the server that we want it to close the connection when it has sent the response. // address large amount of close_wait sockets client and fin sockets server side - request.setRequestHeader("Connection", "close"); + request.setHeader("Connection", "close"); - client.getParams().setAuthenticationPreemptive(true); int response = -1; FutureTask httpTask = null; Thread thread; try { + request.addHeader(new BasicScheme().authenticate(credentials, request, null)); + // Run the HTTP request in a future task so we have the opportunity // to cancel it if it gets hung up; which is possible if stuck at // socket native layer. see issue JENKINS-30558 @@ -310,17 +298,17 @@ public void deleteRequest(String path) throws StashApiException { new FutureTask( new Callable() { - private HttpClient client; - private DeleteMethod request; + private CloseableHttpClient client; + private HttpDelete request; @Override - public Integer call() throws StashApiException, HttpException, IOException { + public Integer call() throws StashApiException, IOException { int response = -1; - response = client.executeMethod(request); + response = client.execute(request).getStatusLine().getStatusCode(); return response; } - public Callable init(HttpClient client, DeleteMethod request) { + public Callable init(CloseableHttpClient client, HttpDelete request) { this.client = client; this.request = request; return this; @@ -333,7 +321,7 @@ public Callable init(HttpClient client, DeleteMethod request) { } catch (TimeoutException e) { request.abort(); throw new StashApiException("Timeout in DELETE request", e); - } catch (ExecutionException | InterruptedException e) { + } catch (AuthenticationException | ExecutionException | InterruptedException e) { throw new StashApiException("Exception in DELETE request", e); } finally { request.releaseConnection(); @@ -344,36 +332,35 @@ public Callable init(HttpClient client, DeleteMethod request) { private String postRequest(String path, String comment) throws StashApiException { logger.log(Level.FINEST, "PR-POST-REQUEST:" + path + " with: " + comment); - HttpClient client = getHttpClient(); - client.getState().setCredentials(AuthScope.ANY, credentials); + CloseableHttpClient client = getHttpClient(); - PostMethod request = new PostMethod(path); + HttpPost request = new HttpPost(path); // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html; section 14.10. // tells the server that we want it to close the connection when it has sent the response. // address large amount of close_wait sockets client and fin sockets server side - request.setRequestHeader("Connection", "close"); - request.setRequestHeader("X-Atlassian-Token", "no-check"); // xsrf + request.setHeader("Connection", "close"); + request.setHeader("X-Atlassian-Token", "no-check"); // xsrf if (comment != null) { ObjectNode node = mapper.getNodeFactory().objectNode(); node.put("text", comment); - - StringRequestEntity requestEntity = null; + StringEntity requestEntity = null; try { requestEntity = - new StringRequestEntity(mapper.writeValueAsString(node), "application/json", "UTF-8"); + new StringEntity(mapper.writeValueAsString(node), ContentType.APPLICATION_JSON); } catch (IOException e) { throw new StashApiException("Exception preparing POST request", e); } - request.setRequestEntity(requestEntity); + request.setEntity(requestEntity); } - client.getParams().setAuthenticationPreemptive(true); String response = ""; FutureTask httpTask = null; Thread thread; try { + request.addHeader(new BasicScheme().authenticate(credentials, request, null)); + // Run the HTTP request in a future task so we have the opportunity // to cancel it if it gets hung up; which is possible if stuck at // socket native layer. see issue JENKINS-30558 @@ -381,26 +368,26 @@ private String postRequest(String path, String comment) throws StashApiException new FutureTask( new Callable() { - private HttpClient client; - private PostMethod request; + private CloseableHttpClient client; + private HttpPost request; @Override - public String call() throws StashApiException, HttpException, IOException { + public String call() throws StashApiException, IOException { String response = ""; - int responseCode = HttpStatus.SC_INTERNAL_SERVER_ERROR; - - responseCode = client.executeMethod(request); + HttpResponse httpResponse = client.execute(request); + int responseCode = httpResponse.getStatusLine().getStatusCode(); if (!validResponseCode(responseCode)) { logger.log( Level.SEVERE, - "Failing to get response from Stash PR POST" + request.getPath()); + "Failing to get response from Stash PR POST" + request.getURI()); throw new StashApiException( "Didn't get a 200 response from Stash PR POST! Response; '" - + HttpStatus.getStatusText(responseCode) + + responseCode + "' with message; " - + response); + + httpResponse.getStatusLine().getReasonPhrase()); } - InputStream responseBodyAsStream = request.getResponseBodyAsStream(); + + InputStream responseBodyAsStream = httpResponse.getEntity().getContent(); StringWriter stringWriter = new StringWriter(); IOUtils.copy(responseBodyAsStream, stringWriter, "UTF-8"); response = stringWriter.toString(); @@ -409,7 +396,7 @@ public String call() throws StashApiException, HttpException, IOException { return response; } - public Callable init(HttpClient client, PostMethod request) { + public Callable init(CloseableHttpClient client, HttpPost request) { this.client = client; this.request = request; return this; @@ -422,7 +409,7 @@ public Callable init(HttpClient client, PostMethod request) { } catch (TimeoutException e) { request.abort(); throw new StashApiException("Timeout in POST request", e); - } catch (ExecutionException | InterruptedException e) { + } catch (AuthenticationException | ExecutionException | InterruptedException e) { throw new StashApiException("Exception in POST request", e); } finally { request.releaseConnection(); @@ -493,81 +480,6 @@ private String pullRequestsPath(int start) { return basePath.substring(0, basePath.length() - 1) + "?start=" + start; } - private static class EasySSLProtocolSocketFactory - extends stashpullrequestbuilder.stashpullrequestbuilder.repackage.org.apache.commons - .httpclient.contrib.ssl.EasySSLProtocolSocketFactory { - private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); - private SSLContext sslcontext = null; - - private static SSLContext createEasySSLContext() { - try { - TrustManager[] trustAllCerts = - new TrustManager[] { - new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] certs, String authType) {} - - public void checkServerTrusted(X509Certificate[] certs, String authType) {} - } - }; - - SSLContext context = SSLContext.getInstance("SSL"); - context.init(null, trustAllCerts, null); - return context; - } catch (KeyManagementException | NoSuchAlgorithmException e) { - LOG.error(e.getMessage(), e); - throw new HttpClientError(e.toString()); - } - } - - private SSLContext getSSLContext() { - if (this.sslcontext == null) { - this.sslcontext = createEasySSLContext(); - } - return this.sslcontext; - } - - public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) - throws IOException, UnknownHostException { - return this.getSSLContext() - .getSocketFactory() - .createSocket(host, port, clientHost, clientPort); - } - - public Socket createSocket( - String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) - throws IOException, UnknownHostException, ConnectTimeoutException { - if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); - } else { - int timeout = params.getConnectionTimeout(); - SSLSocketFactory socketfactory = this.getSSLContext().getSocketFactory(); - if (timeout == 0) { - return socketfactory.createSocket(host, port, localAddress, localPort); - } else { - Socket socket = socketfactory.createSocket(); - InetSocketAddress localaddr = new InetSocketAddress(localAddress, localPort); - InetSocketAddress remoteaddr = new InetSocketAddress(host, port); - socket.bind(localaddr); - socket.connect(remoteaddr, timeout); - return socket; - } - } - } - - public Socket createSocket(String host, int port) throws IOException { - return this.getSSLContext().getSocketFactory().createSocket(host, port); - } - - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) - throws IOException { - return this.getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); - } - } - /** * Indicates an error during interaction with the Bitbucket Server * diff --git a/src/test/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClientTest.java b/src/test/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClientTest.java index 567e75ee..81eb10ff 100644 --- a/src/test/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClientTest.java +++ b/src/test/java/stashpullrequestbuilder/stashpullrequestbuilder/stash/StashApiClientTest.java @@ -25,7 +25,6 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import com.fasterxml.jackson.core.JsonParseException; import com.github.tomakehurst.wiremock.client.BasicCredentials; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; import com.github.tomakehurst.wiremock.http.Fault; @@ -41,7 +40,6 @@ /* * Known issues: * - * Some calls ignore HTTP errors, especially "malformed response" * deletePullRequestComment() gives no indication whether the call has succeeded * mergePullRequest() throws on 409 Conflict instead of returning false as apparently intended * There are no checks whether the HTTP code indicates an error for the specific request @@ -159,8 +157,8 @@ public void getPullRequests_throws_on_malformed_response() throws Exception { stubFor(any(anyUrl()).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); expectedException.expect(StashApiException.class); - expectedException.expectMessage(containsString("Cannot read list of pull requests")); - expectedException.expectCause(is(instanceOf(JsonParseException.class))); + expectedException.expectMessage(containsString("Exception in GET request")); + expectedException.expectCause(is(instanceOf(ExecutionException.class))); client.getPullRequests(); } @@ -221,8 +219,8 @@ public void getPullRequestComments_throws_on_malformed_response() throws Excepti stubFor(any(anyUrl()).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); expectedException.expect(StashApiException.class); - expectedException.expectMessage(containsString("cannot read comments for pull request")); - expectedException.expectCause(is(instanceOf(JsonParseException.class))); + expectedException.expectMessage(containsString("Exception in GET request")); + expectedException.expectCause(is(instanceOf(ExecutionException.class))); client.getPullRequestComments(projectName, repositoryName, pullRequestId); } @@ -253,9 +251,13 @@ public void deletePullRequestComment_doesnt_throw_on_not_found() throws Exceptio } @Test - public void deletePullRequestComment_doesnt_throw_on_malformed_response() throws Exception { + public void deletePullRequestComment_throws_on_malformed_response() throws Exception { stubFor(any(anyUrl()).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); + expectedException.expect(StashApiException.class); + expectedException.expectMessage(containsString("Exception in DELETE request")); + expectedException.expectCause(is(instanceOf(ExecutionException.class))); + client.deletePullRequestComment(pullRequestId, commentId); } @@ -317,8 +319,8 @@ public void postPullRequestComment_throws_on_malformed_response() throws Excepti stubFor(any(anyUrl()).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); expectedException.expect(StashApiException.class); - expectedException.expectMessage(containsString("Cannot parse reply after comment posting")); - expectedException.expectCause(is(instanceOf(JsonParseException.class))); + expectedException.expectMessage(containsString("Exception in POST request")); + expectedException.expectCause(is(instanceOf(ExecutionException.class))); client.postPullRequestComment(pullRequestId, "Some comment"); } @@ -362,8 +364,8 @@ public void getPullRequestMergeStatus_throws_on_malformed_response() throws Exce stubFor(any(anyUrl()).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); expectedException.expect(StashApiException.class); - expectedException.expectMessage(containsString("Cannot parse merge status")); - expectedException.expectCause(is(instanceOf(JsonParseException.class))); + expectedException.expectMessage(containsString("Exception in GET request")); + expectedException.expectCause(is(instanceOf(ExecutionException.class))); client.getPullRequestMergeStatus(pullRequestId); } @@ -428,9 +430,13 @@ public void mergePullRequest_throws_on_not_found() throws Exception { } @Test - public void mergePullRequest_doesnt_throw_on_malformed_response() throws Exception { + public void mergePullRequest_throws_on_malformed_response() throws Exception { stubFor(any(anyUrl()).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); + expectedException.expect(StashApiException.class); + expectedException.expectMessage(containsString("Exception in POST request")); + expectedException.expectCause(is(instanceOf(ExecutionException.class))); + client.mergePullRequest(pullRequestId, mergeVersion); }