FileDocCategorySizeDatePackage
FrameLoader.javaAPI DocAndroid 1.5 API13886Wed May 06 22:41:56 BST 2009android.webkit

FrameLoader

public class FrameLoader extends Object

Fields Summary
private final LoadListener
mListener
private final String
mMethod
private final boolean
mIsHighPriority
private final WebSettings
mSettings
private Map
mHeaders
private byte[]
mPostData
private Network
mNetwork
private int
mCacheMode
private String
mReferrer
private String
mContentType
private static final int
URI_PROTOCOL
private static final String
CONTENT_TYPE
private static final String
mAboutBlank
static final String
HEADER_STR
private static final String
LOGTAG
Constructors Summary
FrameLoader(LoadListener listener, WebSettings settings, String method, boolean highPriority)

    
       
                
        mListener = listener;
        mHeaders = null;
        mMethod = method;
        mIsHighPriority = highPriority;
        mCacheMode = WebSettings.LOAD_NORMAL;
        mSettings = settings;
    
Methods Summary
public booleanexecuteLoad()
Issues the load request. Return value does not indicate if the load was successful or not. It simply indicates that the load request is reasonable.

return
true if the load is reasonable.

        String url = mListener.url();

        // Attempt to decode the percent-encoded url.
        try {
            url = new String(URLUtil.decode(url.getBytes()));
        } catch (IllegalArgumentException e) {
            // Fail with a bad url error if the decode fails.
            mListener.error(EventHandler.ERROR_BAD_URL,
                    mListener.getContext().getString(
                            com.android.internal.R.string.httpErrorBadUrl));
            return false;
        }

        if (URLUtil.isNetworkUrl(url)){
            if (mSettings.getBlockNetworkLoads()) {
                mListener.error(EventHandler.ERROR_BAD_URL,
                        mListener.getContext().getString(
                                com.android.internal.R.string.httpErrorBadUrl));
                return false;
            }
            mNetwork = Network.getInstance(mListener.getContext());
            return handleHTTPLoad();
        } else if (handleLocalFile(url, mListener, mSettings)) {
            return true;
        }
        if (Config.LOGV) {
            Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
                    + mListener.url());
        }
        mListener.error(EventHandler.ERROR_UNSUPPORTED_SCHEME,
                mListener.getContext().getText(
                        com.android.internal.R.string.httpErrorUnsupportedScheme).toString());
        return false;

    
public LoadListenergetLoadListener()

        return mListener;
    
private booleanhandleCache()

        switch (mCacheMode) {
            // This mode is normally used for a reload, it instructs the http
            // loader to not use the cached content.
            case WebSettings.LOAD_NO_CACHE:
                break;
                
                
            // This mode is used when the content should only be loaded from
            // the cache. If it is not there, then fail the load. This is used
            // to load POST content in a history navigation.
            case WebSettings.LOAD_CACHE_ONLY: {
                CacheResult result = CacheManager.getCacheFile(mListener.url(),
                        null);
                if (result != null) {
                    startCacheLoad(result);
                } else {
                    // This happens if WebCore was first told that the POST
                    // response was in the cache, then when we try to use it
                    // it has gone.
                    // Generate a file not found error
                    int err = EventHandler.FILE_NOT_FOUND_ERROR;
                    mListener.error(err, mListener.getContext().getText(
                            EventHandler.errorStringResources[Math.abs(err)])
                            .toString());
                }
                return true;
            }

            // This mode is for when the user is doing a history navigation
            // in the browser and should returned cached content regardless
            // of it's state. If it is not in the cache, then go to the 
            // network.
            case WebSettings.LOAD_CACHE_ELSE_NETWORK: {
                if (Config.LOGV) {
                    Log.v(LOGTAG, "FrameLoader: checking cache: "
                            + mListener.url());
                }
                // Get the cache file name for the current URL, passing null for
                // the validation headers causes no validation to occur
                CacheResult result = CacheManager.getCacheFile(mListener.url(),
                        null);
                if (result != null) {
                    startCacheLoad(result);
                    return true;
                }
                break;
            }

            // This is the default case, which is to check to see if the
            // content in the cache can be used. If it can be used, then
            // use it. If it needs revalidation then the relevant headers
            // are added to the request.
            default:
            case WebSettings.LOAD_NORMAL:
                return mListener.checkCache(mHeaders);
        }// end of switch

        return false;
    
