//package org.terukusu.android.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.Header;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
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.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import android.util.Log;
/**
* Web???????????????????????
*
* @author Teruhiko Kusunoki< * href="teru.kusu@gmail.com">teru.kusu@gmail.com>
*
*/
public class HttpDownloader {
/**
* TAG for {@link android.util.Log}
*/
private static final String TAG = HttpDownloader.class.getSimpleName();
public static enum Method {
POST, GET
}
private static final int DEFAULT_BUFFER_SIZE = 4096;
private static final int DEFAULT_CONNECTION_TIMEOUT = 10000;
private static final int DEFAULT_SO_TIMEOUT = 10000;
/** URL?????????????????? */
private String encoding = StringUtils.getDefaultEncoding();
private Method method = Method.GET;
private String url;
private Map queries;
private Map cookies;
private Map headers;
private int bufferSize = DEFAULT_BUFFER_SIZE;
private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
private int soTimeout = DEFAULT_SO_TIMEOUT;
/** ??????????Content-Length????? */
private long contentLength;
/** ??????????????? */
private long elapsed;
/** ??????????? */
private long downloaded;
/** ??????(bps) */
private long avarageSpeed;
/** ??????????????? */
private boolean isCanceled = false;
/**
* ????????????????
*
*/
public HttpDownloader() {
}
/**
* ????????????????
*
* @param url
* URL???
*/
public HttpDownloader(String url) {
setUrl(url);
}
/**
* ????????????????
*
* @param url
* URL
* @param queries
* ???
*/
public HttpDownloader(String url, Map queries) {
this.url = url;
this.queries = queries;
}
public HttpDownloader(String url, Map queries,
Map cookies) {
this.url = url;
this.queries = queries;
this.cookies = cookies;
}
/**
* ????????????
*
* @throws SocketTimeoutException
* ????????????????????????
* @throws ClientProtocolException
* ?????????????????
* @throws IOException
* ?????????????
*/
public HttpResponse execute() throws SocketTimeoutException,
ClientProtocolException, IOException {
long start = System.currentTimeMillis();
HttpUriRequest request = null;
List postParams = new ArrayList();
if (Method.POST == getMethod()) {
HttpPost post = new HttpPost(getUrl());
if (getQueries() != null) {
for (Map.Entry entry : getQueries().entrySet()) {
postParams.add(new BasicNameValuePair(entry.getKey(), entry
.getValue()));
}
}
post.setEntity(new UrlEncodedFormEntity(postParams, getEncoding()));
request = post;
} else {
StringBuilder sb = new StringBuilder(getUrl());
if (getQueries() != null) {
if (sb.indexOf("?") >= 0) {
sb.append('&');
} else {
sb.append('?');
}
sb.append(makeQueryString(getQueries()));
}
String fullUrl = sb.toString();
HttpGet get = new HttpGet(fullUrl);
request = get;
}
// ????
if (getCookies() != null) {
String cookieStr = makeCookieString(getCookies());
request.addHeader("Cookie", cookieStr);
}
if (getHeaders() != null) {
for (Map.Entry entry : getHeaders().entrySet()) {
request.addHeader(entry.getKey(),
URLEncoder.encode(entry.getValue(), getEncoding()));
}
}
HttpClient client = new DefaultHttpClient();
client.getParams()
.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
getConnectionTimeout());
client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT,
getSoTimeout());
org.apache.http.HttpResponse hr = null;
HttpResponse res = new HttpResponse();
hr = client.execute(request);
// ??
res.setStatusCode(hr.getStatusLine().getStatusCode());
// header
for (Header header : hr.getAllHeaders()) {
res.setHeader(header.getName(), header.getValue());
}
// cookie
for (Header header : hr.getHeaders("Set-Cookie")) {
String cookieEntry = header.getValue();
Cookie cookie = Cookie.parseCookie(cookieEntry, null);
res.setCookie(cookie.getKey(), cookie);
}
// body
if (hr.getEntity() == null) {
return res;
}
// ?????
Header contentTypeHeader = hr.getEntity().getContentType();
if (contentTypeHeader != null) {
String contentType = contentTypeHeader.getValue();
if (contentType != null) {
Pattern p = Pattern.compile(
"text/[^;]+(\\s*;\\s*charset\\s*=\\s*(.+))?",
Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(contentType);
if (m.find() && !StringUtils.isBlank(m.group(2))) {
res.setCharacterEncoding(m.group(2));
}
}
}
setContentLength(hr.getEntity().getContentLength());
res.setContentLength(hr.getEntity().getContentLength());
ByteArrayOutputStream baos = null;
InputStream is = null;
try {
baos = new ByteArrayOutputStream();
is = hr.getEntity().getContent();
byte[] buff = new byte[getBufferSize()];
int readSize = 0;
while (!isCanceled()) {
if (Thread.interrupted()) {
// ??????????
Thread.currentThread().interrupt();
synchronized (this) {
isCanceled = true;
}
break;
}
if ((readSize = is.read(buff)) < 0) {
// ??????
break;
}
synchronized (this) {
setDownloaded(getDownloaded() + readSize);
setElapsed(System.currentTimeMillis() - start);
long elapsedSec = getElapsed() / 1000;
if (elapsedSec == 0) {
setAvarageSpeed(getDownloaded());
} else {
setAvarageSpeed(getDownloaded() / elapsedSec);
}
}
baos.write(buff, 0, readSize);
}
Log.v(TAG, "downloaded: avarage speed = " + getAvarageSpeed()
+ " bps, downloaded = " + getDownloaded() + " bytes");
if (isCanceled()) {
// ?DL??DL???
request.abort();
}
} finally {
try {
baos.close();
} catch (Exception ignore) {
}
try {
is.close();
} catch (Exception ignore) {
}
}
res.setBody(baos.toByteArray());
return res;
}
/**
* ?????URL??????????????
*
* @param params
* ???
* @return ??????
*/
private String makeQueryString(Map params) {
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : params.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
try {
sb.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(),
getEncoding()));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
return sb.toString();
}
/**
* Cookie??????????????????????
*
* @param cookies
* ???????????????
* @return Cookie??????????
*/
private String makeCookieString(Map cookies) {
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : cookies.entrySet()) {
if (sb.length() > 0) {
sb.append("; ");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
}
return sb.toString();
}
/**
* ????????????
*/
public synchronized void cancel() {
isCanceled = true;
}
/**
* ???????(bps)???
*
* @return ???????
*/
public synchronized long getSpeed() {
// TODO implement
return 0;
}
/**
* encoding ???????
*
* @return encoding
*/
public synchronized String getEncoding() {
return encoding;
}
/**
* encoding ???????
*
* @param encoding
* ????? encoding
*/
public synchronized void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* method ???????
*
* @return method
*/
public synchronized Method getMethod() {
return method;
}
/**
* method ???????
*
* @param method
* ????? method
*/
public synchronized void setMethod(Method method) {
this.method = method;
}
/**
* url ???????
*
* @return url
*/
public synchronized String getUrl() {
return url;
}
/**
* url ???????
*
* @param url
* ????? url
*/
public synchronized void setUrl(String url) {
this.url = url;
}
/**
* queries ???????
*
* @return queries
*/
public synchronized Map getQueries() {
return queries;
}
/**
* queries ???????
*
* @param queries
* ????? queries
*/
public synchronized void setQueries(Map queries) {
this.queries = queries;
}
/**
* elapsed ???????
*
* @return elapsed
*/
public synchronized long getElapsed() {
return elapsed;
}
/**
* elapsed ???????
*
* @param elapsed
* ????? elapsed
*/
public synchronized void setElapsed(long elapsed) {
this.elapsed = elapsed;
}
/**
* bufferSize ???????
*
* @return bufferSize
*/
public synchronized int getBufferSize() {
return bufferSize;
}
/**
* bufferSize ???????
*
* @param bufferSize
* ????? bufferSize
*/
public synchronized void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
/**
* cookies ???????
*
* @return cookies
*/
public synchronized Map getCookies() {
return cookies;
}
/**
* cookies ???????
*
* @param cookies
* ????? cookies
*/
public synchronized void setCookies(Map cookies) {
this.cookies = cookies;
}
/**
* contentLength ???????
*
* @return contentLength
*/
public synchronized long getContentLength() {
return contentLength;
}
/**
* contentLength ???????
*
* @param contentLength
* ????? contentLength
*/
protected synchronized void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
/**
* downloaded ???????
*
* @return downloaded
*/
public synchronized long getDownloaded() {
return downloaded;
}
/**
* downloaded ???????
*
* @param downloaded
* ????? downloaded
*/
protected synchronized void setDownloaded(long downloaded) {
this.downloaded = downloaded;
}
/**
* isCanceled ???????
*
* @return isCanceled
*/
public synchronized boolean isCanceled() {
return isCanceled;
}
/**
* isCanceled ???????
*
* @param isCanceled
* ????? isCanceled
*/
protected synchronized void setCanceled(boolean isCanceled) {
this.isCanceled = isCanceled;
}
/**
* avarageSpeed ???????
*
* @return avarageSpeed
*/
public synchronized long getAvarageSpeed() {
return avarageSpeed;
}
/**
* avarageSpeed ???????
*
* @param avarageSpeed
* ????? avarageSpeed
*/
protected synchronized void setAvarageSpeed(long avarageSpeed) {
this.avarageSpeed = avarageSpeed;
}
/**
* connectionTimeout ???????
*
* @return connectionTimeout
*/
public synchronized int getConnectionTimeout() {
return connectionTimeout;
}
/**
* connectionTimeout ???????
*
* @param connectionTimeout
* ????? connectionTimeout
*/
public synchronized void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* soTimeout ???????
*
* @return soTimeout
*/
public synchronized int getSoTimeout() {
return soTimeout;
}
/**
* soTimeout ???????
*
* @param soTimeout
* ????? soTimeout
*/
public synchronized void setSoTimeout(int soTimeout) {
this.soTimeout = soTimeout;
}
/**
* headers ???????
*
* @return headers
*/
public synchronized Map getHeaders() {
return headers;
}
/**
* headers ???????
*
* @param headers
* ????? headers
*/
public synchronized void setHeaders(Map headers) {
this.headers = headers;
}
}
/**
* @author Teruhiko Kusunoki< * href="teru.kusu@gmail.com">teru.kusu@gmail.com>
*
*/
class HttpResponse {
private int statusCode;
private long contentLength;
private String characterEncoding;
private final Map headers = new HashMap();
private final Map cookies = new HashMap();
private byte[] body;
/**
*
*/
public HttpResponse() {
}
public void setHeader(String name, String value) {
this.headers.put(name, value);
}
/**
* header ???????
*
* @return headers
*/
public String getHeader(String name) {
return this.headers.get(name);
}
/**
* headers ???????
*
* @return headers
*/
public Map getHeaders() {
return headers;
}
/**
* ???????????
*
* @param name
* ??
* @return ????
*/
public Cookie getCookie(String name) {
return this.cookies.get(name);
}
/**
* ???????????
*
* @param name
* ??
* @param cookie
* ????
*/
public void setCookie(String name, Cookie cookie) {
this.cookies.put(name, cookie);
}
/**
* cookies ???????
*
* @return cookies
*/
public Map getCookies() {
return cookies;
}
/**
* body ???????
*
* @return body
*/
public byte[] getBody() {
return body;
}
/**
* body ???????
*
* @param body
* ????? body
*/
public void setBody(byte[] body) {
this.body = body;
}
/**
* statusCode ???????
*
* @return statusCode
*/
public int getStatusCode() {
return statusCode;
}
/**
* statusCode ???????
*
* @param statusCode
* ????? statusCode
*/
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
/**
* contentLength ???????
*
* @return contentLength
*/
public long getContentLength() {
return contentLength;
}
/**
* contentLength ???????
*
* @param contentLength
* ????? contentLength
*/
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
/**
* characterEncoding ??????? ????????? text/* ? charset ??????????????????
*
* @return characterEncoding
*/
public String getCharacterEncoding() {
return characterEncoding;
}
/**
* characterEncoding ???????
*
* @param characterEncoding
* ????? characterEncoding
*/
public void setCharacterEncoding(String characterEncoding) {
this.characterEncoding = characterEncoding;
}
}
/**
* ?????????????????????????????
*
* @author Teruhiko Kusunoki< * href="teru.kusu@gmail.com">teru.kusu@gmail.com>
*
*/
class StringUtils {
/**
* ??????????????????????????????
*/
private static final Pattern BLANK_PATTERN = Pattern.compile("^\\s*$");
/**
* ????????????????
*
* @param str
* ????????
* @return ?????null???true??????false
*/
public static boolean isEmpty(String str) {
return (str == null || str.length() == 0);
}
/**
* null????????????????????????????????????
*
* @param str
* ????????
* @return null???????????????????????????? true??????false?
*/
public static boolean isBlank(String str) {
return (str == null || BLANK_PATTERN.matcher(str).matches());
}
/**
* ????????????????????????????????
*
* @return ?????????????????????????
*/
public static String getDefaultEncoding() {
return System.getProperty("file.encoding");
}
/**
* Base64??????????????????????????????????? ?: Mzg1OTQyMjczMA== =>
* 3859422730 => 0xE60A1E0A => 10.30.10.230
*
* @param str
* Base64????????????????
* @return ???????????
*/
public static String base64toInetAddress(String str) {
// TODO ??
throw new UnsupportedOperationException();
// String numStr = new String(Base64.decode(str, Base64.DEFAULT));
// int num = Integer.parseInt(numStr);
//
// String ipAddr = (num & 0xFF) + "." + (num >> 8 & 0xFF) + "."
// + (num >> 16 & 0xFF) + "." + (num >> 24 & 0xFF);
//
// return ipAddr;
}
}
/**
* @author Teruhiko Kusunoki< * href="teru.kusu@gmail.com">teru.kusu@gmail.com>
*
*/
class Cookie {
private String key;
private String value;
private String path;
private Date expire;
private String domain;
private boolean secure = false;
/**
* Set-Cookie ??????????????????????????? ?????????????
*
* @param cookieHeader
* Set-Cookie?????
* @return ??????????
* @throws ParseException
* ?????????
*/
public static Cookie parseCookie(String cookieHeader) {
return parseCookie(cookieHeader, null);
}
/**
* Set-Cookie ???????????????????????????
*
* @param cookieHeader
* Set-Cookie?????
* @param encode
* cookie???????. null?????????????????
* @return ??????????
* @throws ParseException
* ?????????
*/
public static Cookie parseCookie(String cookieHeader, String encode) {
Cookie c = new Cookie();
for (String str : cookieHeader.split("\\s*;\\s*")) {
int index = str.indexOf('=');
if (index < 0) {
if ("secure".equals(str.toLowerCase())) {
c.setSecure(true);
}
continue;
}
String key = str.substring(0, index).toLowerCase();
String value = str.substring(index + 1);
if ("expires".equals(key.toLowerCase())) {
SimpleDateFormat sdf = new SimpleDateFormat(
"EEE, d-MMM-yyyy HH:mm:ss ZZZ", Locale.US);
Date date = null;
try {
date = sdf.parse(value);
} catch (ParseException e) {
throw new RuntimeException(e.getMessage(), e);
}
c.setExpire(date);
} else if ("domain".equals(key.toLowerCase())) {
c.setDomain(value);
} else if ("path".equals(key.toLowerCase())) {
c.setPath(value);
} else {
c.setKey(key);
if (StringUtils.isBlank(encode)) {
c.setValue(value);
} else {
try {
c.setValue(URLDecoder.decode(value, encode));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
}
return c;
}
/**
* key ???????
*
* @return key
*/
public String getKey() {
return key;
}
/**
* key ???????
*
* @param key
* ????? key
*/
public void setKey(String key) {
this.key = key;
}
/**
* value ???????
*
* @return value
*/
public String getValue() {
return value;
}
/**
* value ???????
*
* @param value
* ????? value
*/
public void setValue(String value) {
this.value = value;
}
/**
* path ???????
*
* @return path
*/
public String getPath() {
return path;
}
/**
* path ???????
*
* @param path
* ????? path
*/
public void setPath(String path) {
this.path = path;
}
/**
* expire ???????
*
* @return expire
*/
public Date getExpire() {
return expire;
}
/**
* expire ???????
*
* @param expire
* ????? expire
*/
public void setExpire(Date expire) {
this.expire = expire;
}
/**
* domain ???????
*
* @return domain
*/
public String getDomain() {
return domain;
}
/**
* domain ???????
*
* @param domain
* ????? domain
*/
public void setDomain(String domain) {
this.domain = domain;
}
/**
* secure ???????
*
* @return secure
*/
public boolean isSecure() {
return secure;
}
/**
* secure ???????
*
* @param secure
* ????? secure
*/
public void setSecure(boolean secure) {
this.secure = secure;
}
}