Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsAutoPtr.h"
7 #include "nsJARProtocolHandler.h"
8 #include "nsIIOService.h"
9 #include "nsCRT.h"
10 #include "nsIComponentManager.h"
11 #include "nsIServiceManager.h"
12 #include "nsJARURI.h"
13 #include "nsIURL.h"
14 #include "nsJARChannel.h"
15 #include "nsXPIDLString.h"
16 #include "nsString.h"
17 #include "nsNetCID.h"
18 #include "nsIMIMEService.h"
19 #include "nsMimeTypes.h"
20 #include "nsIRemoteOpenFileListener.h"
21 #include "nsIHashable.h"
22 #include "nsThreadUtils.h"
23 #include "nsXULAppAPI.h"
24 #include "nsTArray.h"
26 static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID);
28 #define NS_JAR_CACHE_SIZE 32
30 //-----------------------------------------------------------------------------
32 nsJARProtocolHandler *gJarHandler = nullptr;
34 nsJARProtocolHandler::nsJARProtocolHandler()
35 : mIsMainProcess(XRE_GetProcessType() == GeckoProcessType_Default)
36 {
37 MOZ_ASSERT(NS_IsMainThread());
38 }
40 nsJARProtocolHandler::~nsJARProtocolHandler()
41 {
42 MOZ_ASSERT(gJarHandler == this);
43 gJarHandler = nullptr;
44 }
46 nsresult
47 nsJARProtocolHandler::Init()
48 {
49 nsresult rv;
51 mJARCache = do_CreateInstance(kZipReaderCacheCID, &rv);
52 if (NS_FAILED(rv)) return rv;
54 rv = mJARCache->Init(NS_JAR_CACHE_SIZE);
55 return rv;
56 }
58 nsIMIMEService *
59 nsJARProtocolHandler::MimeService()
60 {
61 if (!mMimeService)
62 mMimeService = do_GetService("@mozilla.org/mime;1");
64 return mMimeService.get();
65 }
67 bool
68 nsJARProtocolHandler::RemoteOpenFileInProgress(
69 nsIHashable *aRemoteFile,
70 nsIRemoteOpenFileListener *aListener)
71 {
72 MOZ_ASSERT(NS_IsMainThread());
73 MOZ_ASSERT(aRemoteFile);
74 MOZ_ASSERT(aListener);
76 if (IsMainProcess()) {
77 MOZ_CRASH("Shouldn't be called in the main process!");
78 }
80 RemoteFileListenerArray *listeners;
81 if (mRemoteFileListeners.Get(aRemoteFile, &listeners)) {
82 listeners->AppendElement(aListener);
83 return true;
84 }
86 // We deliberately don't put the listener in the new array since the first
87 // load is handled differently.
88 mRemoteFileListeners.Put(aRemoteFile, new RemoteFileListenerArray());
89 return false;
90 }
92 void
93 nsJARProtocolHandler::RemoteOpenFileComplete(nsIHashable *aRemoteFile,
94 nsresult aStatus)
95 {
96 MOZ_ASSERT(NS_IsMainThread());
97 MOZ_ASSERT(aRemoteFile);
99 if (IsMainProcess()) {
100 MOZ_CRASH("Shouldn't be called in the main process!");
101 }
103 RemoteFileListenerArray *tempListeners;
104 if (!mRemoteFileListeners.Get(aRemoteFile, &tempListeners)) {
105 return;
106 }
108 // Save the listeners in a stack array. The call to Remove() below will
109 // delete the tempListeners array.
110 RemoteFileListenerArray listeners;
111 tempListeners->SwapElements(listeners);
113 mRemoteFileListeners.Remove(aRemoteFile);
115 // Technically we must fail OnRemoteFileComplete() since OpenNSPRFileDesc()
116 // won't succeed here. We've trained nsJARChannel to recognize
117 // NS_ERROR_ALREADY_OPENED in this case as "proceed to JAR cache hit."
118 nsresult status = NS_SUCCEEDED(aStatus) ? NS_ERROR_ALREADY_OPENED : aStatus;
120 uint32_t count = listeners.Length();
121 for (uint32_t index = 0; index < count; index++) {
122 listeners[index]->OnRemoteFileOpenComplete(status);
123 }
124 }
126 NS_IMPL_ISUPPORTS(nsJARProtocolHandler,
127 nsIJARProtocolHandler,
128 nsIProtocolHandler,
129 nsISupportsWeakReference)
131 nsJARProtocolHandler*
132 nsJARProtocolHandler::GetSingleton()
133 {
134 if (!gJarHandler) {
135 gJarHandler = new nsJARProtocolHandler();
136 if (!gJarHandler)
137 return nullptr;
139 NS_ADDREF(gJarHandler);
140 nsresult rv = gJarHandler->Init();
141 if (NS_FAILED(rv)) {
142 NS_RELEASE(gJarHandler);
143 return nullptr;
144 }
145 }
146 NS_ADDREF(gJarHandler);
147 return gJarHandler;
148 }
150 NS_IMETHODIMP
151 nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result)
152 {
153 *result = mJARCache;
154 NS_ADDREF(*result);
155 return NS_OK;
156 }
158 ////////////////////////////////////////////////////////////////////////////////
159 // nsIProtocolHandler methods:
161 NS_IMETHODIMP
162 nsJARProtocolHandler::GetScheme(nsACString &result)
163 {
164 result.AssignLiteral("jar");
165 return NS_OK;
166 }
168 NS_IMETHODIMP
169 nsJARProtocolHandler::GetDefaultPort(int32_t *result)
170 {
171 *result = -1; // no port for JAR: URLs
172 return NS_OK;
173 }
175 NS_IMETHODIMP
176 nsJARProtocolHandler::GetProtocolFlags(uint32_t *result)
177 {
178 // URI_LOADABLE_BY_ANYONE, since it's our inner URI that will matter
179 // anyway.
180 *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE;
181 /* Although jar uris have their own concept of relative urls
182 it is very different from the standard behaviour, so we
183 have to say norelative here! */
184 return NS_OK;
185 }
187 NS_IMETHODIMP
188 nsJARProtocolHandler::NewURI(const nsACString &aSpec,
189 const char *aCharset,
190 nsIURI *aBaseURI,
191 nsIURI **result)
192 {
193 nsresult rv = NS_OK;
195 nsRefPtr<nsJARURI> jarURI = new nsJARURI();
196 if (!jarURI)
197 return NS_ERROR_OUT_OF_MEMORY;
199 rv = jarURI->Init(aCharset);
200 NS_ENSURE_SUCCESS(rv, rv);
202 rv = jarURI->SetSpecWithBase(aSpec, aBaseURI);
203 if (NS_FAILED(rv))
204 return rv;
206 NS_ADDREF(*result = jarURI);
207 return rv;
208 }
210 NS_IMETHODIMP
211 nsJARProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result)
212 {
213 nsJARChannel *chan = new nsJARChannel();
214 if (!chan)
215 return NS_ERROR_OUT_OF_MEMORY;
216 NS_ADDREF(chan);
218 nsresult rv = chan->Init(uri);
219 if (NS_FAILED(rv)) {
220 NS_RELEASE(chan);
221 return rv;
222 }
224 *result = chan;
225 return NS_OK;
226 }
229 NS_IMETHODIMP
230 nsJARProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
231 {
232 // don't override anything.
233 *_retval = false;
234 return NS_OK;
235 }
237 ////////////////////////////////////////////////////////////////////////////////