1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libjar/nsJARProtocolHandler.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,237 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsAutoPtr.h" 1.10 +#include "nsJARProtocolHandler.h" 1.11 +#include "nsIIOService.h" 1.12 +#include "nsCRT.h" 1.13 +#include "nsIComponentManager.h" 1.14 +#include "nsIServiceManager.h" 1.15 +#include "nsJARURI.h" 1.16 +#include "nsIURL.h" 1.17 +#include "nsJARChannel.h" 1.18 +#include "nsXPIDLString.h" 1.19 +#include "nsString.h" 1.20 +#include "nsNetCID.h" 1.21 +#include "nsIMIMEService.h" 1.22 +#include "nsMimeTypes.h" 1.23 +#include "nsIRemoteOpenFileListener.h" 1.24 +#include "nsIHashable.h" 1.25 +#include "nsThreadUtils.h" 1.26 +#include "nsXULAppAPI.h" 1.27 +#include "nsTArray.h" 1.28 + 1.29 +static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID); 1.30 + 1.31 +#define NS_JAR_CACHE_SIZE 32 1.32 + 1.33 +//----------------------------------------------------------------------------- 1.34 + 1.35 +nsJARProtocolHandler *gJarHandler = nullptr; 1.36 + 1.37 +nsJARProtocolHandler::nsJARProtocolHandler() 1.38 +: mIsMainProcess(XRE_GetProcessType() == GeckoProcessType_Default) 1.39 +{ 1.40 + MOZ_ASSERT(NS_IsMainThread()); 1.41 +} 1.42 + 1.43 +nsJARProtocolHandler::~nsJARProtocolHandler() 1.44 +{ 1.45 + MOZ_ASSERT(gJarHandler == this); 1.46 + gJarHandler = nullptr; 1.47 +} 1.48 + 1.49 +nsresult 1.50 +nsJARProtocolHandler::Init() 1.51 +{ 1.52 + nsresult rv; 1.53 + 1.54 + mJARCache = do_CreateInstance(kZipReaderCacheCID, &rv); 1.55 + if (NS_FAILED(rv)) return rv; 1.56 + 1.57 + rv = mJARCache->Init(NS_JAR_CACHE_SIZE); 1.58 + return rv; 1.59 +} 1.60 + 1.61 +nsIMIMEService * 1.62 +nsJARProtocolHandler::MimeService() 1.63 +{ 1.64 + if (!mMimeService) 1.65 + mMimeService = do_GetService("@mozilla.org/mime;1"); 1.66 + 1.67 + return mMimeService.get(); 1.68 +} 1.69 + 1.70 +bool 1.71 +nsJARProtocolHandler::RemoteOpenFileInProgress( 1.72 + nsIHashable *aRemoteFile, 1.73 + nsIRemoteOpenFileListener *aListener) 1.74 +{ 1.75 + MOZ_ASSERT(NS_IsMainThread()); 1.76 + MOZ_ASSERT(aRemoteFile); 1.77 + MOZ_ASSERT(aListener); 1.78 + 1.79 + if (IsMainProcess()) { 1.80 + MOZ_CRASH("Shouldn't be called in the main process!"); 1.81 + } 1.82 + 1.83 + RemoteFileListenerArray *listeners; 1.84 + if (mRemoteFileListeners.Get(aRemoteFile, &listeners)) { 1.85 + listeners->AppendElement(aListener); 1.86 + return true; 1.87 + } 1.88 + 1.89 + // We deliberately don't put the listener in the new array since the first 1.90 + // load is handled differently. 1.91 + mRemoteFileListeners.Put(aRemoteFile, new RemoteFileListenerArray()); 1.92 + return false; 1.93 +} 1.94 + 1.95 +void 1.96 +nsJARProtocolHandler::RemoteOpenFileComplete(nsIHashable *aRemoteFile, 1.97 + nsresult aStatus) 1.98 +{ 1.99 + MOZ_ASSERT(NS_IsMainThread()); 1.100 + MOZ_ASSERT(aRemoteFile); 1.101 + 1.102 + if (IsMainProcess()) { 1.103 + MOZ_CRASH("Shouldn't be called in the main process!"); 1.104 + } 1.105 + 1.106 + RemoteFileListenerArray *tempListeners; 1.107 + if (!mRemoteFileListeners.Get(aRemoteFile, &tempListeners)) { 1.108 + return; 1.109 + } 1.110 + 1.111 + // Save the listeners in a stack array. The call to Remove() below will 1.112 + // delete the tempListeners array. 1.113 + RemoteFileListenerArray listeners; 1.114 + tempListeners->SwapElements(listeners); 1.115 + 1.116 + mRemoteFileListeners.Remove(aRemoteFile); 1.117 + 1.118 + // Technically we must fail OnRemoteFileComplete() since OpenNSPRFileDesc() 1.119 + // won't succeed here. We've trained nsJARChannel to recognize 1.120 + // NS_ERROR_ALREADY_OPENED in this case as "proceed to JAR cache hit." 1.121 + nsresult status = NS_SUCCEEDED(aStatus) ? NS_ERROR_ALREADY_OPENED : aStatus; 1.122 + 1.123 + uint32_t count = listeners.Length(); 1.124 + for (uint32_t index = 0; index < count; index++) { 1.125 + listeners[index]->OnRemoteFileOpenComplete(status); 1.126 + } 1.127 +} 1.128 + 1.129 +NS_IMPL_ISUPPORTS(nsJARProtocolHandler, 1.130 + nsIJARProtocolHandler, 1.131 + nsIProtocolHandler, 1.132 + nsISupportsWeakReference) 1.133 + 1.134 +nsJARProtocolHandler* 1.135 +nsJARProtocolHandler::GetSingleton() 1.136 +{ 1.137 + if (!gJarHandler) { 1.138 + gJarHandler = new nsJARProtocolHandler(); 1.139 + if (!gJarHandler) 1.140 + return nullptr; 1.141 + 1.142 + NS_ADDREF(gJarHandler); 1.143 + nsresult rv = gJarHandler->Init(); 1.144 + if (NS_FAILED(rv)) { 1.145 + NS_RELEASE(gJarHandler); 1.146 + return nullptr; 1.147 + } 1.148 + } 1.149 + NS_ADDREF(gJarHandler); 1.150 + return gJarHandler; 1.151 +} 1.152 + 1.153 +NS_IMETHODIMP 1.154 +nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result) 1.155 +{ 1.156 + *result = mJARCache; 1.157 + NS_ADDREF(*result); 1.158 + return NS_OK; 1.159 +} 1.160 + 1.161 +//////////////////////////////////////////////////////////////////////////////// 1.162 +// nsIProtocolHandler methods: 1.163 + 1.164 +NS_IMETHODIMP 1.165 +nsJARProtocolHandler::GetScheme(nsACString &result) 1.166 +{ 1.167 + result.AssignLiteral("jar"); 1.168 + return NS_OK; 1.169 +} 1.170 + 1.171 +NS_IMETHODIMP 1.172 +nsJARProtocolHandler::GetDefaultPort(int32_t *result) 1.173 +{ 1.174 + *result = -1; // no port for JAR: URLs 1.175 + return NS_OK; 1.176 +} 1.177 + 1.178 +NS_IMETHODIMP 1.179 +nsJARProtocolHandler::GetProtocolFlags(uint32_t *result) 1.180 +{ 1.181 + // URI_LOADABLE_BY_ANYONE, since it's our inner URI that will matter 1.182 + // anyway. 1.183 + *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE; 1.184 + /* Although jar uris have their own concept of relative urls 1.185 + it is very different from the standard behaviour, so we 1.186 + have to say norelative here! */ 1.187 + return NS_OK; 1.188 +} 1.189 + 1.190 +NS_IMETHODIMP 1.191 +nsJARProtocolHandler::NewURI(const nsACString &aSpec, 1.192 + const char *aCharset, 1.193 + nsIURI *aBaseURI, 1.194 + nsIURI **result) 1.195 +{ 1.196 + nsresult rv = NS_OK; 1.197 + 1.198 + nsRefPtr<nsJARURI> jarURI = new nsJARURI(); 1.199 + if (!jarURI) 1.200 + return NS_ERROR_OUT_OF_MEMORY; 1.201 + 1.202 + rv = jarURI->Init(aCharset); 1.203 + NS_ENSURE_SUCCESS(rv, rv); 1.204 + 1.205 + rv = jarURI->SetSpecWithBase(aSpec, aBaseURI); 1.206 + if (NS_FAILED(rv)) 1.207 + return rv; 1.208 + 1.209 + NS_ADDREF(*result = jarURI); 1.210 + return rv; 1.211 +} 1.212 + 1.213 +NS_IMETHODIMP 1.214 +nsJARProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result) 1.215 +{ 1.216 + nsJARChannel *chan = new nsJARChannel(); 1.217 + if (!chan) 1.218 + return NS_ERROR_OUT_OF_MEMORY; 1.219 + NS_ADDREF(chan); 1.220 + 1.221 + nsresult rv = chan->Init(uri); 1.222 + if (NS_FAILED(rv)) { 1.223 + NS_RELEASE(chan); 1.224 + return rv; 1.225 + } 1.226 + 1.227 + *result = chan; 1.228 + return NS_OK; 1.229 +} 1.230 + 1.231 + 1.232 +NS_IMETHODIMP 1.233 +nsJARProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) 1.234 +{ 1.235 + // don't override anything. 1.236 + *_retval = false; 1.237 + return NS_OK; 1.238 +} 1.239 + 1.240 +////////////////////////////////////////////////////////////////////////////////