modules/libjar/nsJARProtocolHandler.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:cfec6ca04f9c
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/. */
5
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"
25
26 static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID);
27
28 #define NS_JAR_CACHE_SIZE 32
29
30 //-----------------------------------------------------------------------------
31
32 nsJARProtocolHandler *gJarHandler = nullptr;
33
34 nsJARProtocolHandler::nsJARProtocolHandler()
35 : mIsMainProcess(XRE_GetProcessType() == GeckoProcessType_Default)
36 {
37 MOZ_ASSERT(NS_IsMainThread());
38 }
39
40 nsJARProtocolHandler::~nsJARProtocolHandler()
41 {
42 MOZ_ASSERT(gJarHandler == this);
43 gJarHandler = nullptr;
44 }
45
46 nsresult
47 nsJARProtocolHandler::Init()
48 {
49 nsresult rv;
50
51 mJARCache = do_CreateInstance(kZipReaderCacheCID, &rv);
52 if (NS_FAILED(rv)) return rv;
53
54 rv = mJARCache->Init(NS_JAR_CACHE_SIZE);
55 return rv;
56 }
57
58 nsIMIMEService *
59 nsJARProtocolHandler::MimeService()
60 {
61 if (!mMimeService)
62 mMimeService = do_GetService("@mozilla.org/mime;1");
63
64 return mMimeService.get();
65 }
66
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);
75
76 if (IsMainProcess()) {
77 MOZ_CRASH("Shouldn't be called in the main process!");
78 }
79
80 RemoteFileListenerArray *listeners;
81 if (mRemoteFileListeners.Get(aRemoteFile, &listeners)) {
82 listeners->AppendElement(aListener);
83 return true;
84 }
85
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 }
91
92 void
93 nsJARProtocolHandler::RemoteOpenFileComplete(nsIHashable *aRemoteFile,
94 nsresult aStatus)
95 {
96 MOZ_ASSERT(NS_IsMainThread());
97 MOZ_ASSERT(aRemoteFile);
98
99 if (IsMainProcess()) {
100 MOZ_CRASH("Shouldn't be called in the main process!");
101 }
102
103 RemoteFileListenerArray *tempListeners;
104 if (!mRemoteFileListeners.Get(aRemoteFile, &tempListeners)) {
105 return;
106 }
107
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);
112
113 mRemoteFileListeners.Remove(aRemoteFile);
114
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;
119
120 uint32_t count = listeners.Length();
121 for (uint32_t index = 0; index < count; index++) {
122 listeners[index]->OnRemoteFileOpenComplete(status);
123 }
124 }
125
126 NS_IMPL_ISUPPORTS(nsJARProtocolHandler,
127 nsIJARProtocolHandler,
128 nsIProtocolHandler,
129 nsISupportsWeakReference)
130
131 nsJARProtocolHandler*
132 nsJARProtocolHandler::GetSingleton()
133 {
134 if (!gJarHandler) {
135 gJarHandler = new nsJARProtocolHandler();
136 if (!gJarHandler)
137 return nullptr;
138
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 }
149
150 NS_IMETHODIMP
151 nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result)
152 {
153 *result = mJARCache;
154 NS_ADDREF(*result);
155 return NS_OK;
156 }
157
158 ////////////////////////////////////////////////////////////////////////////////
159 // nsIProtocolHandler methods:
160
161 NS_IMETHODIMP
162 nsJARProtocolHandler::GetScheme(nsACString &result)
163 {
164 result.AssignLiteral("jar");
165 return NS_OK;
166 }
167
168 NS_IMETHODIMP
169 nsJARProtocolHandler::GetDefaultPort(int32_t *result)
170 {
171 *result = -1; // no port for JAR: URLs
172 return NS_OK;
173 }
174
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 }
186
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;
194
195 nsRefPtr<nsJARURI> jarURI = new nsJARURI();
196 if (!jarURI)
197 return NS_ERROR_OUT_OF_MEMORY;
198
199 rv = jarURI->Init(aCharset);
200 NS_ENSURE_SUCCESS(rv, rv);
201
202 rv = jarURI->SetSpecWithBase(aSpec, aBaseURI);
203 if (NS_FAILED(rv))
204 return rv;
205
206 NS_ADDREF(*result = jarURI);
207 return rv;
208 }
209
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);
217
218 nsresult rv = chan->Init(uri);
219 if (NS_FAILED(rv)) {
220 NS_RELEASE(chan);
221 return rv;
222 }
223
224 *result = chan;
225 return NS_OK;
226 }
227
228
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 }
236
237 ////////////////////////////////////////////////////////////////////////////////

mercurial