private booleanhandleHTTPLoad()

        if (mHeaders == null) {
            mHeaders = new HashMap<String, String>();
        }
        populateStaticHeaders();
        populateHeaders();

        // response was handled by UrlIntercept, don't issue HTTP request
        if (handleUrlIntercept()) return true;

        // response was handled by Cache, don't issue HTTP request
        if (handleCache()) {
            // push the request data down to the LoadListener
            // as response from the cache could be a redirect
            // and we may need to initiate a network request if the cache
            // can't satisfy redirect URL
            mListener.setRequestData(mMethod, mHeaders, mPostData, 
                    mIsHighPriority);
            return true;
        }

        if (Config.LOGV) {
            Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
                    + mListener.url());
        }

        boolean ret = false;
        int error = EventHandler.ERROR_UNSUPPORTED_SCHEME;
        
        try {
            ret = mNetwork.requestURL(mMethod, mHeaders,
                    mPostData, mListener, mIsHighPriority);
        } catch (android.net.ParseException ex) {
            error = EventHandler.ERROR_BAD_URL;
        } catch (java.lang.RuntimeException ex) {
            /* probably an empty header set by javascript.  We want
               the same result as bad URL  */
            error = EventHandler.ERROR_BAD_URL;
        }
        if (!ret) {
            mListener.error(error, mListener.getContext().getText(
                    EventHandler.errorStringResources[Math.abs(error)]).toString());
            return false;
        }
        return true;
    
static booleanhandleLocalFile(java.lang.String url, LoadListener loadListener, WebSettings settings)

        if (URLUtil.isAssetUrl(url)) {
            FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
                    true, settings.getAllowFileAccess());
            return true;
        } else if (URLUtil.isFileUrl(url)) {
            FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
                    false, settings.getAllowFileAccess());
            return true;
        } else if (URLUtil.isContentUrl(url)) {
            // Send the raw url to the ContentLoader because it will do a
            // permission check and the url has to match..
            ContentLoader.requestUrl(loadListener.url(), loadListener,
                                     loadListener.getContext());
            return true;
        } else if (URLUtil.isDataUrl(url)) {
            DataLoader.requestUrl(url, loadListener);
            return true;
        } else if (URLUtil.isAboutUrl(url)) {
            loadListener.data(mAboutBlank.getBytes(), mAboutBlank.length());
            loadListener.endData();
            return true;
        }
        return false;
    
private booleanhandleUrlIntercept()

        // Check if the URL can be served from UrlIntercept. If
        // successful, return the data just like a cache hit.

        PluginData data = UrlInterceptRegistry.getPluginData(
                mListener.url(), mHeaders);

        if(data != null) {
            PluginContentLoader loader =
                    new PluginContentLoader(mListener, data);
            loader.load();
            return true;
        }
        // Not intercepted. Carry on as normal.
        return false;
    
private voidpopulateHeaders()
Add the content related headers. These headers contain user private data and is not used when we are proxying an untrusted request.

        
        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);
        }
    
private voidpopulateStaticHeaders()
Add the static headers that don't change with each request.

        // Accept header should already be there as they are built by WebCore,
        // but in the case they are missing, add some.
        String accept = mHeaders.get("Accept");
        if (accept == null || accept.length() == 0) {
            mHeaders.put("Accept", HEADER_STR);
        }
        mHeaders.put("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");

        String acceptLanguage = mSettings.getAcceptLanguage();
        if (acceptLanguage.length() > 0) {
            mHeaders.put("Accept-Language", acceptLanguage);
        }
        
        mHeaders.put("User-Agent", mSettings.getUserAgentString());
    
public voidsetCacheMode(int cacheMode)

        mCacheMode = cacheMode;
    
public voidsetContentTypeForPost(java.lang.String postContentType)

        mContentType = postContentType;
    
public voidsetHeaders(java.util.HashMap headers)

        mHeaders = headers;
    
public voidsetPostData(byte[] postData)

        mPostData = postData;
    
public voidsetReferrer(java.lang.String ref)

        // only set referrer for http or https
        if (URLUtil.isNetworkUrl(ref)) mReferrer = ref;
    
private voidstartCacheLoad(android.webkit.CacheManager.CacheResult result)

        if (Config.LOGV) {
            Log.v(LOGTAG, "FrameLoader: loading from cache: "
                  + mListener.url());
        }
        // Tell the Listener respond with the cache file
        CacheLoader cacheLoader =
                new CacheLoader(mListener, result);
        mListener.setCacheLoader(cacheLoader);
        cacheLoader.load();