/**
   * Parse the headers sent from the server.
   *
   * @param headers gives up the HeaderGroup IMPORTANT: as this is called from network thread, can't
   *     call native directly
   */
  public void headers(Headers headers) {
    if (Config.LOGV) Log.v(LOGTAG, "LoadListener.headers");
    if (mCancelled) return;
    mHeaders = headers;
    mMimeType = "";
    mEncoding = "";

    ArrayList<String> cookies = headers.getSetCookie();
    for (int i = 0; i < cookies.size(); ++i) {
      CookieManager.getInstance().setCookie(mUri, cookies.get(i));
    }

    long contentLength = headers.getContentLength();
    if (contentLength != Headers.NO_CONTENT_LENGTH) {
      mContentLength = contentLength;
    } else {
      mContentLength = 0;
    }

    String contentType = headers.getContentType();
    if (contentType != null) {
      parseContentTypeHeader(contentType);

      // If we have one of "generic" MIME types, try to deduce
      // the right MIME type from the file extension (if any):
      if (mMimeType.equalsIgnoreCase("text/plain")
          || mMimeType.equalsIgnoreCase("application/octet-stream")) {

        String newMimeType = guessMimeTypeFromExtension();
        if (newMimeType != null) {
          mMimeType = newMimeType;
        }
      } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) {
        // As we don't support wml, render it as plain text
        mMimeType = "text/plain";
      } else {
        // XXX: Until the servers send us either correct xhtml or
        // text/html, treat application/xhtml+xml as text/html.
        // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
        // subtypes are used interchangeably. So treat them the same.
        if (mMimeType.equalsIgnoreCase("application/xhtml+xml")
            || mMimeType.equals("application/vnd.wap.xhtml+xml")) {
          mMimeType = "text/html";
        }
      }
    } else {
      /* Often when servers respond with 304 Not Modified or a
      Redirect, then they don't specify a MIMEType. When this
      occurs, the function below is called.  In the case of
      304 Not Modified, the cached headers are used rather
      than the headers that are returned from the server. */
      guessMimeType();
    }

    // is it an authentication request?
    boolean mustAuthenticate = (mStatusCode == HTTP_AUTH || mStatusCode == HTTP_PROXY_AUTH);
    // is it a proxy authentication request?
    boolean isProxyAuthRequest = (mStatusCode == HTTP_PROXY_AUTH);
    // is this authentication request due to a failed attempt to
    // authenticate ealier?
    mAuthFailed = false;

    // if we tried to authenticate ourselves last time
    if (mAuthHeader != null) {
      // we failed, if we must to authenticate again now and
      // we have a proxy-ness match
      mAuthFailed = (mustAuthenticate && isProxyAuthRequest == mAuthHeader.isProxy());

      // if we did NOT fail and last authentication request was a
      // proxy-authentication request
      if (!mAuthFailed && mAuthHeader.isProxy()) {
        Network network = Network.getInstance(mContext);
        // if we have a valid proxy set
        if (network.isValidProxySet()) {
          /* The proxy credentials can be read in the WebCore thread
           */
          synchronized (network) {
            // save authentication credentials for pre-emptive proxy
            // authentication
            network.setProxyUsername(mAuthHeader.getUsername());
            network.setProxyPassword(mAuthHeader.getPassword());
          }
        }
      }
    }
    // it is only here that we can reset the last mAuthHeader object
    // (if existed) and start a new one!!!
    mAuthHeader = null;
    if (mustAuthenticate) {
      if (mStatusCode == HTTP_AUTH) {
        mAuthHeader = parseAuthHeader(headers.getWwwAuthenticate());
      } else {
        mAuthHeader = parseAuthHeader(headers.getProxyAuthenticate());
        // if successfully parsed the header
        if (mAuthHeader != null) {
          // mark the auth-header object as a proxy
          mAuthHeader.setProxy();
        }
      }
    }

    // Only create a cache file if the server has responded positively.
    if ((mStatusCode == HTTP_OK
            || mStatusCode == HTTP_FOUND
            || mStatusCode == HTTP_MOVED_PERMANENTLY
            || mStatusCode == HTTP_TEMPORARY_REDIRECT)
        && mNativeLoader != 0) {
      // Content arriving from a StreamLoader (eg File, Cache or Data)
      // will not be cached as they have the header:
      // cache-control: no-store
      mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode, headers, mMimeType, false);
      if (mCacheResult != null) {
        mCacheResult.encoding = mEncoding;
      }
    }
    sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS));
  }