summaryrefslogtreecommitdiffstats
path: root/core/java/android/webkit/FrameLoader.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch)
treed88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/webkit/FrameLoader.java
parentd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff)
downloadframeworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/webkit/FrameLoader.java')
-rw-r--r--core/java/android/webkit/FrameLoader.java370
1 files changed, 370 insertions, 0 deletions
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
new file mode 100644
index 0000000..5e323eb
--- /dev/null
+++ b/core/java/android/webkit/FrameLoader.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.net.http.EventHandler;
+import android.net.http.RequestHandle;
+import android.util.Config;
+import android.util.Log;
+import android.webkit.CacheManager.CacheResult;
+import android.webkit.UrlInterceptRegistry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class FrameLoader {
+
+ private final LoadListener mListener;
+ private final String mMethod;
+ private final boolean mIsHighPriority;
+ private final WebSettings mSettings;
+ private Map<String, String> mHeaders;
+ private byte[] mPostData;
+ private Network mNetwork;
+ private int mCacheMode;
+ private String mReferrer;
+ private String mContentType;
+
+ private static final int URI_PROTOCOL = 0x100;
+
+ private static final String CONTENT_TYPE = "content-type";
+
+ // Contents of an about:blank page
+ private static final String mAboutBlank =
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EB\">" +
+ "<html><head><title>about:blank</title></head><body></body></html>";
+
+ static final String HEADER_STR = "text/xml, text/html, " +
+ "application/xhtml+xml, image/png, text/plain, */*;q=0.8";
+
+ private static final String LOGTAG = "webkit";
+
+ FrameLoader(LoadListener listener, WebSettings settings,
+ String method, boolean highPriority) {
+ mListener = listener;
+ mHeaders = null;
+ mMethod = method;
+ mIsHighPriority = highPriority;
+ mCacheMode = WebSettings.LOAD_NORMAL;
+ mSettings = settings;
+ }
+
+ public void setReferrer(String ref) {
+ // only set referrer for http or https
+ if (URLUtil.isNetworkUrl(ref)) mReferrer = ref;
+ }
+
+ public void setPostData(byte[] postData) {
+ mPostData = postData;
+ }
+
+ public void setContentTypeForPost(String postContentType) {
+ mContentType = postContentType;
+ }
+
+ public void setCacheMode(int cacheMode) {
+ mCacheMode = cacheMode;
+ }
+
+ public void setHeaders(HashMap headers) {
+ mHeaders = headers;
+ }
+
+ public LoadListener getLoadListener() {
+ return mListener;
+ }
+
+ /**
+ * 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.
+ */
+ public boolean executeLoad() {
+ 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;
+
+ }
+
+ /* package */
+ static boolean handleLocalFile(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 boolean handleHTTPLoad() {
+ 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;
+ }
+
+ /*
+ * This function is used by handleUrlInterecpt and handleCache to
+ * setup a load from the byte stream in a CacheResult.
+ */
+ private void startCacheLoad(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();
+ }
+
+ /*
+ * This function is used by handleHTTPLoad to allow URL
+ * interception. This can be used to provide alternative load
+ * methods such as locally stored versions or for debugging.
+ *
+ * Returns true if the response was handled by UrlIntercept.
+ */
+ private boolean handleUrlIntercept() {
+ // Check if the URL can be served from UrlIntercept. If
+ // successful, return the data just like a cache hit.
+ CacheResult result = UrlInterceptRegistry.getSurrogate(
+ mListener.url(), mHeaders);
+ if(result != null) {
+ // Intercepted. The data is stored in result.stream. Setup
+ // a load from the CacheResult.
+ startCacheLoad(result);
+ return true;
+ }
+ // Not intercepted. Carry on as normal.
+ return false;
+ }
+
+ /*
+ * This function is used by the handleHTTPLoad to setup the cache headers
+ * correctly.
+ * Returns true if the response was handled from the cache
+ */
+ private boolean handleCache() {
+ 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;
+ }
+
+ /**
+ * Add the static headers that don't change with each request.
+ */
+ private void populateStaticHeaders() {
+ // 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());
+ }
+
+ /**
+ * 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);
+ }
+ }
+}