1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Startup Cache.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * The Mozilla Foundation <http://www.mozilla.org/>.
18 : * Portions created by the Initial Developer are Copyright (C) 2009-2011
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Benedict Hsieh <bhsieh@mozilla.com>
23 : * Taras Glek <tglek@mozilla.com>
24 : * Mike Hommey <mh@glandium.org>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsCOMPtr.h"
41 : #include "nsIInputStream.h"
42 : #include "nsIStringStream.h"
43 : #include "nsNetUtil.h"
44 : #include "nsIJARURI.h"
45 : #include "nsIResProtocolHandler.h"
46 : #include "nsIChromeRegistry.h"
47 : #include "nsAutoPtr.h"
48 : #include "StartupCacheUtils.h"
49 : #include "mozilla/scache/StartupCache.h"
50 : #include "mozilla/Omnijar.h"
51 :
52 : namespace mozilla {
53 : namespace scache {
54 :
55 : NS_EXPORT nsresult
56 643 : NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
57 : nsIObjectInputStream** stream)
58 : {
59 : nsCOMPtr<nsIStringInputStream> stringStream
60 1286 : = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
61 : nsCOMPtr<nsIObjectInputStream> objectInput
62 1286 : = do_CreateInstance("@mozilla.org/binaryinputstream;1");
63 :
64 643 : stringStream->AdoptData(buffer, len);
65 643 : objectInput->SetInputStream(stringStream);
66 :
67 643 : objectInput.forget(stream);
68 643 : return NS_OK;
69 : }
70 :
71 : NS_EXPORT nsresult
72 7375 : NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
73 : nsIStorageStream** stream,
74 : bool wantDebugStream)
75 : {
76 14750 : nsCOMPtr<nsIStorageStream> storageStream;
77 :
78 7375 : nsresult rv = NS_NewStorageStream(256, PR_UINT32_MAX, getter_AddRefs(storageStream));
79 7375 : NS_ENSURE_SUCCESS(rv, rv);
80 :
81 : nsCOMPtr<nsIObjectOutputStream> objectOutput
82 14750 : = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
83 : nsCOMPtr<nsIOutputStream> outputStream
84 14750 : = do_QueryInterface(storageStream);
85 :
86 7375 : objectOutput->SetOutputStream(outputStream);
87 :
88 : #ifdef DEBUG
89 7375 : if (wantDebugStream) {
90 : // Wrap in debug stream to detect unsupported writes of
91 : // multiply-referenced non-singleton objects
92 7375 : StartupCache* sc = StartupCache::GetSingleton();
93 7375 : NS_ENSURE_TRUE(sc, NS_ERROR_UNEXPECTED);
94 14750 : nsCOMPtr<nsIObjectOutputStream> debugStream;
95 7375 : sc->GetDebugObjectOutputStream(objectOutput, getter_AddRefs(debugStream));
96 7375 : debugStream.forget(wrapperStream);
97 : } else {
98 0 : objectOutput.forget(wrapperStream);
99 : }
100 : #else
101 : objectOutput.forget(wrapperStream);
102 : #endif
103 :
104 7375 : storageStream.forget(stream);
105 7375 : return NS_OK;
106 : }
107 :
108 : NS_EXPORT nsresult
109 7376 : NewBufferFromStorageStream(nsIStorageStream *storageStream,
110 : char** buffer, PRUint32* len)
111 : {
112 : nsresult rv;
113 14752 : nsCOMPtr<nsIInputStream> inputStream;
114 7376 : rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
115 7376 : NS_ENSURE_SUCCESS(rv, rv);
116 :
117 : PRUint32 avail, read;
118 7376 : rv = inputStream->Available(&avail);
119 7376 : NS_ENSURE_SUCCESS(rv, rv);
120 :
121 22128 : nsAutoArrayPtr<char> temp (new char[avail]);
122 7376 : rv = inputStream->Read(temp, avail, &read);
123 7376 : if (NS_SUCCEEDED(rv) && avail != read)
124 0 : rv = NS_ERROR_UNEXPECTED;
125 :
126 7376 : if (NS_FAILED(rv)) {
127 0 : return rv;
128 : }
129 :
130 7376 : *len = avail;
131 7376 : *buffer = temp.forget();
132 7376 : return NS_OK;
133 : }
134 :
135 : static const char baseName[2][5] = { "gre/", "app/" };
136 :
137 : static inline bool
138 13651 : canonicalizeBase(nsCAutoString &spec,
139 : nsACString &out,
140 : mozilla::Omnijar::Type aType)
141 : {
142 27302 : nsCAutoString base;
143 13651 : nsresult rv = mozilla::Omnijar::GetURIString(aType, base);
144 :
145 13651 : if (NS_FAILED(rv) || !base.Length())
146 892 : return false;
147 :
148 12759 : if (base.Compare(spec.get(), false, base.Length()))
149 892 : return false;
150 :
151 11867 : out.Append("/resource/");
152 11867 : out.Append(baseName[aType]);
153 11867 : out.Append(Substring(spec, base.Length()));
154 11867 : return true;
155 : }
156 :
157 : /**
158 : * PathifyURI transforms uris into useful zip paths
159 : * to make it easier to manipulate startup cache entries
160 : * using standard zip tools.
161 : * Transformations applied:
162 : * * resource:// URIs are resolved to their corresponding file/jar URI to
163 : * canonicalize resources URIs other than gre and app.
164 : * * Paths under GRE or APP directory have their base path replaced with
165 : * resource/gre or resource/app to avoid depending on install location.
166 : * * jar:file:///path/to/file.jar!/sub/path urls are replaced with
167 : * /path/to/file.jar/sub/path
168 : *
169 : * The result is appended to the string passed in. Adding a prefix before
170 : * calling is recommended to avoid colliding with other cache users.
171 : *
172 : * For example, in the js loader (string is prefixed with jsloader by caller):
173 : * resource://gre/modules/XPCOMUtils.jsm or
174 : * file://$GRE_DIR/modules/XPCOMUtils.jsm or
175 : * jar:file://$GRE_DIR/omni.jar!/modules/XPCOMUtils.jsm becomes
176 : * jsloader/resource/gre/modules/XPCOMUtils.jsm
177 : * file://$PROFILE_DIR/extensions/{uuid}/components/component.js becomes
178 : * jsloader/$PROFILE_DIR/extensions/%7Buuid%7D/components/component.js
179 : * jar:file://$PROFILE_DIR/extensions/some.xpi!/components/component.js becomes
180 : * jsloader/$PROFILE_DIR/extensions/some.xpi/components/component.js
181 : */
182 : NS_EXPORT nsresult
183 12763 : PathifyURI(nsIURI *in, nsACString &out)
184 : {
185 : bool equals;
186 : nsresult rv;
187 25526 : nsCOMPtr<nsIURI> uri = in;
188 25526 : nsCAutoString spec;
189 :
190 : // Resolve resource:// URIs. At the end of this if/else block, we
191 : // have both spec and uri variables identifying the same URI.
192 12763 : if (NS_SUCCEEDED(in->SchemeIs("resource", &equals)) && equals) {
193 19356 : nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
194 9678 : NS_ENSURE_SUCCESS(rv, rv);
195 :
196 19356 : nsCOMPtr<nsIProtocolHandler> ph;
197 9678 : rv = ioService->GetProtocolHandler("resource", getter_AddRefs(ph));
198 9678 : NS_ENSURE_SUCCESS(rv, rv);
199 :
200 19356 : nsCOMPtr<nsIResProtocolHandler> irph(do_QueryInterface(ph, &rv));
201 9678 : NS_ENSURE_SUCCESS(rv, rv);
202 :
203 9678 : rv = irph->ResolveURI(in, spec);
204 9678 : NS_ENSURE_SUCCESS(rv, rv);
205 :
206 9678 : rv = ioService->NewURI(spec, nsnull, nsnull, getter_AddRefs(uri));
207 9678 : NS_ENSURE_SUCCESS(rv, rv);
208 : } else {
209 3085 : if (NS_SUCCEEDED(in->SchemeIs("chrome", &equals)) && equals) {
210 : nsCOMPtr<nsIChromeRegistry> chromeReg =
211 414 : mozilla::services::GetChromeRegistryService();
212 207 : if (!chromeReg)
213 0 : return NS_ERROR_UNEXPECTED;
214 :
215 207 : rv = chromeReg->ConvertChromeURL(in, getter_AddRefs(uri));
216 207 : NS_ENSURE_SUCCESS(rv, rv);
217 : }
218 :
219 3081 : rv = uri->GetSpec(spec);
220 3081 : NS_ENSURE_SUCCESS(rv, rv);
221 : }
222 :
223 13651 : if (!canonicalizeBase(spec, out, mozilla::Omnijar::GRE) &&
224 892 : !canonicalizeBase(spec, out, mozilla::Omnijar::APP)) {
225 892 : if (NS_SUCCEEDED(uri->SchemeIs("file", &equals)) && equals) {
226 1336 : nsCOMPtr<nsIFileURL> baseFileURL;
227 668 : baseFileURL = do_QueryInterface(uri, &rv);
228 668 : NS_ENSURE_SUCCESS(rv, rv);
229 :
230 1336 : nsCAutoString path;
231 668 : rv = baseFileURL->GetPath(path);
232 668 : NS_ENSURE_SUCCESS(rv, rv);
233 :
234 1336 : out.Append(path);
235 224 : } else if (NS_SUCCEEDED(uri->SchemeIs("jar", &equals)) && equals) {
236 448 : nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(uri, &rv);
237 224 : NS_ENSURE_SUCCESS(rv, rv);
238 :
239 448 : nsCOMPtr<nsIURI> jarFileURI;
240 224 : rv = jarURI->GetJARFile(getter_AddRefs(jarFileURI));
241 224 : NS_ENSURE_SUCCESS(rv, rv);
242 :
243 224 : rv = PathifyURI(jarFileURI, out);
244 224 : NS_ENSURE_SUCCESS(rv, rv);
245 :
246 448 : nsCAutoString path;
247 224 : rv = jarURI->GetJAREntry(path);
248 224 : NS_ENSURE_SUCCESS(rv, rv);
249 224 : out.Append("/");
250 448 : out.Append(path);
251 : } else { // Very unlikely
252 0 : nsCAutoString spec;
253 0 : rv = uri->GetSpec(spec);
254 0 : NS_ENSURE_SUCCESS(rv, rv);
255 :
256 0 : out.Append("/");
257 0 : out.Append(spec);
258 : }
259 : }
260 12759 : return NS_OK;
261 : }
262 :
263 : }
264 : }
|