コード例 #1
0
  /**
   * Add data to the internal collection of data. This function is used by the data: scheme, about:
   * scheme and http/https schemes.
   *
   * @param data A byte array containing the content.
   * @param length The length of data. IMPORTANT: as this is called from network thread, can't call
   *     native directly
   */
  public void data(byte[] data, int length) {
    if (Config.LOGV) {
      Log.v(LOGTAG, "LoadListener.data(): url: " + url());
    }

    if (ignoreCallbacks()) {
      return;
    }

    // Decode base64 data
    // Note: It's fine that we only decode base64 here and not in the other
    // data call because the only caller of the stream version is not
    // base64 encoded.
    if ("base64".equalsIgnoreCase(mTransferEncoding)) {
      if (length < data.length) {
        byte[] trimmedData = new byte[length];
        System.arraycopy(data, 0, trimmedData, 0, length);
        data = trimmedData;
      }
      data = Base64.decodeBase64(data);
      length = data.length;
    }
    // Synchronize on mData because commitLoad may write mData to WebCore
    // and we don't want to replace mData or mDataLength at the same time
    // as a write.
    boolean sendMessage = false;
    synchronized (mDataBuilder) {
      sendMessage = mDataBuilder.isEmpty();
      mDataBuilder.append(data, 0, length);
    }
    if (sendMessage) {
      // Send a message whenever data comes in after a write to WebCore
      sendMessageInternal(obtainMessage(MSG_CONTENT_DATA));
    }
  }
コード例 #2
0
 /**
  * Implementation of error handler for EventHandler. Subclasses should call this method to have
  * error fields set.
  *
  * @param id The error id described by EventHandler.
  * @param description A string description of the error. IMPORTANT: as this is called from network
  *     thread, can't call native directly
  */
 public void error(int id, String description) {
   mErrorID = id;
   mErrorDescription = description;
   sendMessageInternal(obtainMessage(MSG_CONTENT_ERROR));
   if (Config.LOGV) {
     Log.v(
         LOGTAG, "LoadListener.error url:" + url() + " id:" + id + " description:" + description);
   }
   detachRequestHandle();
 }
コード例 #3
0
  /**
   * 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();
  }
コード例 #4
0
  /**
   * 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));
  }