@Override
  public void run() {
    if (mDownloadManager != null) {
      mDownloadManager.onStartDownload(this);
    }
    mException = null;
    InputStream inputStream = null;
    BufferedWriter bufferedWriter = null;
    try {
      int bufferSize = 8192;
      if (mDownloadRateLimit > 0 && bufferSize > mDownloadRateLimit << 10) {
        bufferSize = mDownloadRateLimit << 10;
      }
      mTargetFile = new File(getTempFilePath());
      URL url = new URL(getTargetURL());
      String host = url.getHost();
      int port = (url.getPort() == -1) ? url.getDefaultPort() : url.getPort();

      mSocket = new Socket();
      mSocket.setReceiveBufferSize(bufferSize);
      mSocket.setSoTimeout(getTimeoutInterval());
      SocketAddress address = new InetSocketAddress(host, port);
      mSocket.connect(address, getTimeoutInterval());

      Log.i(TAG, "socket receive buffer size is: " + mSocket.getReceiveBufferSize());
      bufferedWriter =
          new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream(), "UTF8"));
      String requestStr = "GET " + url.getFile() + " HTTP/1.1\r\n";

      String hostHeader = "Host: " + host + "\r\n";
      String acceptHeader =
          "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
      String charsetHeader = "Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3\r\n";
      String languageHeader = "Accept-Language: zh-CN,zh;q=0.8\r\n";
      String keepHeader = "Connection: close\r\n";

      bufferedWriter.write(requestStr);
      bufferedWriter.write(hostHeader);
      bufferedWriter.write(acceptHeader);
      bufferedWriter.write(charsetHeader);
      bufferedWriter.write(languageHeader);
      bufferedWriter.write(keepHeader);
      if (mLoadedByteLength > 0) {
        bufferedWriter.write("Range: bytes=" + mLoadedByteLength + "-\r\n");
      } else {
        guessFileName();
        String folderPath = getFilePath().substring(0, getFilePath().lastIndexOf("/"));
        File folder = new File(folderPath);
        if (!folder.exists() || !folder.isDirectory()) {
          folder.mkdirs();
        } else {
          deleteFile(getFilePath());
          deleteFile(getTempFilePath());
        }
      }
      bufferedWriter.write("\r\n");
      bufferedWriter.flush();
      inputStream = mSocket.getInputStream();
      Log.i(TAG, inputStream.getClass().getName());
      HttpResponseHeaderParser responseHeader = new HttpResponseHeaderParser();
      String responseHeaderLine = null;
      char readChar = 0;
      StringBuilder headerBuilder = new StringBuilder();
      while ((byte) (readChar = (char) inputStream.read()) != -1) {
        headerBuilder.append(readChar);
        if (readChar == 10) {
          responseHeaderLine = headerBuilder.substring(0, headerBuilder.length() - 2);
          headerBuilder.setLength(0);
          if (responseHeaderLine.length() == 0) {
            break;
          } else {
            responseHeader.addResponseHeaderLine(responseHeaderLine);
            Log.i(TAG, responseHeaderLine);
          }
        }
      }
      Log.i(TAG, "status code: " + responseHeader.getStatusCode());

      if (mTotalByteLength == 0) {
        mTotalByteLength = responseHeader.getContentLength();
      }
      mOutputStream = new FileOutputStream(mTargetFile, true);
      mByteOutput = new ByteArrayOutputStream();
      byte[] buffer = new byte[bufferSize];
      int length = -1;
      mTimeStart = System.currentTimeMillis();
      mDeltaLByteLength = 0;
      mSleepTime = 0;
      while ((length = inputStream.read(buffer)) != -1 && mIsDownloading) {
        Log.i(TAG, "receive data: " + length + " available: " + inputStream.available());
        mByteOutput.write(buffer, 0, length);
        if (mByteOutput.size() >= getMemoryCacheSize() << 10) {
          writeCache();
        }
        limitTheByteRate(length);
      }
      Log.i(TAG, "receive data: " + length + " available: " + inputStream.available());

    } catch (Exception e) {
      mException = e;
    } finally {
      if (mException != null && mIsDownloading && mDownloadManager != null) {
        mDownloadManager.onFailedDownload(this);
      }
      try {
        if (bufferedWriter != null) {
          bufferedWriter.close();
          bufferedWriter = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      try {
        if (inputStream != null) {
          inputStream.close();
          inputStream = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      stop();
      writeCache();
      try {
        if (mOutputStream != null) {
          mOutputStream.close();
          mOutputStream = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      try {
        if (mByteOutput != null) {
          mByteOutput.close();
          mByteOutput = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
 /**
  * Read / Parse the waiting read/fill buffer
  *
  * @param buffer the buffer to fill into from the endpoint
  * @return true if there is more to read, false if reading should stop
  */
 private boolean read(ByteBuffer buffer) {
   EndPoint endPoint = getEndPoint();
   try {
     while (true) {
       int filled = endPoint.fill(buffer);
       if (filled == 0) {
         return true;
       } else if (filled < 0) {
         LOG.debug("read - EOF Reached");
         return false;
       } else {
         if (LOG.isDebugEnabled()) {
           LOG.debug("Filled {} bytes - {}", filled, BufferUtil.toDetailString(buffer));
         }
         ClientUpgradeResponse resp = parser.parse(buffer);
         if (resp != null) {
           // Got a response!
           client.setUpgradeResponse(resp);
           validateResponse(resp);
           notifyConnect(resp);
           upgradeConnection(resp);
           return false; // do no more reading
         }
       }
     }
   } catch (IOException e) {
     LOG.warn(e);
     client.failed(e);
     disconnect(false);
     return false;
   } catch (UpgradeException e) {
     LOG.warn(e);
     client.failed(e);
     disconnect(false);
     return false;
   }
 }