package com.zenip.weibo.sdk.android.net;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
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.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import android.text.TextUtils;
import com.weibo.sdk.android.WeiboException;
import com.weibo.sdk.android.WeiboParameters;
import com.zenip.weibo.sdk.android.util.Utility;
/**
* @author luopeng (luopeng@staff.sina.com.cn)
*/
public class HttpManager {
// private static final String BOUNDARY = "7cd4a6d158c";
private static final String BOUNDARY = getBoundry();
private static final String MP_BOUNDARY = "--" + BOUNDARY;
private static final String END_MP_BOUNDARY = "--" + BOUNDARY + "--";
private static final String MULTIPART_FORM_DATA = "multipart/form-data";
private static final String HTTPMETHOD_POST = "POST";
public static final String HTTPMETHOD_GET = "GET";
private static final int SET_CONNECTION_TIMEOUT = 5 * 1000;
private static final int SET_SOCKET_TIMEOUT = 20 * 1000;
private static ConnectionKeepAliveStrategy sKeeyAliveStrategy = new ConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse response,
HttpContext context) {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && "timeout".equalsIgnoreCase(param)) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException ignore) {
}
}
}
HttpHost target = (HttpHost) context
.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName())) {
// Keep alive for 5 seconds only
return 5 * 1000;
} else {
// otherwise keep alive for 30 seconds
return 30 * 1000;
}
}
};
/**
* @param url
* 服务器地址
* @param method
* "GET"or “POST”
* @param params
* 存放参数的容器
* @param file
* 文件路径,如果 是发送带有照片的微博的话,此参数为图片在sdcard里的绝对路径
* @return 响应结果
* @throws WeiboException
*/
public static String openUrl(String url, String method,
WeiboParameters params, String file) throws WeiboException {
String result = "";
try {
HttpClient client = getNewHttpClient();
HttpUriRequest request = null;
ByteArrayOutputStream bos = null;
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
NetStateManager.getAPN());
if (method.equals(HTTPMETHOD_GET)) {
url = url + "?" + Utility.encodeUrl(params);
HttpGet get = new HttpGet(url);
request = get;
} else if (method.equals(HTTPMETHOD_POST)) {
HttpPost post = new HttpPost(url);
request = post;
byte[] data = null;
String _contentType = params.getValue("content-type");
bos = new ByteArrayOutputStream();
if (!TextUtils.isEmpty(file)) {
paramToUpload(bos, params);
post.setHeader("Content-Type", MULTIPART_FORM_DATA
+ "; boundary=" + BOUNDARY);
Utility.UploadImageUtils.revitionPostImageSize(file);
imageContentToUpload(bos, file);
} else {
if (_contentType != null) {
params.remove("content-type");
post.setHeader("Content-Type", _contentType);
} else {
post.setHeader("Content-Type",
"application/x-www-form-urlencoded");
}
String postParam = Utility.encodeParameters(params);
data = postParam.getBytes("UTF-8");
bos.write(data);
}
data = bos.toByteArray();
bos.close();
ByteArrayEntity formEntity = new ByteArrayEntity(data);
post.setEntity(formEntity);
} else if (method.equals("DELETE")) {
request = new HttpDelete(url);
}
HttpResponse response = client.execute(request);
StatusLine status = response.getStatusLine();
int statusCode = status.getStatusCode();
if (statusCode != 200) {
result = readHttpResponse(response);
throw new WeiboException(result, statusCode);
}
result = readHttpResponse(response);
return result;
} catch (IOException e) {
throw new WeiboException(e);
}
}
private static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(
params, registry);
HttpConnectionParams.setConnectionTimeout(params,
SET_CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, SET_SOCKET_TIMEOUT);
DefaultHttpClient client = new DefaultHttpClient(ccm, params);
client.setKeepAliveStrategy(sKeeyAliveStrategy);
// workAroundReverseDnsBugInHoneycombAndEarlier(client);
// if (NetState.Mobile == NetStateManager.CUR_NETSTATE) {
// // 获取当前正在使用的APN接入点
// HttpHost proxy = NetStateManager.getAPN();
// if (null != proxy) {
// client.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY,
// proxy);
// }
// }
return client;
} catch (Exception e) {
return new DefaultHttpClient();
}
}
private static void workAroundReverseDnsBugInHoneycombAndEarlier(
HttpClient client) {
// Android had a bug where HTTPS made reverse DNS lookups (fixed in Ice
// Cream Sandwich)
// http://code.google.com/p/android/issues/detail?id=13117
SocketFactory socketFactory = new LayeredSocketFactory() {
SSLSocketFactory delegate = SSLSocketFactory.getSocketFactory();
@Override
public Socket createSocket() throws IOException {
return delegate.createSocket();
}
@Override
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException {
return delegate.connectSocket(sock, host, port, localAddress,
localPort, params);
}
@Override
public boolean isSecure(Socket sock)
throws IllegalArgumentException {
return delegate.isSecure(sock);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException {
injectHostname(socket, host);
return delegate.createSocket(socket, host, port, autoClose);
}
private void injectHostname(Socket socket, String host) {
try {
Field field = InetAddress.class
.getDeclaredField("hostName");
field.setAccessible(true);
field.set(socket.getInetAddress(), host);
} catch (Exception ignored) {
}
}
};
client.getConnectionManager().getSchemeRegistry()
.register(new Scheme("https", socketFactory, 443));
}
private static class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
injectHostname(socket, host);
return sslContext.getSocketFactory().createSocket(socket, host,
port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
private void injectHostname(Socket socket, String host) {
try {
Field field = InetAddress.class.getDeclaredField("hostName");
field.setAccessible(true);
field.set(socket.getInetAddress(), host);
} catch (Exception ignored) {
}
}
}
private static void paramToUpload(OutputStream baos, WeiboParameters params)
throws WeiboException {
String key = "";
for (int loc = 0; loc < params.size(); loc++) {
key = params.getKey(loc);
StringBuilder temp = new StringBuilder(10);
temp.setLength(0);
temp.append(MP_BOUNDARY).append("\r\n");
temp.append("content-disposition: form-data; name=\"").append(key)
.append("\"\r\n\r\n");
temp.append(params.getValue(key)).append("\r\n");
byte[] res = temp.toString().getBytes();
try {
baos.write(res);
} catch (IOException e) {
throw new WeiboException(e);
}
}
}
private static void imageContentToUpload(OutputStream out, String imgpath)
throws WeiboException {
if (imgpath == null) {
return;
}
StringBuilder temp = new StringBuilder();
temp.append(MP_BOUNDARY).append("\r\n");
temp.append("Content-Disposition: form-data; name=\"pic\"; filename=\"")
.append("news_image").append("\"\r\n");
String filetype = "image/png";
temp.append("Content-Type: ").append(filetype).append("\r\n\r\n");
byte[] res = temp.toString().getBytes();
FileInputStream input = null;
try {
out.write(res);
input = new FileInputStream(imgpath);
byte[] buffer = new byte[1024 * 50];
while (true) {
int count = input.read(buffer);
if (count == -1) {
break;
}
out.write(buffer, 0, count);
}
out.write("\r\n".getBytes());
out.write(("\r\n" + END_MP_BOUNDARY).getBytes());
} catch (IOException e) {
throw new WeiboException(e);
} finally {
if (null != input) {
try {
input.close();
} catch (IOException e) {
throw new WeiboException(e);
}
}
}
}
/**
* 读取HttpResponse数据
*
* @param response
* @return
*/
private static String readHttpResponse(HttpResponse response) {
String result = "";
HttpEntity entity = response.getEntity();
InputStream inputStream;
try {
inputStream = entity.getContent();
ByteArrayOutputStream content = new ByteArrayOutputStream();
Header header = response.getFirstHeader("Content-Encoding");
if (header != null
&& header.getValue().toLowerCase().indexOf("gzip") > -1) {
inputStream = new GZIPInputStream(inputStream);
}
int readBytes = 0;
byte[] sBuffer = new byte[512];
while ((readBytes = inputStream.read(sBuffer)) != -1) {
content.write(sBuffer, 0, readBytes);
}
result = new String(content.toByteArray());
return result;
} catch (IllegalStateException e) {
} catch (IOException e) {
}
return result;
}
/**
* 产生11位的boundary
*/
static String getBoundry() {
StringBuffer _sb = new StringBuffer();
for (int t = 1; t < 12; t++) {
long time = System.currentTimeMillis() + t;
if (time % 3 == 0) {
_sb.append((char) time % 9);
} else if (time % 3 == 1) {
_sb.append((char) (65 + time % 26));
} else {
_sb.append((char) (97 + time % 26));
}
}
return _sb.toString();
}
}