/**
   * Add the content related headers. These headers contain user private data and is not used when
   * we are proxying an untrusted request.
   */
  private void populateHeaders() {

    if (mReferrer != null) mHeaders.put("Referer", mReferrer);
    if (mContentType != null) mHeaders.put(CONTENT_TYPE, mContentType);

    // if we have an active proxy and have proxy credentials, do pre-emptive
    // authentication to avoid an extra round-trip:
    if (mNetwork.isValidProxySet()) {
      String username;
      String password;
      /* The proxy credentials can be set in the Network thread */
      synchronized (mNetwork) {
        username = mNetwork.getProxyUsername();
        password = mNetwork.getProxyPassword();
      }
      if (username != null && password != null) {
        // we collect credentials ONLY if the proxy scheme is BASIC!!!
        String proxyHeader = RequestHandle.authorizationHeader(true);
        mHeaders.put(
            proxyHeader, "Basic " + RequestHandle.computeBasicAuthResponse(username, password));
      }
    }

    // Set cookie header
    String cookie = CookieManager.getInstance().getCookie(mListener.getWebAddress());
    if (cookie != null && cookie.length() > 0) {
      mHeaders.put("Cookie", cookie);
    }
  }
 // Cancel the download if active and release the queue. Called on WebCore thread.
 public void cancelAndReleaseQueue() {
   if (mRequestHandle != null) {
     mRequestHandle.cancel();
     mRequestHandle = null;
   }
   releaseQueue();
 }
  /** Uses user-supplied credentials to restar a request. */
  void handleAuthResponse(String username, String password) {
    if (Config.LOGV) {
      Log.v(
          LOGTAG,
          "LoadListener.handleAuthResponse: url: "
              + mUrl
              + " username: "******" password: "
              + password);
    }

    // create and queue an authentication-response
    if (username != null && password != null) {
      if (mAuthHeader != null && mRequestHandle != null) {
        mAuthHeader.setUsername(username);
        mAuthHeader.setPassword(password);

        int scheme = mAuthHeader.getScheme();
        if (scheme == HttpAuthHeader.BASIC) {
          // create a basic response
          boolean isProxy = mAuthHeader.isProxy();

          mRequestHandle.setupBasicAuthResponse(isProxy, username, password);
        } else {
          if (scheme == HttpAuthHeader.DIGEST) {
            // create a digest response
            boolean isProxy = mAuthHeader.isProxy();

            String realm = mAuthHeader.getRealm();
            String nonce = mAuthHeader.getNonce();
            String qop = mAuthHeader.getQop();
            String algorithm = mAuthHeader.getAlgorithm();
            String opaque = mAuthHeader.getOpaque();

            mRequestHandle.setupDigestAuthResponse(
                isProxy, username, password, realm, nonce, qop, algorithm, opaque);
          }
        }
      }
    }
  }
  /**
   * Cancel a request. FIXME: This will only work if the request has yet to be handled. This is in
   * no way guarenteed if requests are served in a separate thread. It also causes major problems if
   * cancel is called during an EventHandler's method call.
   */
  public void cancel() {
    if (Config.LOGV) {
      if (mRequestHandle == null) {
        Log.v(LOGTAG, "LoadListener.cancel(): no requestHandle");
      } else {
        Log.v(LOGTAG, "LoadListener.cancel()");
      }
    }
    if (mRequestHandle != null) {
      mRequestHandle.cancel();
      mRequestHandle = null;
    }

    mCacheResult = null;
    mCancelled = true;

    clearNativeLoader();
  }
  /*
   * Perform the actual redirection. This involves setting up the new URL,
   * informing WebCore and then telling the Network to start loading again.
   */
  private void doRedirect() {
    // as cancel() can cancel the load before doRedirect() is
    // called through handleMessage, needs to check to see if we
    // are canceled before proceed
    if (mCancelled) {
      return;
    }

    String redirectTo = mHeaders.getLocation();
    if (redirectTo != null) {
      int nativeResponse = createNativeResponse();
      redirectTo = nativeRedirectedToUrl(mUrl, redirectTo, nativeResponse);
      // nativeRedirectedToUrl() may call cancel(), e.g. when redirect
      // from a https site to a http site, check mCancelled again
      if (mCancelled) {
        return;
      }
      if (redirectTo == null) {
        Log.d(LOGTAG, "Redirection failed for " + mHeaders.getLocation());
        cancel();
        return;
      } else if (!URLUtil.isNetworkUrl(redirectTo)) {
        final String text =
            mContext.getString(com.android.internal.R.string.open_permission_deny)
                + "\n"
                + redirectTo;
        nativeAddData(text.getBytes(), text.length());
        nativeFinished();
        clearNativeLoader();
        return;
      }

      if (mOriginalUrl == null) {
        mOriginalUrl = mUrl;
      }

      // Cache the redirect response
      if (mCacheResult != null) {
        if (getErrorID() == OK) {
          CacheManager.saveCacheFile(mUrl, mCacheResult);
        }
        mCacheResult = null;
      }

      setUrl(redirectTo);

      // Redirect may be in the cache
      if (mRequestHeaders == null) {
        mRequestHeaders = new HashMap<String, String>();
      }
      if (!checkCache(mRequestHeaders)) {
        // mRequestHandle can be null when the request was satisfied
        // by the cache, and the cache returned a redirect
        if (mRequestHandle != null) {
          mRequestHandle.setupRedirect(redirectTo, mStatusCode, mRequestHeaders);
        } else {
          String method = mMethod;

          if (method == null) {
            return;
          }

          Network network = Network.getInstance(getContext());
          network.requestURL(method, mRequestHeaders, mPostData, this, mIsHighPriority);
        }
      }
    } else {
      cancel();
    }

    if (Config.LOGV) {
      Log.v(LOGTAG, "LoadListener.onRedirect(): redirect to: " + redirectTo);
    }
  }
 /**
  * Handles SSL error(s) on the way down from the user (the user has already provided their
  * feedback).
  */
 void handleSslErrorResponse(boolean proceed) {
   if (mRequestHandle != null) {
     mRequestHandle.handleSslErrorResponse(proceed);
   }
 }
  /**
   * Event handler's endData call. Send a message to the handler notifying them that the data has
   * finished. IMPORTANT: as this is called from network thread, can't call native directly
   */
  public void endData() {
    if (Config.LOGV) {
      Log.v(LOGTAG, "LoadListener.endData(): url: " + url());
    }

    if (mCancelled) return;

    switch (mStatusCode) {
      case HTTP_MOVED_PERMANENTLY:
        // 301 - permanent redirect
        mPermanent = true;
      case HTTP_FOUND:
      case HTTP_SEE_OTHER:
      case HTTP_TEMPORARY_REDIRECT:
        if (mMethod == null && mRequestHandle == null) {
          Log.e(LOGTAG, "LoadListener.endData(): method is null!");
          Log.e(LOGTAG, "LoadListener.endData(): url = " + url());
        }
        // 301, 302, 303, and 307 - redirect
        if (mStatusCode == HTTP_TEMPORARY_REDIRECT) {
          if (mRequestHandle != null && mRequestHandle.getMethod().equals("POST")) {
            sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED_REQUEST));
          } else if (mMethod != null && mMethod.equals("POST")) {
            sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED_REQUEST));
          } else {
            sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED));
          }
        } else {
          sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED));
        }
        return;

      case HTTP_AUTH:
      case HTTP_PROXY_AUTH:
        // According to rfc2616, the response for HTTP_AUTH must include
        // WWW-Authenticate header field and the response for
        // HTTP_PROXY_AUTH must include Proxy-Authenticate header field.
        if (mAuthHeader != null
            && (Network.getInstance(mContext).isValidProxySet() || !mAuthHeader.isProxy())) {
          Network.getInstance(mContext).handleAuthRequest(this);
          return;
        }
        break; // use default

      case HTTP_NOT_MODIFIED:
        // Server could send back NOT_MODIFIED even if we didn't
        // ask for it, so make sure we have a valid CacheLoader
        // before calling it.
        if (mCacheLoader != null) {
          detachRequestHandle();
          mCacheLoader.load();
          if (Config.LOGV) {
            Log.v(LOGTAG, "LoadListener cache load url=" + url());
          }
          return;
        }
        break; // use default

      case HTTP_NOT_FOUND:
        // Not an error, the server can send back content.
      default:
        break;
    }

    sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
    detachRequestHandle();
  }