/** * 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(); }