/**
   * If this looks like a POST request (form submission) containing a username and password, give
   * the user the option of saving them. Will either do nothing, or block until the UI interaction
   * is complete.
   *
   * <p>Called by startLoadingResource when using the Apache HTTP stack. Called directly by WebKit
   * when using the Chrome HTTP stack.
   *
   * @param postData The data about to be sent as the body of a POST request.
   * @param username The username entered by the user (sniffed from the DOM).
   * @param password The password entered by the user (sniffed from the DOM).
   */
  private void maybeSavePassword(byte[] postData, String username, String password) {
    if (postData == null
        || username == null
        || username.isEmpty()
        || password == null
        || password.isEmpty()) {
      return; // No password to save.
    }

    if (!mSettings.getSavePassword()) {
      return; // User doesn't want to save passwords.
    }

    try {
      if (DebugFlags.BROWSER_FRAME) {
        Assert.assertNotNull(mCallbackProxy.getBackForwardList().getCurrentItem());
      }
      WebAddress uri =
          new WebAddress(mCallbackProxy.getBackForwardList().getCurrentItem().getUrl());
      String schemePlusHost = uri.getScheme() + uri.getHost();
      // Check to see if the username & password appear in
      // the post data (there could be another form on the
      // page and that was posted instead.
      String postString = new String(postData);
      if (postString.contains(URLEncoder.encode(username))
          && postString.contains(URLEncoder.encode(password))) {
        String[] saved = mDatabase.getUsernamePassword(schemePlusHost);
        if (saved != null) {
          // null username implies that user has chosen not to
          // save password
          if (saved[0] != null) {
            // non-null username implies that user has
            // chosen to save password, so update the
            // recorded password
            mDatabase.setUsernamePassword(schemePlusHost, username, password);
          }
        } else {
          // CallbackProxy will handle creating the resume
          // message
          mCallbackProxy.onSavePassword(schemePlusHost, username, password, null);
        }
      }
    } catch (ParseException ex) {
      // if it is bad uri, don't save its password
    }
  }
  /**
   * Start loading a resource.
   *
   * @param loaderHandle The native ResourceLoader that is the target of the data.
   * @param url The url to load.
   * @param method The http method.
   * @param headers The http headers.
   * @param postData If the method is "POST" postData is sent as the request body. Is null when
   *     empty.
   * @param cacheMode The cache mode to use when loading this resource.
   * @param isHighPriority True if this resource needs to be put at the front of the network queue.
   * @param synchronous True if the load is synchronous.
   * @return A newly created LoadListener object.
   */
  private LoadListener startLoadingResource(
      int loaderHandle,
      String url,
      String method,
      HashMap headers,
      byte[] postData,
      int cacheMode,
      boolean isHighPriority,
      boolean synchronous) {
    PerfChecker checker = new PerfChecker();

    if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
      cacheMode = mSettings.getCacheMode();
    }

    if (method.equals("POST")) {
      // Don't use the cache on POSTs when issuing a normal POST
      // request.
      if (cacheMode == WebSettings.LOAD_NORMAL) {
        cacheMode = WebSettings.LOAD_NO_CACHE;
      }
      if (mSettings.getSavePassword() && hasPasswordField()) {
        try {
          if (WebView.DEBUG) {
            Assert.assertNotNull(mCallbackProxy.getBackForwardList().getCurrentItem());
          }
          WebAddress uri =
              new WebAddress(mCallbackProxy.getBackForwardList().getCurrentItem().getUrl());
          String schemePlusHost = uri.mScheme + uri.mHost;
          String[] ret = getUsernamePassword();
          // Has the user entered a username/password pair and is
          // there some POST data
          if (ret != null && postData != null && ret[0].length() > 0 && ret[1].length() > 0) {
            // Check to see if the username & password appear in
            // the post data (there could be another form on the
            // page and that was posted instead.
            String postString = new String(postData);
            if (postString.contains(URLEncoder.encode(ret[0]))
                && postString.contains(URLEncoder.encode(ret[1]))) {
              String[] saved = mDatabase.getUsernamePassword(schemePlusHost);
              if (saved != null) {
                // null username implies that user has chosen not to
                // save password
                if (saved[0] != null) {
                  // non-null username implies that user has
                  // chosen to save password, so update the
                  // recorded password
                  mDatabase.setUsernamePassword(schemePlusHost, ret[0], ret[1]);
                }
              } else {
                // CallbackProxy will handle creating the resume
                // message
                mCallbackProxy.onSavePassword(schemePlusHost, ret[0], ret[1], null);
              }
            }
          }
        } catch (ParseException ex) {
          // if it is bad uri, don't save its password
        }
      }
    }

    // is this resource the main-frame top-level page?
    boolean isMainFramePage = mIsMainFrame;

    if (WebView.LOGV_ENABLED) {
      Log.v(
          LOGTAG,
          "startLoadingResource: url="
              + url
              + ", method="
              + method
              + ", postData="
              + postData
              + ", isHighPriority="
              + isHighPriority
              + ", isMainFramePage="
              + isMainFramePage);
    }

    // Create a LoadListener
    LoadListener loadListener =
        LoadListener.getLoadListener(
            mContext, this, url, loaderHandle, synchronous, isMainFramePage);

    mCallbackProxy.onLoadResource(url);

    if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
      loadListener.error(
          android.net.http.EventHandler.ERROR,
          mContext.getString(com.android.internal.R.string.httpErrorTooManyRequests));
      loadListener.notifyError();
      loadListener.tearDown();
      return null;
    }

    // during synchronous load, the WebViewCore thread is blocked, so we
    // need to endCacheTransaction first so that http thread won't be
    // blocked in setupFile() when createCacheFile.
    if (synchronous) {
      CacheManager.endCacheTransaction();
    }

    FrameLoader loader = new FrameLoader(loadListener, mSettings, method, isHighPriority);
    loader.setHeaders(headers);
    loader.setPostData(postData);
    // Set the load mode to the mode used for the current page.
    // If WebKit wants validation, go to network directly.
    loader.setCacheMode(
        headers.containsKey("If-Modified-Since") || headers.containsKey("If-None-Match")
            ? WebSettings.LOAD_NO_CACHE
            : cacheMode);
    // Set referrer to current URL?
    if (!loader.executeLoad()) {
      checker.responseAlert("startLoadingResource fail");
    }
    checker.responseAlert("startLoadingResource succeed");

    if (synchronous) {
      CacheManager.startCacheTransaction();
    }

    return !synchronous ? loadListener : null;
  }