Network Android

//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;
  }
}