/** * Create a WebCore response object so that it can be used by nativeReceivedResponse or * nativeRedirectedToUrl * * @return native response pointer */ private int createNativeResponse() { // The reason we change HTTP_NOT_MODIFIED to HTTP_OK is because we know // that WebCore never sends the if-modified-since header. Our // CacheManager does it for us. If the server responds with a 304, then // we treat it like it was a 200 code and proceed with loading the file // from the cache. int statusCode = mStatusCode == HTTP_NOT_MODIFIED ? HTTP_OK : mStatusCode; // pass content-type content-length and content-encoding final int nativeResponse = nativeCreateResponse( mUrl, statusCode, mStatusText, mMimeType, mContentLength, mEncoding, mCacheResult == null ? 0 : mCacheResult.expires / 1000); if (mHeaders != null) { mHeaders.getHeaders( new Headers.HeaderCallback() { public void header(String name, String value) { nativeSetResponseHeader(nativeResponse, name, value); } }); } return nativeResponse; }
@Override public void endData() { Xlog.d(XLOGTAG, "endData::mStatusCode is: " + mStatusCode + this); if (mStatusCode == 200) { if (mPosterBytes.size() > 0) { Bitmap poster = BitmapFactory.decodeByteArray(mPosterBytes.toByteArray(), 0, mPosterBytes.size()); mProxy.doSetPoster(poster); } cleanup(); } else if (mStatusCode >= 300 && mStatusCode < 400) { // We have a redirect. try { mUrl = new URL(mHeaders.getLocation()); } catch (MalformedURLException e) { mUrl = null; } if (mUrl != null) { mHandler.post( new Runnable() { @Override public void run() { if (mRequestHandle != null) { mRequestHandle.setupRedirect( mUrl.toString(), mStatusCode, new HashMap<String, String>()); } } }); } } }
/* * This function is called from native WebCore code to * notify this LoadListener that the content it is currently * downloading should be saved to a file and not sent to * WebCore. */ void downloadFile() { // Setting the Cache Result to null ensures that this // content is not added to the cache mCacheResult = null; // Inform the client that they should download a file mBrowserFrame .getCallbackProxy() .onDownloadStart( url(), mBrowserFrame.getUserAgentString(), mHeaders.getContentDisposition(), mMimeType, mContentLength); // Cancel the download. We need to stop the http load. // The native loader object will get cleared by the call to // cancel() but will also be cleared on the WebCore side // when this function returns. cancel(); }
/* * 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); } }
/** * 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)); }