Back to index

lightning-sunbird  0.9+nobinonly
nsFileProtocolHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 // vim:ts=4 sw=4 sts=4 et cin:
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Rich Walsh <dragtext@e-vertise.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsFileProtocolHandler.h"
00041 #include "nsFileChannel.h"
00042 #include "nsInputStreamChannel.h"
00043 #include "nsStandardURL.h"
00044 #include "nsURLHelper.h"
00045 #include "nsNetCID.h"
00046 
00047 #include "nsIServiceManager.h"
00048 #include "nsIURL.h"
00049 
00050 #include "nsNetUtil.h"
00051 
00052 // URL file handling, copied and modified from xpfe/components/bookmarks/src/nsBookmarksService.cpp
00053 #ifdef XP_WIN
00054 #include <shlobj.h>
00055 #include <intshcut.h>
00056 #include "nsIFileURL.h"
00057 #ifdef CompareString
00058 #undef CompareString
00059 #endif
00060 #endif
00061 
00062 // URL file handling for OS/2
00063 #ifdef XP_OS2
00064 #include "prio.h"
00065 #include "nsIFileURL.h"
00066 #include "nsILocalFileOS2.h"
00067 #endif
00068 
00069 //-----------------------------------------------------------------------------
00070 
00071 nsFileProtocolHandler::nsFileProtocolHandler()
00072 {
00073 }
00074 
00075 nsresult
00076 nsFileProtocolHandler::Init()
00077 {
00078     return NS_OK;
00079 }
00080 
00081 NS_IMPL_THREADSAFE_ISUPPORTS3(nsFileProtocolHandler,
00082                               nsIFileProtocolHandler,
00083                               nsIProtocolHandler,
00084                               nsISupportsWeakReference)
00085 
00086 //-----------------------------------------------------------------------------
00087 // nsIProtocolHandler methods:
00088 
00089 #if defined(XP_WIN)
00090 NS_IMETHODIMP
00091 nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
00092 {
00093 // IUniformResourceLocator isn't supported by VC5 (bless its little heart)
00094 #if _MSC_VER < 1200 || defined (WINCE)
00095     return NS_ERROR_NOT_AVAILABLE;
00096 #else
00097     nsAutoString path;
00098     nsresult rv = aFile->GetPath(path);
00099     if (NS_FAILED(rv))
00100         return rv;
00101 
00102     if (path.Length() < 4)
00103         return NS_ERROR_NOT_AVAILABLE;
00104     if (!StringTail(path, 4).LowerCaseEqualsLiteral(".url"))
00105         return NS_ERROR_NOT_AVAILABLE;
00106 
00107     HRESULT result;
00108 
00109     rv = NS_ERROR_NOT_AVAILABLE;
00110 
00111     IUniformResourceLocator* urlLink = nsnull;
00112     result = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
00113                                 IID_IUniformResourceLocator, (void**)&urlLink);
00114     if (SUCCEEDED(result) && urlLink) {
00115         IPersistFile* urlFile = nsnull;
00116         result = urlLink->QueryInterface(IID_IPersistFile, (void**)&urlFile);
00117         if (SUCCEEDED(result) && urlFile) {
00118             result = urlFile->Load(path.get(), STGM_READ);
00119             if (SUCCEEDED(result) ) {
00120                 LPSTR lpTemp = nsnull;
00121 
00122                 // The URL this method will give us back seems to be already
00123                 // escaped. Hence, do not do escaping of our own.
00124                 result = urlLink->GetURL(&lpTemp);
00125                 if (SUCCEEDED(result) && lpTemp) {
00126                     rv = NS_NewURI(aURI, lpTemp);
00127 
00128                     // free the string that GetURL alloc'd
00129                     CoTaskMemFree(lpTemp);
00130                 }
00131             }
00132             urlFile->Release();
00133         }
00134         urlLink->Release();
00135     }
00136     return rv;
00137 
00138 #endif //_MSC_VER < 1200 || defined (WINCE)
00139 }
00140 
00141 #elif defined(XP_OS2)
00142 NS_IMETHODIMP
00143 nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
00144 {
00145     nsresult rv;
00146 
00147     nsCOMPtr<nsILocalFileOS2> os2File (do_QueryInterface(aFile, &rv));
00148     if (NS_FAILED(rv))
00149         return NS_ERROR_NOT_AVAILABLE;
00150 
00151     // see if this file is a WPS UrlObject
00152     PRBool isUrl;
00153     rv = os2File->IsFileType(NS_LITERAL_CSTRING("UniformResourceLocator"),
00154                              &isUrl);
00155     if (NS_FAILED(rv) || !isUrl)
00156         return NS_ERROR_NOT_AVAILABLE;
00157 
00158     // if so, open it & get its size
00159     PRFileDesc *file;
00160     rv = os2File->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
00161     if (NS_FAILED(rv))
00162         return NS_ERROR_NOT_AVAILABLE;
00163 
00164     PRInt64 fileSize;
00165     os2File->GetFileSize(&fileSize);
00166     rv = NS_ERROR_NOT_AVAILABLE;
00167 
00168     // get a buffer, read the entire file, then create
00169     // an nsURI;  we assume the string is already escaped
00170     char * buffer = (char*)NS_Alloc(fileSize+1);
00171     if (buffer) {
00172         PRInt32 cnt = PR_Read(file, buffer, fileSize);
00173         if (cnt > 0) {
00174             buffer[cnt] = '\0';
00175             if (NS_SUCCEEDED(NS_NewURI(aURI, nsDependentCString(buffer))))
00176                 rv = NS_OK;
00177         }
00178         NS_Free(buffer);
00179     }
00180     PR_Close(file);
00181 
00182     return rv;
00183 }
00184 
00185 #else // other platforms
00186 NS_IMETHODIMP
00187 nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
00188 {
00189     return NS_ERROR_NOT_AVAILABLE;
00190 }
00191 #endif // ReadURLFile()
00192 
00193 NS_IMETHODIMP
00194 nsFileProtocolHandler::GetScheme(nsACString &result)
00195 {
00196     result.AssignLiteral("file");
00197     return NS_OK;
00198 }
00199 
00200 NS_IMETHODIMP
00201 nsFileProtocolHandler::GetDefaultPort(PRInt32 *result)
00202 {
00203     *result = -1;        // no port for file: URLs
00204     return NS_OK;
00205 }
00206 
00207 NS_IMETHODIMP
00208 nsFileProtocolHandler::GetProtocolFlags(PRUint32 *result)
00209 {
00210     *result = URI_NOAUTH;
00211     return NS_OK;
00212 }
00213 
00214 NS_IMETHODIMP
00215 nsFileProtocolHandler::NewURI(const nsACString &spec,
00216                               const char *charset,
00217                               nsIURI *baseURI,
00218                               nsIURI **result)
00219 {
00220     nsCOMPtr<nsIStandardURL> url = new nsStandardURL(PR_TRUE);
00221     if (!url)
00222         return NS_ERROR_OUT_OF_MEMORY;
00223 
00224     const nsACString *specPtr = &spec;
00225 
00226 #if defined(XP_WIN) || defined(XP_OS2)
00227     nsCAutoString buf;
00228     if (net_NormalizeFileURL(spec, buf))
00229         specPtr = &buf;
00230 #endif
00231 
00232     nsresult rv = url->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
00233                             *specPtr, charset, baseURI);
00234     if (NS_FAILED(rv)) return rv;
00235 
00236     return CallQueryInterface(url, result);
00237 }
00238 
00239 NS_IMETHODIMP
00240 nsFileProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result)
00241 {
00242     // This file may be a url file
00243     nsCOMPtr<nsIFileURL> url(do_QueryInterface(uri));
00244     if (url) {
00245         nsCOMPtr<nsIFile> file;
00246         nsresult rv = url->GetFile(getter_AddRefs(file));
00247         if (NS_SUCCEEDED(rv)) {
00248             nsCOMPtr<nsIURI> uri;
00249             rv = ReadURLFile(file, getter_AddRefs(uri));
00250             if (NS_SUCCEEDED(rv)) {
00251                 rv = NS_NewChannel(result, uri);
00252                 if (NS_SUCCEEDED(rv))
00253                     return rv;
00254             }
00255         }
00256     }
00257 
00258     nsFileChannel *chan = new nsFileChannel();
00259     if (!chan)
00260         return NS_ERROR_OUT_OF_MEMORY;
00261     NS_ADDREF(chan);
00262 
00263     nsresult rv = chan->Init(uri);
00264     if (NS_FAILED(rv)) {
00265         NS_RELEASE(chan);
00266         return rv;
00267     }
00268 
00269     *result = chan;
00270     return NS_OK;
00271 }
00272 
00273 NS_IMETHODIMP 
00274 nsFileProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *result)
00275 {
00276     // don't override anything.  
00277     *result = PR_FALSE;
00278     return NS_OK;
00279 }
00280 
00281 //-----------------------------------------------------------------------------
00282 // nsIFileProtocolHandler methods:
00283 
00284 NS_IMETHODIMP
00285 nsFileProtocolHandler::NewFileURI(nsIFile *file, nsIURI **result)
00286 {
00287     nsresult rv;
00288 
00289     nsCOMPtr<nsIFileURL> url = new nsStandardURL(PR_TRUE);
00290     if (!url)
00291         return NS_ERROR_OUT_OF_MEMORY;
00292 
00293     // NOTE: the origin charset is assigned the value of the platform
00294     // charset by the SetFile method.
00295     rv = url->SetFile(file);
00296     if (NS_FAILED(rv)) return rv;
00297 
00298     return CallQueryInterface(url, result);
00299 }
00300 
00301 NS_IMETHODIMP
00302 nsFileProtocolHandler::GetURLSpecFromFile(nsIFile *file, nsACString &result)
00303 {
00304     NS_ENSURE_ARG_POINTER(file);
00305     return net_GetURLSpecFromFile(file, result);
00306 }
00307 
00308 NS_IMETHODIMP
00309 nsFileProtocolHandler::GetFileFromURLSpec(const nsACString &spec, nsIFile **result)
00310 {
00311     return net_GetFileFromURLSpec(spec, result);
00312 }