package io.craft.atom.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* A http utility class that sends http request and parse response.
*
* @author mindwind
* @version 1.0, 2011-10-18
*/
public class HttpUtil {
public static final String DEFAULT_CHARSET = "UTF-8" ;
public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded;charset=";
private static final Map<String, String> DEFAULT_HEADER = new HashMap<String, String>() ;
static {
DEFAULT_HEADER.put("User-Agent", "http-util");
DEFAULT_HEADER.put("Accept", "text/xml,text/javascript,text/html");
}
/**
* Build http query string.
*
* @param params
* @param charset
* @return http query string
* @throws UnsupportedEncodingException
*/
public static String buildQuery(Map<String, String> params, String charset) throws UnsupportedEncodingException {
if (params == null || params.isEmpty()) { return null; }
StringBuilder query = new StringBuilder();
Set<Entry<String, String>> entries = params.entrySet();
boolean hasParam = false;
for (Entry<String, String> entry : entries) {
String name = entry.getKey();
String value = entry.getValue();
if (StringUtil.isAllNotEmpty(name, value)) {
if (hasParam) {
query.append("&");
} else {
hasParam = true;
}
query.append(name).append("=").append(URLEncoder.encode(value, charset));
}
}
return query.toString();
}
/**
* Execute http post request, using query string as post content with
* default charset(UTF-8).
*
* @param url
* @param params
* @param connectTimeout
* an int that specifies the connect timeout value in milliseconds
* @param readTimeout
* an int that specifies the read timeout value in milliseconds
* @return post response
* @throws Exception
*/
public static String doPost(String url, Map<String, String> params, int connectTimeout, int readTimeout) throws Exception {
return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
}
/**
* Execute http post request, using query string as post content with
* dedicated charset.
*
* @param url
* @param params
* @param charset
* @param connectTimeout
* an int that specifies the connect timeout value in milliseconds
* @param readTimeout
* an int that specifies the read timeout value in milliseconds
* @return post response
* @throws Exception
*/
public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout) throws Exception {
String ctype = DEFAULT_CONTENT_TYPE + charset;
String query = buildQuery(params, charset);
byte[] content = {};
if (query != null) {
content = query.getBytes(charset);
}
return doPost(url, ctype, content, DEFAULT_HEADER, connectTimeout, readTimeout);
}
/**
* Execute http post request, use dedicated content and content type with
* dedicated header.
*
* @param url
* @param contentType
* @param content
* @param connectTimeout
* an int that specifies the connect timeout value in milliseconds
* @param readTimeout
* an int that specifies the read timeout value in milliseconds
* @param header
* @return post response
* @throws IOException
*/
public static String doPost(String url, String contentType, byte[] content, Map<String, String> header, int connectTimeout, int readTimeout) throws IOException {
HttpURLConnection conn = null;
OutputStream out = null;
String rsp = null;
try {
conn = getConnection(new URL(url), "POST", contentType, header);
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
out = conn.getOutputStream();
out.write(content);
rsp = getResponseAsString(conn);
} finally {
if (out != null) {
out.close();
}
if (conn != null) {
conn.disconnect();
}
}
return rsp;
}
private static HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> header) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", ctype);
if (header != null) {
for (Map.Entry<String, String> entry : header.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
return conn;
}
private static String getResponseAsString(HttpURLConnection conn) throws IOException {
String charset = getResponseCharset(conn.getContentType());
InputStream es = conn.getErrorStream();
if (es == null) {
return getStreamAsString(conn.getInputStream(), charset);
} else {
String msg = getStreamAsString(es, charset);
if (StringUtil.isEmpty(msg)) {
throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());
} else {
throw new IOException(msg);
}
}
}
private static String getResponseCharset(String ctype) {
String charset = DEFAULT_CHARSET;
if (!StringUtil.isEmpty(ctype)) {
String[] params = ctype.split(";");
for (String param : params) {
param = param.trim();
if (param.startsWith("charset")) {
String[] pair = param.split("=", 2);
if (pair.length == 2 && !StringUtil.isEmpty(pair[1])) {
charset = pair[1].trim();
}
break;
}
}
}
return charset;
}
private static String getStreamAsString(InputStream stream, String charset) throws IOException {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, charset));
StringWriter writer = new StringWriter();
char[] chars = new char[256];
int count = 0;
while ((count = reader.read(chars)) > 0) {
writer.write(chars, 0, count);
}
return writer.toString();
} finally {
if (stream != null) {
stream.close();
}
}
}
private HttpUtil() {
throw new UnsupportedOperationException();
}
}