Java tutorial
/* * The MIT License * * Copyright 2017 Intuit Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.intuit.karate.http.apache; import org.apache.http.conn.ssl.LenientSslConnectionSocketFactory; import com.intuit.karate.ScriptValue; import static com.intuit.karate.http.Cookie.*; import com.intuit.karate.http.HttpClient; import com.intuit.karate.http.HttpConfig; import com.intuit.karate.http.HttpResponse; import com.intuit.karate.http.HttpUtils; import com.intuit.karate.http.MultiPartItem; import com.intuit.karate.http.MultiValuedMap; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import javax.net.ssl.SSLContext; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.NameValuePair; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CookieStore; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.cookie.Cookie; import org.apache.http.entity.ContentType; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.FormBodyPartBuilder; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.ContentBody; import org.apache.http.entity.mime.content.InputStreamBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.BasicHttpContext; /** * * @author pthomas3 */ public class ApacheHttpClient extends HttpClient<HttpEntity> { public static final String URI_CONTEXT_KEY = ApacheHttpClient.class.getName() + ".URI"; private HttpClientBuilder clientBuilder; private URIBuilder uriBuilder; private RequestBuilder requestBuilder; private CookieStore cookieStore; private void build() { try { URI uri = uriBuilder.build(); String method = request.getMethod(); requestBuilder = RequestBuilder.create(method).setUri(uri); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void configure(HttpConfig config) { clientBuilder = HttpClientBuilder.create(); cookieStore = new BasicCookieStore(); clientBuilder.setDefaultCookieStore(cookieStore); AtomicInteger counter = new AtomicInteger(); clientBuilder.addInterceptorLast(new RequestLoggingInterceptor(counter)); clientBuilder.addInterceptorLast(new ResponseLoggingInterceptor(counter)); if (config.isSslEnabled()) { // System.setProperty("jsse.enableSNIExtension", "false"); String sslAlgorithm = config.getSslAlgorithm(); logger.info("ssl enabled, initializing generic trusted certificate / key-store with algorithm: {}", sslAlgorithm); SSLContext sslContext = HttpUtils.getSslContext(sslAlgorithm); SSLConnectionSocketFactory socketFactory = new LenientSslConnectionSocketFactory(sslContext, new NoopHostnameVerifier()); clientBuilder.setSSLSocketFactory(socketFactory); } RequestConfig.Builder configBuilder = RequestConfig.custom().setConnectTimeout(config.getConnectTimeout()) .setSocketTimeout(config.getReadTimeout()); clientBuilder.setDefaultRequestConfig(configBuilder.build()); if (config.getProxyUri() != null) { try { URI proxyUri = new URIBuilder(config.getProxyUri()).build(); clientBuilder.setProxy(new HttpHost(proxyUri.getHost(), proxyUri.getPort(), proxyUri.getScheme())); if (config.getProxyUsername() != null && config.getProxyPassword() != null) { CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(new AuthScope(proxyUri.getHost(), proxyUri.getPort()), new UsernamePasswordCredentials(config.getProxyUsername(), config.getProxyPassword())); clientBuilder.setDefaultCredentialsProvider(credsProvider); } } catch (Exception e) { throw new RuntimeException(e); } } } @Override protected void buildUrl(String url) { try { uriBuilder = new URIBuilder(url); build(); } catch (Exception e) { throw new RuntimeException(e); } } @Override protected void buildPath(String path) { String temp = uriBuilder.getPath(); if (!temp.endsWith("/")) { temp = temp + "/"; } if (path.startsWith("/")) { path = path.substring(1); } uriBuilder.setPath(temp + path); build(); } @Override protected void buildParam(String name, Object... values) { for (Object o : values) { uriBuilder.setParameter(name, o == null ? "" : o.toString()); } build(); } @Override protected void buildHeader(String name, Object value, boolean replace) { if (replace) { requestBuilder.removeHeaders(name); } requestBuilder.addHeader(name, value == null ? null : value.toString()); } @Override protected void buildCookie(com.intuit.karate.http.Cookie c) { BasicClientCookie cookie = new BasicClientCookie(c.getName(), c.getValue()); for (Entry<String, String> entry : c.entrySet()) { switch (entry.getKey()) { case DOMAIN: cookie.setDomain(entry.getValue()); break; case PATH: cookie.setPath(entry.getValue()); break; } } if (cookie.getDomain() == null) { cookie.setDomain(uriBuilder.getHost()); } cookieStore.addCookie(cookie); } @Override protected HttpEntity getEntity(List<MultiPartItem> items, String mediaType) { boolean hasNullName = false; for (MultiPartItem item : items) { if (item.getName() == null) { hasNullName = true; break; } } if (hasNullName) { // multipart/related String boundary = createBoundary(); String text = getAsStringEntity(items, boundary); ContentType ct = ContentType.create(mediaType) .withParameters(new BasicNameValuePair("boundary", boundary)); return new StringEntity(text, ct); } else { MultipartEntityBuilder builder = MultipartEntityBuilder.create() .setContentType(ContentType.create(mediaType)); for (MultiPartItem item : items) { if (item.getValue() == null || item.getValue().isNull()) { logger.warn("ignoring null multipart value for key: {}", item.getName()); continue; } String name = item.getName(); ScriptValue sv = item.getValue(); if (name == null) { // builder.addPart(bodyPart); } else { FormBodyPartBuilder formBuilder = FormBodyPartBuilder.create().setName(name); ContentBody contentBody; switch (sv.getType()) { case INPUT_STREAM: InputStream is = (InputStream) sv.getValue(); contentBody = new InputStreamBody(is, ContentType.APPLICATION_OCTET_STREAM, name); break; case XML: contentBody = new StringBody(sv.getAsString(), ContentType.APPLICATION_XML); break; case JSON: contentBody = new StringBody(sv.getAsString(), ContentType.APPLICATION_JSON); break; default: contentBody = new StringBody(sv.getAsString(), ContentType.TEXT_PLAIN); } formBuilder = formBuilder.setBody(contentBody); builder = builder.addPart(formBuilder.build()); } } return builder.build(); } } @Override protected HttpEntity getEntity(MultiValuedMap fields, String mediaType) { List<NameValuePair> list = new ArrayList<>(fields.size()); for (Entry<String, List> entry : fields.entrySet()) { String stringValue; List values = entry.getValue(); if (values == null) { stringValue = null; } else if (values.size() == 1) { Object value = values.get(0); if (value == null) { stringValue = null; } else if (value instanceof String) { stringValue = (String) value; } else { stringValue = value.toString(); } } else { stringValue = StringUtils.join(values, ','); } list.add(new BasicNameValuePair(entry.getKey(), stringValue)); } try { UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list); entity.setContentType(mediaType); return entity; } catch (Exception e) { throw new RuntimeException(e); } } @Override protected HttpEntity getEntity(String value, String mediaType) { return new StringEntity(value, ContentType.create(mediaType)); } @Override protected HttpEntity getEntity(InputStream value, String mediaType) { return new InputStreamEntity(value, ContentType.create(mediaType)); } @Override protected HttpResponse makeHttpRequest(HttpEntity entity, long startTime) { if (entity != null) { requestBuilder.setEntity(entity); requestBuilder.setHeader(entity.getContentType()); } HttpUriRequest httpRequest = requestBuilder.build(); CloseableHttpClient client = clientBuilder.build(); BasicHttpContext context = new BasicHttpContext(); context.setAttribute(URI_CONTEXT_KEY, getRequestUri()); CloseableHttpResponse httpResponse; byte[] bytes; try { httpResponse = client.execute(httpRequest, context); HttpEntity responseEntity = httpResponse.getEntity(); InputStream is = responseEntity.getContent(); bytes = IOUtils.toByteArray(is); } catch (Exception e) { throw new RuntimeException(e); } long responseTime = getResponseTime(startTime); HttpResponse response = new HttpResponse(); response.setTime(responseTime); response.setUri(getRequestUri()); response.setBody(bytes); response.setStatus(httpResponse.getStatusLine().getStatusCode()); for (Cookie c : cookieStore.getCookies()) { com.intuit.karate.http.Cookie cookie = new com.intuit.karate.http.Cookie(c.getName(), c.getValue()); cookie.put(DOMAIN, c.getDomain()); cookie.put(PATH, c.getPath()); if (c.getExpiryDate() != null) { cookie.put(EXPIRES, c.getExpiryDate().getTime() + ""); } cookie.put(PERSISTENT, c.isPersistent() + ""); cookie.put(SECURE, c.isSecure() + ""); response.addCookie(cookie); } for (Header header : httpResponse.getAllHeaders()) { response.addHeader(header.getName(), header.getValue()); } return response; } @Override protected String getRequestUri() { return requestBuilder.getUri().toString(); } private static final AtomicInteger BOUNDARY_COUNTER = new AtomicInteger(); public static String createBoundary() { ; StringBuilder sb = new StringBuilder("boundary_"); sb.append(BOUNDARY_COUNTER.incrementAndGet()).append('_'); sb.append(System.currentTimeMillis()); return sb.toString(); } private static String getContentType(ScriptValue sv) { switch (sv.getType()) { case JSON: return APPLICATION_JSON; case XML: return APPLICATION_XML; case INPUT_STREAM: return APPLICATION_OCTET_STREAM; default: return TEXT_PLAIN; } } private static String getAsStringEntity(List<MultiPartItem> items, String boundary) { StringBuilder sb = new StringBuilder(); boolean firstItem = true; for (MultiPartItem item : items) { if (firstItem) { firstItem = false; sb.append("--"); } else { sb.append("\r\n--"); } sb.append(boundary); sb.append("\r\n"); ScriptValue sv = item.getValue(); String contentType = getContentType(sv); sb.append("Content-Type: ").append(contentType); sb.append("\r\n"); String name = item.getName(); if (name != null) { sb.append("Content-Disposition: form-data"); if (sv.getType() == ScriptValue.Type.INPUT_STREAM) { sb.append("; filename=\"").append(name).append("\""); } sb.append("; name=\"").append(name).append("\""); sb.append("\r\n"); } sb.append("\r\n"); if (sv.getType() == ScriptValue.Type.INPUT_STREAM) { InputStream is = sv.getValue(InputStream.class); try { byte[] bytes = IOUtils.toByteArray(is); sb.append(new String(bytes, "utf-8")); } catch (Exception e) { throw new RuntimeException(e); } } else { sb.append(sv.getAsString()); } } sb.append("\r\n--"); sb.append(boundary); sb.append("--\r\n"); return sb.toString(); } }