/* * Copyright (C) 2011 JFrog Ltd. * * 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 org.jfrog.build.client; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; import org.apache.commons.codec.net.URLCodec; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.util.EntityUtils; import org.jfrog.build.api.util.Log; import org.jfrog.build.util.URI; import java.io.IOException; import java.io.InputStream; /** * @author Noam Y. Tenne */ public class ArtifactoryHttpClient { public static final ArtifactoryVersion UNKNOWN_PROPERTIES_TOLERANT_ARTIFACTORY_VERSION = new ArtifactoryVersion("2.2.3"); public static final ArtifactoryVersion NON_NUMERIC_BUILD_NUMBERS_TOLERANT_ARTIFACTORY_VERSION = new ArtifactoryVersion("2.2.4"); public static final ArtifactoryVersion STANDALONE_BUILD_RETENTION_SUPPORTED_ARTIFACTORY_VERSION = new ArtifactoryVersion("5.2.1"); public static final ArtifactoryVersion MINIMAL_ARTIFACTORY_VERSION = new ArtifactoryVersion("2.2.3"); public static final String VERSION_INFO_URL = "/api/system/version"; private static final int DEFAULT_CONNECTION_TIMEOUT_SECS = 300; // 5 Minutes in seconds public static final int DEFAULT_CONNECTION_RETRY = 3; private final Log log; private final String artifactoryUrl; private final String username; private final String password; private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT_SECS; private int connectionRetries = DEFAULT_CONNECTION_RETRY; private ProxyConfiguration proxyConfiguration; private PreemptiveHttpClient deployClient; public ArtifactoryHttpClient(String artifactoryUrl, String username, String password, Log log) { this.artifactoryUrl = StringUtils.stripEnd(artifactoryUrl, "/"); this.username = username; this.password = password; this.log = log; } public static String encodeUrl(String unescaped) { byte[] rawdata = URLCodec.encodeUrl(URI.allowed_query, org.apache.commons.codec.binary.StringUtils.getBytesUtf8(unescaped)); return org.apache.commons.codec.binary.StringUtils.newStringUsAscii(rawdata); } /** * Sets the proxy host and port. * * @param host Proxy host * @param port Proxy port */ public void setProxyConfiguration(String host, int port) { setProxyConfiguration(host, port, null, null); } /** * Sets the proxy details. * * @param host Proxy host * @param port Proxy port * @param username Username to authenticate with the proxy * @param password Password to authenticate with the proxy */ public void setProxyConfiguration(String host, int port, String username, String password) { proxyConfiguration = new ProxyConfiguration(); proxyConfiguration.host = host; proxyConfiguration.port = port; proxyConfiguration.username = username; proxyConfiguration.password = password; } /** * Network timeout in seconds to use both for connection establishment and for unanswered requests. * * @param connectionTimeout Timeout in seconds. */ public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } /** * Max Retries to perform * * @param connectionRetries The number of max retries. */ public void setConnectionRetries(int connectionRetries){ this.connectionRetries = connectionRetries; } public int getConnectionRetries() { return connectionRetries; } /** * Release all connection and cleanup resources. */ public void close() { if (deployClient != null) { deployClient.close(); } } public PreemptiveHttpClient getHttpClient() { return getHttpClient(connectionTimeout); } public PreemptiveHttpClient getHttpClient(int connectionTimeout) { if (deployClient == null) { deployClient = new PreemptiveHttpClient(username, password, connectionTimeout, proxyConfiguration, connectionRetries); deployClient.setLog(log); } return deployClient; } public ArtifactoryVersion getVersion() throws IOException { String versionUrl = artifactoryUrl + VERSION_INFO_URL; PreemptiveHttpClient client = getHttpClient(); HttpGet httpGet = new HttpGet(versionUrl); HttpResponse response = client.execute(httpGet); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_NOT_FOUND) { HttpEntity httpEntity = response.getEntity(); if (httpEntity != null) { EntityUtils.consume(httpEntity); } return ArtifactoryVersion.NOT_FOUND; } if (statusCode != HttpStatus.SC_OK) { if (response.getEntity() != null) { EntityUtils.consume(response.getEntity()); } throw new IOException(response.getStatusLine().getReasonPhrase()); } HttpEntity httpEntity = response.getEntity(); if (httpEntity != null) { InputStream content = httpEntity.getContent(); JsonParser parser; try { parser = createJsonParser(content); EntityUtils.consume(httpEntity); JsonNode result = parser.readValueAsTree(); log.debug("Version result: " + result); String version = result.get("version").asText(); JsonNode addonsNode = result.get("addons"); boolean hasAddons = (addonsNode != null) && addonsNode.iterator().hasNext(); return new ArtifactoryVersion(version, hasAddons); } finally { if (content != null) { content.close(); } } } return ArtifactoryVersion.NOT_FOUND; } public JsonParser createJsonParser(InputStream in) throws IOException { JsonFactory jsonFactory = createJsonFactory(); return jsonFactory.createJsonParser(in); } public JsonParser createJsonParser(String content) throws IOException { JsonFactory jsonFactory = createJsonFactory(); return jsonFactory.createJsonParser(content); } public JsonFactory createJsonFactory() { JsonFactory jsonFactory = new JsonFactory(); ObjectMapper mapper = new ObjectMapper(jsonFactory); mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector()); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); jsonFactory.setCodec(mapper); return jsonFactory; } public ArtifactoryUploadResponse upload(HttpPut httpPut, HttpEntity fileEntity) throws IOException { httpPut.setEntity(fileEntity); return execute(httpPut); } public ArtifactoryUploadResponse execute(HttpPut httpPut) throws IOException { HttpResponse response = getHttpClient().execute(httpPut); ArtifactoryUploadResponse artifactoryResponse = null; StatusLine statusLine = response.getStatusLine(); HttpEntity entity = response.getEntity(); if (entity != null) { InputStream in = entity.getContent(); if (in != null) { String content = IOUtils.toString(in, "UTF-8"); try { JsonParser parser = createJsonParser(content); artifactoryResponse = parser.readValueAs(ArtifactoryUploadResponse.class); } catch (Exception e) { // Displays the response received from the client and the stacktrace in case an Exception caught. log.info("Response received: \n\n" + content + "\n\n"); log.error("Failed while reading the response from: " + httpPut, e); } finally { in.close(); } } } if (artifactoryResponse == null) { artifactoryResponse = new ArtifactoryUploadResponse(); } artifactoryResponse.setStatusLine(statusLine); return artifactoryResponse; } }