Home | History | Annotate | Download | only in webkit
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.webkit;
     18 
     19 import com.android.internal.R;
     20 
     21 import android.content.res.AssetManager;
     22 import android.net.http.EventHandler;
     23 import android.net.http.Headers;
     24 import android.util.Log;
     25 import android.util.TypedValue;
     26 
     27 import java.io.File;
     28 import java.io.FileInputStream;
     29 import java.lang.reflect.Field;
     30 
     31 /**
     32  * This class is a concrete implementation of StreamLoader that uses a
     33  * file or asset as the source for the stream.
     34  *
     35  */
     36 class FileLoader extends StreamLoader {
     37 
     38     private String mPath;  // Full path to the file to load
     39     private int mType;  // Indicates the type of the load
     40     private boolean mAllowFileAccess; // Allow/block file system access
     41 
     42     // used for files under asset directory
     43     static final int TYPE_ASSET = 1;
     44     // used for files under res directory
     45     static final int TYPE_RES = 2;
     46     // generic file
     47     static final int TYPE_FILE = 3;
     48 
     49     private static final String LOGTAG = "webkit";
     50 
     51     /**
     52      * Construct a FileLoader with the file URL specified as the content
     53      * source.
     54      *
     55      * @param url Full file url pointing to content to be loaded
     56      * @param loadListener LoadListener to pass the content to
     57      * @param asset true if url points to an asset.
     58      * @param allowFileAccess true if this WebView is allowed to access files
     59      *                        on the file system.
     60      */
     61     FileLoader(String url, LoadListener loadListener, int type,
     62             boolean allowFileAccess) {
     63         super(loadListener);
     64         mType = type;
     65         mAllowFileAccess = allowFileAccess;
     66 
     67         // clean the Url
     68         int index = url.indexOf('?');
     69         if (mType == TYPE_ASSET) {
     70             mPath = index > 0 ? URLUtil.stripAnchor(
     71                     url.substring(URLUtil.ASSET_BASE.length(), index)) :
     72                     URLUtil.stripAnchor(url.substring(
     73                             URLUtil.ASSET_BASE.length()));
     74         } else if (mType == TYPE_RES) {
     75             mPath = index > 0 ? URLUtil.stripAnchor(
     76                     url.substring(URLUtil.RESOURCE_BASE.length(), index)) :
     77                     URLUtil.stripAnchor(url.substring(
     78                             URLUtil.RESOURCE_BASE.length()));
     79         } else {
     80             mPath = index > 0 ? URLUtil.stripAnchor(
     81                     url.substring(URLUtil.FILE_BASE.length(), index)) :
     82                     URLUtil.stripAnchor(url.substring(
     83                             URLUtil.FILE_BASE.length()));
     84         }
     85     }
     86 
     87     private String errString(Exception ex) {
     88         String exMessage = ex.getMessage();
     89         String errString = mContext.getString(R.string.httpErrorFileNotFound);
     90         if (exMessage != null) {
     91             errString += " " + exMessage;
     92         }
     93         return errString;
     94     }
     95 
     96     @Override
     97     protected boolean setupStreamAndSendStatus() {
     98         try {
     99             if (mType == TYPE_ASSET) {
    100                 try {
    101                     mDataStream = mContext.getAssets().open(mPath);
    102                 } catch (java.io.FileNotFoundException ex) {
    103                     // try the rest files included in the package
    104                     mDataStream = mContext.getAssets().openNonAsset(mPath);
    105                 }
    106             } else if (mType == TYPE_RES) {
    107                 // get the resource id from the path. e.g. for the path like
    108                 // drawable/foo.png, the id is located at field "foo" of class
    109                 // "<package>.R$drawable"
    110                 if (mPath == null || mPath.length() == 0) {
    111                     Log.e(LOGTAG, "Need a path to resolve the res file");
    112                     mLoadListener.error(EventHandler.FILE_ERROR, mContext
    113                             .getString(R.string.httpErrorFileNotFound));
    114                     return false;
    115 
    116                 }
    117                 int slash = mPath.indexOf('/');
    118                 int dot = mPath.indexOf('.', slash);
    119                 if (slash == -1 || dot == -1) {
    120                     Log.e(LOGTAG, "Incorrect res path: " + mPath);
    121                     mLoadListener.error(EventHandler.FILE_ERROR, mContext
    122                             .getString(R.string.httpErrorFileNotFound));
    123                     return false;
    124                 }
    125                 String subClassName = mPath.substring(0, slash);
    126                 String fieldName = mPath.substring(slash + 1, dot);
    127                 String errorMsg = null;
    128                 try {
    129                     final Class<?> d = mContext.getApplicationContext()
    130                             .getClassLoader().loadClass(
    131                                     mContext.getPackageName() + ".R$"
    132                                             + subClassName);
    133                     final Field field = d.getField(fieldName);
    134                     final int id = field.getInt(null);
    135                     TypedValue value = new TypedValue();
    136                     mContext.getResources().getValue(id, value, true);
    137                     if (value.type == TypedValue.TYPE_STRING) {
    138                         mDataStream = mContext.getAssets().openNonAsset(
    139                                 value.assetCookie, value.string.toString(),
    140                                 AssetManager.ACCESS_STREAMING);
    141                     } else {
    142                         errorMsg = "Only support TYPE_STRING for the res files";
    143                     }
    144                 } catch (ClassNotFoundException e) {
    145                     errorMsg = "Can't find class:  "
    146                             + mContext.getPackageName() + ".R$" + subClassName;
    147                 } catch (SecurityException e) {
    148                     errorMsg = "Caught SecurityException: " + e;
    149                 } catch (NoSuchFieldException e) {
    150                     errorMsg = "Can't find field:  " + fieldName + " in "
    151                             + mContext.getPackageName() + ".R$" + subClassName;
    152                 } catch (IllegalArgumentException e) {
    153                     errorMsg = "Caught IllegalArgumentException: " + e;
    154                 } catch (IllegalAccessException e) {
    155                     errorMsg = "Caught IllegalAccessException: " + e;
    156                 }
    157                 if (errorMsg != null) {
    158                     mLoadListener.error(EventHandler.FILE_ERROR, mContext
    159                             .getString(R.string.httpErrorFileNotFound));
    160                     return false;
    161                 }
    162             } else {
    163                 if (!mAllowFileAccess) {
    164                     mLoadListener.error(EventHandler.FILE_ERROR,
    165                             mContext.getString(R.string.httpErrorFileNotFound));
    166                     return false;
    167                 }
    168 
    169                 mDataStream = new FileInputStream(mPath);
    170                 mContentLength = (new File(mPath)).length();
    171             }
    172             mLoadListener.status(1, 1, 200, "OK");
    173 
    174         } catch (java.io.FileNotFoundException ex) {
    175             mLoadListener.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex));
    176             return false;
    177 
    178         } catch (java.io.IOException ex) {
    179             mLoadListener.error(EventHandler.FILE_ERROR, errString(ex));
    180             return false;
    181         }
    182         return true;
    183     }
    184 
    185     @Override
    186     protected void buildHeaders(Headers headers) {
    187         // do nothing.
    188     }
    189 }
    190