/**
  * This horrible hack is required on Android, due to implementation of BasicManagedEntity, which
  * doesn't chain call consumeContent on underlying wrapped HttpEntity see more at open source
  * project 'android-async-http'
  *
  * @param entity HttpEntity, may be null
  */
 public void endEntityViaReflection(HttpEntity entity) {
   if (entity instanceof HttpEntityWrapper) {
     try {
       Field f = null;
       Field[] fields = HttpEntityWrapper.class.getDeclaredFields();
       for (Field ff : fields) {
         if (ff.getName().equals("wrappedEntity")) {
           f = ff;
           break;
         }
       }
       if (f != null) {
         f.setAccessible(true);
         HttpEntity wrapped = (HttpEntity) f.get(entity);
         if (wrapped != null) {
           wrapped.consumeContent();
           if (HttpLog.isPrint) {
             HttpLog.d(TAG, "HttpEntity wrappedEntity reflection consumeContent");
           }
         }
       }
     } catch (Throwable t) {
       HttpLog.e(TAG, "wrappedEntity consume error. ", t);
     }
   }
 }
 /** get Charset String From HTTP Response */
 private String getCharsetFromEntity(HttpEntity entity, String defCharset) {
   final Header header = entity.getContentType();
   if (header != null) {
     final HeaderElement[] elements = header.getElements();
     if (elements.length > 0) {
       HeaderElement helem = elements[0];
       // final String mimeType = helem.getName();
       final NameValuePair[] params = helem.getParameters();
       if (params != null) {
         for (final NameValuePair param : params) {
           if (param.getName().equalsIgnoreCase("charset")) {
             String s = param.getValue();
             if (s != null && s.length() > 0) {
               return s;
             }
           }
         }
       }
     }
   }
   return defCharset == null ? Charsets.UTF_8 : defCharset;
 }
  /** 连接网络读取数据 */
  @Override
  protected <T> void connectWithRetries(AbstractRequest<T> request, InternalResponse response)
      throws HttpClientException, HttpNetException, HttpServerException {

    // if(true) {
    //    throw new HttpNetException(NetException.NetworkDisabled);
    // }

    // 1. create apache request
    final HttpUriRequest apacheRequest = createApacheRequest(request);

    // 2. update http header
    if (request.getHeaders() != null) {
      Set<Entry<String, String>> set = request.getHeaders().entrySet();
      for (Entry<String, String> en : set) {
        apacheRequest.setHeader(new BasicHeader(en.getKey(), en.getValue()));
      }
    }

    // 3. try to connect
    HttpListener<T> listener = request.getHttpListener();
    StatisticsListener statistic = response.getStatistics();
    int times = 0,
        maxRetryTimes = request.getMaxRetryTimes(),
        maxRedirectTimes = request.getMaxRedirectTimes();
    boolean retry = true;
    IOException cause = null;
    while (retry) {
      try {
        cause = null;
        retry = false;
        if (request.isCancelledOrInterrupted()) {
          return;
        }
        if (statistic != null) {
          statistic.onPreConnect(request);
        }
        HttpResponse ares = mHttpClient.execute(apacheRequest);
        if (statistic != null) {
          statistic.onAfterConnect(request);
        }
        // status
        StatusLine status = ares.getStatusLine();
        HttpStatus httpStatus = new HttpStatus(status.getStatusCode(), status.getReasonPhrase());
        response.setHttpStatus(httpStatus);
        // header
        Header[] headers = ares.getAllHeaders();
        if (headers != null) {
          com.litesuits.http.data.NameValuePair hs[] =
              new com.litesuits.http.data.NameValuePair[headers.length];
          for (int i = 0; i < headers.length; i++) {
            String name = headers[i].getName();
            String value = headers[i].getValue();
            if ("Content-Length".equalsIgnoreCase(name)) {
              response.setContentLength(Long.parseLong(value));
            }
            hs[i] = new com.litesuits.http.data.NameValuePair(name, value);
          }
          response.setHeaders(hs);
        }

        // data body
        if (status.getStatusCode() <= 299 || status.getStatusCode() == 600) {
          // 成功
          HttpEntity entity = ares.getEntity();
          if (entity != null) {
            // charset
            String charSet = getCharsetFromEntity(entity, request.getCharSet());
            response.setCharSet(charSet);
            // is cancelled ?
            if (request.isCancelledOrInterrupted()) {
              return;
            }
            // length
            long len = response.getContentLength();
            DataParser<T> parser = request.getDataParser();
            if (statistic != null) {
              statistic.onPreRead(request);
            }
            parser.readFromNetStream(entity.getContent(), len, charSet);
            if (statistic != null) {
              statistic.onAfterRead(request);
            }
            response.setReadedLength(parser.getReadedLength());
            endEntityViaReflection(entity);
          }
          return;
        } else if (status.getStatusCode() <= 399) {
          // redirect
          if (response.getRedirectTimes() < maxRedirectTimes) {
            // get the location header to find out where to redirect to
            Header locationHeader = ares.getFirstHeader(Consts.REDIRECT_LOCATION);
            if (locationHeader != null) {
              String location = locationHeader.getValue();
              if (location != null && location.length() > 0) {
                if (!location.toLowerCase().startsWith("http")) {
                  URI uri = new URI(request.getFullUri());
                  URI redirect = new URI(uri.getScheme(), uri.getHost(), location, null);
                  location = redirect.toString();
                }
                response.setRedirectTimes(response.getRedirectTimes() + 1);
                request.setUri(location);
                if (HttpLog.isPrint) {
                  HttpLog.i(TAG, "Redirect to : " + location);
                }
                if (listener != null) {
                  listener.notifyCallRedirect(
                      request, maxRedirectTimes, response.getRedirectTimes());
                }
                connectWithRetries(request, response);
                return;
              }
            }
            throw new HttpServerException(httpStatus);
          } else {
            throw new HttpServerException(ServerException.RedirectTooMuch);
          }
        } else if (status.getStatusCode() <= 499) {
          // 客户端被拒
          throw new HttpServerException(httpStatus);
        } else if (status.getStatusCode() < 599) {
          // 服务器有误
          throw new HttpServerException(httpStatus);
        }
      } catch (IOException e) {
        cause = e;
      } catch (NullPointerException e) {
        // bug in HttpClient 4.0.x, see http://code.google.com/p/android/issues/detail?id=5255
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
          cause = new IOException(e.getMessage());
        } else {
          cause = new IOException(e);
        }
      } catch (URISyntaxException e) {
        throw new HttpClientException(e);
      } catch (IllegalStateException e) {
        // for apache http client. if url is illegal, it usually raises an exception as
        // "IllegalStateException:
        // Scheme 'xxx' not registered."
        throw new HttpClientException(e);
      } catch (SecurityException e) {
        throw new HttpClientException(e, ClientException.PermissionDenied);
      } catch (RuntimeException e) {
        throw new HttpClientException(e);
      }
      if (cause != null) {
        try {
          if (request.isCancelledOrInterrupted()) {
            return;
          }
          times++;
          retry =
              retryHandler.retryRequest(
                  cause, times, maxRetryTimes, mHttpContext, config.getContext());
        } catch (InterruptedException e) {
          e.printStackTrace();
          return;
        }
        if (retry) {
          response.setRetryTimes(times);
          if (HttpLog.isPrint) {
            HttpLog.i(TAG, "LiteHttp retry request: " + request.getUri());
          }
          if (listener != null) {
            listener.notifyCallRetry(request, maxRetryTimes, times);
          }
        }
      }
    }
    if (cause != null) {
      throw new HttpNetException(cause);
    }
  }