package com.hua.goddess.base.net;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
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.ssl.SSLSocketFactory;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.SyncBasicHttpContext;
import com.hua.goddess.global.Globe;
/**
* HTTP请求相应处理类
* @author hanchao
* created by May 5, 2010 5:28:34 PM
*/
public abstract class HttpConnect {
/**
* 请求参数
*/
protected RequestParcelable requestParam;
private DefaultHttpClient httpClient;
private int executionCount;
private HttpContext httpContext;
HttpUriRequest httpRequest;
protected HttpConnect(RequestParcelable requestParam) {
this(true);
this.requestParam = requestParam;
}
protected HttpConnect() {
this(true);
}
protected HttpConnect(Boolean isretry){
super();
init(isretry);
}
/**
* 建立HTTPost对象
*/
private void init(Boolean isretry){
BasicHttpParams httpParams = new BasicHttpParams();
ConnManagerParams.setTimeout(httpParams, Globe.TIMEOUT_SOCKET);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(15));
ConnManagerParams.setMaxTotalConnections(httpParams, 15);
HttpConnectionParams.setConnectionTimeout(httpParams, Globe.TIMEOUT_CONNECTION);
HttpConnectionParams.setSoTimeout(httpParams, Globe.TIMEOUT_SOCKET);
HttpConnectionParams.setTcpNoDelay(httpParams, true);
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
httpContext = new SyncBasicHttpContext(new BasicHttpContext());
httpClient = new DefaultHttpClient(cm, httpParams);
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(HttpRequest request, HttpContext context) {
if (!request.containsHeader(Globe.HEADER_ACCEPT_ENCODING)) {
request.addHeader(Globe.HEADER_ACCEPT_ENCODING, Globe.ENCODING_GZIP);
}
}
});
httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
public void process(HttpResponse response, HttpContext context) {
final HttpEntity entity = response.getEntity();
final Header encoding = entity.getContentEncoding();
if (encoding != null) {
for (HeaderElement element : encoding.getElements()) {
if (element.getName().equalsIgnoreCase(Globe.ENCODING_GZIP)) {
response.setEntity(new InflatingEntity(response.getEntity()));
break;
}
}
}
}
});
if(isretry){
httpClient.setHttpRequestRetryHandler(new RetryHandler(3));
}
}
/**
* 发送请求
* @throws IOException
* @throws ClientProtocolException
* @throws ErrorResponseException
* @throws UnsupportedEncodingException
* @throws ConnectException
*/
public void connect() throws
ErrorResponseException, UnsupportedEncodingException, Exception {
/*
* 若以.png或.apk结尾,则不加jsessionid
*/
String requestUri = "";
if (requestParam.getUrl() != null
&& (requestParam.getUrl().endsWith(".png")
|| requestParam.getUrl().endsWith(".jpg")
|| requestParam.getUrl().endsWith(".jpeg")
|| requestParam.getUrl().endsWith(".gif") || requestParam
.getUrl().endsWith(".apk"))){
//添加引用页头信息
requestParam.getHeaders().put("Referer", requestParam.getUrl().substring(requestParam.getUrl().lastIndexOf("/"))+"index.html");
requestUri = requestParam.getUrl();
}else
//下载路径,
// requestUri = requestParam.getUrl()+"?phpsessid="+Globe.session_id;//+"?jsessionid="+Globe.session_id;
requestUri = requestParam.getUrl();
//判断是否需要post方式访问服务器
byte[] postStream = requestParam.getPostStream();
if ((postStream != null && postStream.length > 0) || (requestParam.getParams() !=null)) {
httpRequest = getHttpPostRequest(requestUri);
}else{
httpRequest = getHttpGetRequest(requestUri);
}
makeRequestWithRetries();
}
/**
* 发送请求获取服务器响应
* @throws IllegalStateException
* @throws Exception
*/
private void makeRequest() throws IllegalStateException, Exception {
//throw new UnknownHostException();
/*发送请求并等待响应*/
HttpResponse httpResponse = httpClient.execute(httpRequest);
int statusCode = httpResponse.getStatusLine().getStatusCode();
//200
if (statusCode == 200
|| httpResponse.getStatusLine().getStatusCode() == 206) {
onDataReceived(httpResponse);
} else {
// 200以外的响应状态码
throw new ErrorResponseException(httpResponse.getStatusLine()
.getStatusCode());
}
}
private void makeRequestWithRetries() throws Exception {
// This is an additional layer of retry logic lifted from droid-fu
// See: https://github.com/kaeppler/droid-fu/blob/master/src/main/java/com/github/droidfu/http/BetterHttpRequestBase.java
boolean retry = false;
IOException cause = null;
HttpRequestRetryHandler retryHandler = null;
do {
try {
makeRequest();
return;
} catch (IOException e) {
cause = e;
retryHandler = httpClient.getHttpRequestRetryHandler();
if(retryHandler != null && retryHandler instanceof RetryHandler){
retry = retryHandler.retryRequest(cause, ++executionCount, httpContext);
}
retry = false;
} catch (NullPointerException e) {
// there's a bug in HttpClient 4.0.x that on some occasions causes
// DefaultRequestExecutor to throw an NPE, see
// http://code.google.com/p/android/issues/detail?id=5255
cause = new IOException("NPE in HttpClient" + e.getMessage());
//retry = retryHandler.retryRequest(cause, ++executionCount, httpContext);
retryHandler = httpClient.getHttpRequestRetryHandler();
if(retryHandler != null && retryHandler instanceof RetryHandler){
retry = retryHandler.retryRequest(cause, ++executionCount, httpContext);
}
retry = false;
}catch (Exception e) {
e.printStackTrace();
throw e;
}
}while (retry);
// // no retries left, crap out with exception
// ConnectException ex = new ConnectException();
// ex.initCause(cause);
// throw ex;
}
/**
* 服务器响应事件
* @throws IOException
* @throws IllegalStateException
* @throws IOException
*/
protected void onDataReceived(HttpResponse httpResponse) throws IllegalStateException, IOException,Exception
{
onReceiverHeaders(httpResponse);
getResponseEntity(httpResponse);
}
/**
* 获取响应头参数事件
* 虚函数,当调用HttpConnect时,需要实现onReceiverHeaders(HttpResponse httpResponse)
* 注意:
* 若不需要获取响应头信息,则只实现空函数体即可.
* 若需要获取响应头信息,则可以直接调用super.getResponseHeaders(HttpResponse httpResponse)方法,
* 该方法返回HashMap<String,String>类型的响应头参数
* @param httpResponse
*/
protected abstract void onReceiverHeaders(HttpResponse httpResponse) throws UnsupportedEncodingException;
/**
* 接收相应体触发事件.利用该事件可以实现大文件下载时的进度监控。
* 虚函数,当调用HttpConnect时,需要实现onReceiverBodyStream(InputStream is)
* 注意:
* 1.该函数是在服务器响应请求时,相应体内有数据的情况下(content-length>0)才会触发。
*
* 两种读取方式:
* 1.文本文件类型:
* //InputStreamReader isr = new InputStreamReader(is);
* //BufferedReader br = new BufferedReader(isr);
* //br.readLine();
*
* 2.文件类型:
* //读取到的数据长度
* //int len;
* //1K的数据缓冲
* //byte[] bs = new byte[1024];
* //while ((len = is.read(bs)) != -1)
* // os.write(bs, 0, len);
* @param bytes
* @param len
*/
protected abstract void onReceiveBodyStream(InputStream is,long contentLength) throws IOException,Exception;
/**
* 获取响应头参数
* @param httpResponse
* @return
* @throws UnsupportedEncodingException
*/
protected ParcelMap getResponseHeaders(HttpResponse httpResponse) throws UnsupportedEncodingException
{
/*读取相应头参数*/
ParcelMap resHeaders = new ParcelMap();
HeaderIterator hIte = httpResponse.headerIterator();
while(hIte.hasNext())
{
Header header = hIte.nextHeader();
String key = header.getName();
String value = header.getValue();
value = new String(value.getBytes("ISO-8859-1"),"GB2312");
resHeaders.put(key, value);
}
return resHeaders;
}
/**
* 获取相应体
* @param httpResponse
* @throws IllegalStateException
* @throws IOException
*/
protected void getResponseEntity(HttpResponse httpResponse) throws IllegalStateException, IOException,Exception
{
/*读取相应体*/
HttpEntity entity = httpResponse.getEntity();
if (entity != null ) {//&& entity.getContentLength() > 0) {
InputStream is = null;
// try {
is = entity.getContent();
onReceiveBodyStream(is,entity.getContentLength());
if(is!=null)
is.close();
// }
// finally
// {
// if(is!=null)
// is.close();
// }
}
}
/**
* 设置请求参数
*
* @throws UnsupportedEncodingException
*/
private HttpPost getHttpPostRequest(String requestUri) throws UnsupportedEncodingException
{
HttpPost httpRequest = new HttpPost(requestUri);
/*设置请求参数*/
HashMap<String, String> reqParams = requestParam.getParams();
if(reqParams!=null&&reqParams.size()>0)
{
Set<String> keyset = reqParams.keySet();
Iterator<String> ite = keyset.iterator();
ArrayList<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
while(ite.hasNext())
{
String key = ite.next();
String value = reqParams.get(key);
params.add(new BasicNameValuePair(key,value));
}
httpRequest.setEntity(new UrlEncodedFormEntity(params, requestParam.getCharset()));
}
/*设置请求头参数*/
HashMap<String, String> reqHeaders = requestParam.getHeaders();
if(reqHeaders!=null&&reqHeaders.size()>0)
{
Set<String> keyset = reqHeaders.keySet();
Iterator<String> ite = keyset.iterator();
while(ite.hasNext())
{
String key = ite.next();
String value = reqHeaders.get(key);
httpRequest.setHeader(key, value);
}
}
/*设置请求实体*/
byte[] postStream = requestParam.getPostStream();
if(postStream!=null&&postStream.length>0)
{
InputStream is = new ByteArrayInputStream(postStream);
InputStreamEntity reqEntity = new InputStreamEntity(is, postStream.length);
//reqEntity.setContentType("binary/octet-stream");
// reqEntity.setChunked(true); //设置chunked 传输模式
httpRequest.setEntity(reqEntity);
}
return httpRequest;
}
private HttpGet getHttpGetRequest(String requestUri)
throws UnsupportedEncodingException {
/*设置请求参数*/
HashMap<String, String> reqParams = requestParam.getParams();
if (reqParams != null && reqParams.size() > 0) {
StringBuffer uriParam = new StringBuffer("");
Set<String> keyset = reqParams.keySet();
Iterator<String> ite = keyset.iterator();
while (ite.hasNext()) {
String key = ite.next();
String value = reqParams.get(key);
uriParam.append(key+"="+value+"&");
}
requestUri += uriParam.substring(0, uriParam.length()-1);
}
HttpGet httpRequest = new HttpGet(requestUri);
/*设置请求头参数*/
HashMap<String, String> reqHeaders = requestParam.getHeaders();
if (reqHeaders != null && reqHeaders.size() > 0) {
Set<String> keyset = reqHeaders.keySet();
Iterator<String> ite = keyset.iterator();
while (ite.hasNext()) {
String key = ite.next();
String value = reqHeaders.get(key);
httpRequest.setHeader(key, value);
}
}
return httpRequest;
}
private static class InflatingEntity extends HttpEntityWrapper {
public InflatingEntity(HttpEntity wrapped) {
super(wrapped);
}
@Override
public InputStream getContent() throws IOException {
return new GZIPInputStream(wrappedEntity.getContent());
}
@Override
public long getContentLength() {
return -1;
}
}
}