package com.intuit.tank.http;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.MultipartStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.intuit.tank.http.binary.BinaryResponse;
import com.intuit.tank.http.json.JsonResponse;
import com.intuit.tank.http.xml.XMLResponse;
/**
* utitly methods for tank http clients
* @author denisa
*
*/
public class TankHttpUtil {
private static Logger LOG = LogManager.getLogger(TankHttpUtil.class);
public static URL buildUrl(String protocol, String host, int port, String path, Map<String, String> urlVariables) {
try {
// no default port specified for http
if (protocol.equalsIgnoreCase("http") && port == -1) {
return new URL(protocol, host, path + getQueryString(urlVariables));
} else if (protocol.equalsIgnoreCase("https") && port == -1) {
return new URL(protocol, host, path + getQueryString(urlVariables));
}
// ensure that port 80 and 8080 requests use http and not https
if (port == 80 || port == 8080) {
protocol = "http";
}
return new URL(protocol, host, port, path + getQueryString(urlVariables));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static String getQueryString(Map<String, String> urlVariables) {
StringBuilder queryString = new StringBuilder();
// Set the query string
if (urlVariables != null) {
if (!urlVariables.isEmpty()) {
queryString.append("?");
// Set<Map.Entry<String, String>> set = urlVariables.entrySet();
// Iterator<Map.Entry<String, String>> iterator =
// set.iterator();
for (Entry<String, String> entry : urlVariables.entrySet()) {
try {
StringBuilder nvp = new StringBuilder();
nvp.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
if (entry.getValue() != null) {
nvp.append("=");
nvp.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
nvp.append("&");
queryString.append(nvp.toString());
} catch (Exception ex) {
LOG.warn("Unable to set query string value: " + ex.getMessage());
}
}
}
}
// Remove the last &
String reqQueryString = "";
if (queryString.length() > 0) {
if (queryString.charAt(queryString.length() - 1) == '&')
reqQueryString = queryString.deleteCharAt(queryString.length() - 1).toString();
else
reqQueryString = queryString.toString();
}
return reqQueryString;
}
/**
* New up a response object depending on the content type
*
* @return
*/
public static BaseResponse newResponseObject(String contentTypeHeader) {
String contentType = StringUtils.isNotBlank(contentTypeHeader) ? contentTypeHeader : "";
if (contentType.contains("xml")) {
return new XMLResponse();
} else if (contentType.contains("json")) {
return new JsonResponse();
} else {
return new BinaryResponse();
}
}
public static List<PartHolder> getPartsFromBody(BaseRequest request) {
List<PartHolder> parameters = new ArrayList<PartHolder>();
String s = new String(Base64.decodeBase64(request.getBody()));
if (StringUtils.isNotBlank(s)) {
String boundary = StringUtils.substringBefore(s, "\r\n").substring(2);
request.setBody(s);
try {
@SuppressWarnings("deprecation")
MultipartStream multipartStream = new MultipartStream(new ByteArrayInputStream(s.getBytes()), boundary.getBytes());
boolean nextPart = multipartStream.skipPreamble();
while (nextPart) {
String header = multipartStream.readHeaders();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
multipartStream.readBodyData(bos);
PartHolder p = new PartHolder(bos.toByteArray(), header);
parameters.add(p);
nextPart = multipartStream.readBoundary();
}
} catch (Exception e) {
LOG.error(e.toString(), e);
// a read or write error occurred
}
}
return parameters;
}
public static class PartHolder {
private byte[] body;
private String header;
private Map<String, String> headerMap = new HashMap<String, String>();
private Map<String, String> dispositionMap = new HashMap<String, String>();
public PartHolder(byte[] body, String header) {
super();
this.body = body;
this.header = header;
String[] headers = StringUtils.splitByWholeSeparator(this.header, "\r\n");
for (String s : headers) {
if (StringUtils.isNotBlank(s) && s.indexOf(':') != -1) {
String key = StringUtils.substringBefore(s, ":").trim();
String value = StringUtils.substringAfter(s, ":").trim();
headerMap.put(key, value);
}
}
String[] dispositions = StringUtils.split(getContentDisposition(), ';');
for (String s : dispositions) {
if (StringUtils.isNotBlank(s) && s.indexOf('=') != -1) {
String key = removeQuotes(StringUtils.substringBefore(s, "=").trim());
String value = removeQuotes(StringUtils.substringAfter(s, "=").trim());
dispositionMap.put(key, value);
}
}
}
/**
* @return the body
*/
public byte[] getBody() {
return body;
}
/**
* @return the body as a string
*/
public String getBodyAsString() {
return new String(body, Charset.forName("UTF-8"));
}
// Content-Disposition: form-data; name="uploadname1";
// filename="diamond-sword.png"
public String getPartName() {
return dispositionMap.get("name");
}
// Content-Disposition: form-data; name="uploadname1";
// filename="diamond-sword.png"
public String getFileName() {
return dispositionMap.get("filename");
}
// Content-Disposition: form-data; name="uploadname1";
// filename="diamond-sword.png"
public String getContentType() {
String ct = headerMap.get("Content-Type");
if (ct == null) {
ct = "text/plain";
}
return ct;
}
// Content-Disposition: form-data; name="uploadname1";
// filename="diamond-sword.png"
public String getContentDisposition() {
String ct = headerMap.get("Content-Disposition");
if (ct == null) {
ct = "form-data";
}
return ct;
}
/**
*
* @return
*/
public boolean isContentTypeSet() {
return headerMap.get("Content-Type") != null;
}
/**
*
* @param s
* @return
*/
private String removeQuotes(String s) {
s = StringUtils.removeEnd(s, "\"");
s = StringUtils.removeStart(s, "\"");
return s;
}
}
}