1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "base/basictypes.h"
8
9 #include "nsJARURI.h"
10 #include "nsNetUtil.h"
11 #include "nsIClassInfoImpl.h"
12 #include "nsIIOService.h"
13 #include "nsIStandardURL.h"
14 #include "nsCRT.h"
15 #include "nsReadableUtils.h"
16 #include "nsNetCID.h"
17 #include "nsIObjectInputStream.h"
18 #include "nsIObjectOutputStream.h"
19 #include "nsQueryObject.h"
20 #include "mozilla/ipc/URIUtils.h"
21
22 using namespace mozilla::ipc;
23
24 static NS_DEFINE_CID(kJARURICID, NS_JARURI_CID);
25
26 ////////////////////////////////////////////////////////////////////////////////
27
NS_IMPL_CLASSINFO(nsJARURI,nullptr,nsIClassInfo::THREADSAFE,NS_JARURI_CID)28 NS_IMPL_CLASSINFO(nsJARURI, nullptr, nsIClassInfo::THREADSAFE, NS_JARURI_CID)
29 // Empty CI getter. We only need nsIClassInfo for Serialization
30 NS_IMPL_CI_INTERFACE_GETTER0(nsJARURI)
31
32 nsJARURI::nsJARURI() {}
33
~nsJARURI()34 nsJARURI::~nsJARURI() {}
35
36 // XXX Why is this threadsafe?
37 NS_IMPL_ADDREF(nsJARURI)
NS_IMPL_RELEASE(nsJARURI)38 NS_IMPL_RELEASE(nsJARURI)
39 NS_INTERFACE_MAP_BEGIN(nsJARURI)
40 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJARURI)
41 NS_INTERFACE_MAP_ENTRY(nsIURI)
42 NS_INTERFACE_MAP_ENTRY(nsIURL)
43 NS_INTERFACE_MAP_ENTRY(nsIJARURI)
44 NS_INTERFACE_MAP_ENTRY(nsISerializable)
45 NS_IMPL_QUERY_CLASSINFO(nsJARURI)
46 NS_INTERFACE_MAP_ENTRY(nsINestedURI)
47 NS_INTERFACE_MAP_ENTRY_CONCRETE(nsJARURI)
48 NS_INTERFACE_MAP_END
49
50 nsresult nsJARURI::Init(const char* charsetHint) {
51 mCharsetHint = charsetHint;
52 return NS_OK;
53 }
54
55 #define NS_JAR_SCHEME "jar:"_ns
56 #define NS_JAR_DELIMITER "!/"_ns
57 #define NS_BOGUS_ENTRY_SCHEME "x:///"_ns
58
59 // FormatSpec takes the entry spec (including the "x:///" at the
60 // beginning) and gives us a full JAR spec.
FormatSpec(const nsACString & entrySpec,nsACString & result,bool aIncludeScheme)61 nsresult nsJARURI::FormatSpec(const nsACString& entrySpec, nsACString& result,
62 bool aIncludeScheme) {
63 // The entrySpec MUST start with "x:///"
64 NS_ASSERTION(StringBeginsWith(entrySpec, NS_BOGUS_ENTRY_SCHEME),
65 "bogus entry spec");
66
67 nsAutoCString fileSpec;
68 nsresult rv = mJARFile->GetSpec(fileSpec);
69 if (NS_FAILED(rv)) return rv;
70
71 if (aIncludeScheme)
72 result = NS_JAR_SCHEME;
73 else
74 result.Truncate();
75
76 result.Append(fileSpec + NS_JAR_DELIMITER +
77 Substring(entrySpec, 5, entrySpec.Length() - 5));
78 return NS_OK;
79 }
80
CreateEntryURL(const nsACString & entryFilename,const char * charset,nsIURL ** url)81 nsresult nsJARURI::CreateEntryURL(const nsACString& entryFilename,
82 const char* charset, nsIURL** url) {
83 *url = nullptr;
84 // Flatten the concatenation, just in case. See bug 128288
85 nsAutoCString spec(NS_BOGUS_ENTRY_SCHEME + entryFilename);
86 return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
87 .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
88 nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, spec,
89 charset, nullptr, nullptr))
90 .Finalize(url);
91 }
92
93 ////////////////////////////////////////////////////////////////////////////////
94 // nsISerializable methods:
95
96 NS_IMETHODIMP
Read(nsIObjectInputStream * aStream)97 nsJARURI::Read(nsIObjectInputStream* aStream) {
98 MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
99 return NS_ERROR_NOT_IMPLEMENTED;
100 }
101
ReadPrivate(nsIObjectInputStream * aInputStream)102 nsresult nsJARURI::ReadPrivate(nsIObjectInputStream* aInputStream) {
103 nsresult rv;
104
105 nsCOMPtr<nsISupports> supports;
106 rv = aInputStream->ReadObject(true, getter_AddRefs(supports));
107 NS_ENSURE_SUCCESS(rv, rv);
108
109 mJARFile = do_QueryInterface(supports, &rv);
110 NS_ENSURE_SUCCESS(rv, rv);
111
112 rv = aInputStream->ReadObject(true, getter_AddRefs(supports));
113 NS_ENSURE_SUCCESS(rv, rv);
114
115 mJAREntry = do_QueryInterface(supports);
116 NS_ENSURE_SUCCESS(rv, rv);
117
118 rv = aInputStream->ReadCString(mCharsetHint);
119 return rv;
120 }
121
122 NS_IMETHODIMP
Write(nsIObjectOutputStream * aOutputStream)123 nsJARURI::Write(nsIObjectOutputStream* aOutputStream) {
124 nsresult rv;
125
126 rv = aOutputStream->WriteCompoundObject(mJARFile, NS_GET_IID(nsIURI), true);
127 NS_ENSURE_SUCCESS(rv, rv);
128
129 rv = aOutputStream->WriteCompoundObject(mJAREntry, NS_GET_IID(nsIURL), true);
130 NS_ENSURE_SUCCESS(rv, rv);
131
132 rv = aOutputStream->WriteStringZ(mCharsetHint.get());
133 return rv;
134 }
135
136 ////////////////////////////////////////////////////////////////////////////////
137 // nsIURI methods:
138
139 NS_IMETHODIMP
GetSpec(nsACString & aSpec)140 nsJARURI::GetSpec(nsACString& aSpec) {
141 nsAutoCString entrySpec;
142 mJAREntry->GetSpec(entrySpec);
143 return FormatSpec(entrySpec, aSpec);
144 }
145
146 NS_IMETHODIMP
GetSpecIgnoringRef(nsACString & aSpec)147 nsJARURI::GetSpecIgnoringRef(nsACString& aSpec) {
148 nsAutoCString entrySpec;
149 mJAREntry->GetSpecIgnoringRef(entrySpec);
150 return FormatSpec(entrySpec, aSpec);
151 }
152
153 NS_IMETHODIMP
GetDisplaySpec(nsACString & aUnicodeSpec)154 nsJARURI::GetDisplaySpec(nsACString& aUnicodeSpec) {
155 return GetSpec(aUnicodeSpec);
156 }
157
158 NS_IMETHODIMP
GetDisplayHostPort(nsACString & aUnicodeHostPort)159 nsJARURI::GetDisplayHostPort(nsACString& aUnicodeHostPort) {
160 return GetHostPort(aUnicodeHostPort);
161 }
162
163 NS_IMETHODIMP
GetDisplayPrePath(nsACString & aPrePath)164 nsJARURI::GetDisplayPrePath(nsACString& aPrePath) {
165 return GetPrePath(aPrePath);
166 }
167
168 NS_IMETHODIMP
GetDisplayHost(nsACString & aUnicodeHost)169 nsJARURI::GetDisplayHost(nsACString& aUnicodeHost) {
170 return GetHost(aUnicodeHost);
171 }
172
173 NS_IMETHODIMP
GetHasRef(bool * result)174 nsJARURI::GetHasRef(bool* result) { return mJAREntry->GetHasRef(result); }
175
SetSpecInternal(const nsACString & aSpec)176 nsresult nsJARURI::SetSpecInternal(const nsACString& aSpec) {
177 return SetSpecWithBase(aSpec, nullptr);
178 }
179
180 // Queries this list of interfaces. If none match, it queries mURI.
NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsJARURI::Mutator,nsIURISetters,nsIURIMutator,nsIURLMutator,nsISerializable,nsIJARURIMutator)181 NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsJARURI::Mutator, nsIURISetters, nsIURIMutator,
182 nsIURLMutator, nsISerializable,
183 nsIJARURIMutator)
184
185 NS_IMETHODIMP
186 nsJARURI::Mutator::SetFileName(const nsACString& aFileName,
187 nsIURIMutator** aMutator) {
188 if (!mURI) {
189 return NS_ERROR_NULL_POINTER;
190 }
191 if (aMutator) {
192 nsCOMPtr<nsIURIMutator> mutator = this;
193 mutator.forget(aMutator);
194 }
195 return mURI->SetFileNameInternal(aFileName);
196 }
197
198 NS_IMETHODIMP
SetFileBaseName(const nsACString & aFileBaseName,nsIURIMutator ** aMutator)199 nsJARURI::Mutator::SetFileBaseName(const nsACString& aFileBaseName,
200 nsIURIMutator** aMutator) {
201 if (!mURI) {
202 return NS_ERROR_NULL_POINTER;
203 }
204 if (aMutator) {
205 nsCOMPtr<nsIURIMutator> mutator = this;
206 mutator.forget(aMutator);
207 }
208 return mURI->SetFileBaseNameInternal(aFileBaseName);
209 }
210
211 NS_IMETHODIMP
SetFileExtension(const nsACString & aFileExtension,nsIURIMutator ** aMutator)212 nsJARURI::Mutator::SetFileExtension(const nsACString& aFileExtension,
213 nsIURIMutator** aMutator) {
214 if (!mURI) {
215 return NS_ERROR_NULL_POINTER;
216 }
217 if (aMutator) {
218 nsCOMPtr<nsIURIMutator> mutator = this;
219 mutator.forget(aMutator);
220 }
221 return mURI->SetFileExtensionInternal(aFileExtension);
222 }
223
224 NS_IMETHODIMP
Mutate(nsIURIMutator ** aMutator)225 nsJARURI::Mutate(nsIURIMutator** aMutator) {
226 RefPtr<nsJARURI::Mutator> mutator = new nsJARURI::Mutator();
227 nsresult rv = mutator->InitFromURI(this);
228 if (NS_FAILED(rv)) {
229 return rv;
230 }
231 mutator.forget(aMutator);
232 return NS_OK;
233 }
234
SetSpecWithBase(const nsACString & aSpec,nsIURI * aBaseURL)235 nsresult nsJARURI::SetSpecWithBase(const nsACString& aSpec, nsIURI* aBaseURL) {
236 nsresult rv;
237
238 nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
239 NS_ENSURE_SUCCESS(rv, rv);
240
241 nsAutoCString scheme;
242 rv = ioServ->ExtractScheme(aSpec, scheme);
243 if (NS_FAILED(rv)) {
244 // not an absolute URI
245 if (!aBaseURL) return NS_ERROR_MALFORMED_URI;
246
247 RefPtr<nsJARURI> otherJAR = do_QueryObject(aBaseURL);
248 NS_ENSURE_TRUE(otherJAR, NS_NOINTERFACE);
249
250 mJARFile = otherJAR->mJARFile;
251
252 nsCOMPtr<nsIURI> entry;
253
254 rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
255 .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
256 nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
257 nsCString(aSpec), mCharsetHint.get(),
258 otherJAR->mJAREntry, nullptr))
259 .Finalize(entry);
260 if (NS_FAILED(rv)) {
261 return rv;
262 }
263
264 mJAREntry = do_QueryInterface(entry);
265 if (!mJAREntry) return NS_NOINTERFACE;
266
267 return NS_OK;
268 }
269
270 NS_ENSURE_TRUE(scheme.EqualsLiteral("jar"), NS_ERROR_MALFORMED_URI);
271
272 nsACString::const_iterator begin, end;
273 aSpec.BeginReading(begin);
274 aSpec.EndReading(end);
275
276 while (begin != end && *begin != ':') ++begin;
277
278 ++begin; // now we're past the "jar:"
279
280 nsACString::const_iterator delim_begin = begin;
281 nsACString::const_iterator delim_end = end;
282 nsACString::const_iterator frag = begin;
283
284 if (FindInReadable(NS_JAR_DELIMITER, delim_begin, delim_end)) {
285 frag = delim_end;
286 }
287 while (frag != end && (*frag != '#' && *frag != '?')) {
288 ++frag;
289 }
290 if (frag != end) {
291 // there was a fragment or query, mark that as the end of the URL to scan
292 end = frag;
293 }
294
295 // Search backward from the end for the "!/" delimiter. Remember, jar URLs
296 // can nest, e.g.:
297 // jar:jar:http://www.foo.com/bar.jar!/a.jar!/b.html
298 // This gets the b.html document from out of the a.jar file, that's
299 // contained within the bar.jar file.
300 // Also, the outermost "inner" URI may be a relative URI:
301 // jar:../relative.jar!/a.html
302
303 delim_begin = begin;
304 delim_end = end;
305
306 if (!RFindInReadable(NS_JAR_DELIMITER, delim_begin, delim_end)) {
307 return NS_ERROR_MALFORMED_URI;
308 }
309
310 rv = ioServ->NewURI(Substring(begin, delim_begin), mCharsetHint.get(),
311 aBaseURL, getter_AddRefs(mJARFile));
312 if (NS_FAILED(rv)) return rv;
313
314 // skip over any extra '/' chars
315 while (*delim_end == '/') ++delim_end;
316
317 aSpec.EndReading(end); // set to the original 'end'
318 return SetJAREntry(Substring(delim_end, end));
319 }
320
321 NS_IMETHODIMP
GetPrePath(nsACString & prePath)322 nsJARURI::GetPrePath(nsACString& prePath) {
323 prePath = NS_JAR_SCHEME;
324 return NS_OK;
325 }
326
327 NS_IMETHODIMP
GetScheme(nsACString & aScheme)328 nsJARURI::GetScheme(nsACString& aScheme) {
329 aScheme = "jar";
330 return NS_OK;
331 }
332
SetScheme(const nsACString & aScheme)333 nsresult nsJARURI::SetScheme(const nsACString& aScheme) {
334 // doesn't make sense to set the scheme of a jar: URL
335 return NS_ERROR_FAILURE;
336 }
337
338 NS_IMETHODIMP
GetUserPass(nsACString & aUserPass)339 nsJARURI::GetUserPass(nsACString& aUserPass) { return NS_ERROR_FAILURE; }
340
SetUserPass(const nsACString & aUserPass)341 nsresult nsJARURI::SetUserPass(const nsACString& aUserPass) {
342 return NS_ERROR_FAILURE;
343 }
344
345 NS_IMETHODIMP
GetUsername(nsACString & aUsername)346 nsJARURI::GetUsername(nsACString& aUsername) { return NS_ERROR_FAILURE; }
347
SetUsername(const nsACString & aUsername)348 nsresult nsJARURI::SetUsername(const nsACString& aUsername) {
349 return NS_ERROR_FAILURE;
350 }
351
352 NS_IMETHODIMP
GetPassword(nsACString & aPassword)353 nsJARURI::GetPassword(nsACString& aPassword) { return NS_ERROR_FAILURE; }
354
SetPassword(const nsACString & aPassword)355 nsresult nsJARURI::SetPassword(const nsACString& aPassword) {
356 return NS_ERROR_FAILURE;
357 }
358
359 NS_IMETHODIMP
GetHostPort(nsACString & aHostPort)360 nsJARURI::GetHostPort(nsACString& aHostPort) { return NS_ERROR_FAILURE; }
361
SetHostPort(const nsACString & aHostPort)362 nsresult nsJARURI::SetHostPort(const nsACString& aHostPort) {
363 return NS_ERROR_FAILURE;
364 }
365
366 NS_IMETHODIMP
GetHost(nsACString & aHost)367 nsJARURI::GetHost(nsACString& aHost) { return NS_ERROR_FAILURE; }
368
SetHost(const nsACString & aHost)369 nsresult nsJARURI::SetHost(const nsACString& aHost) { return NS_ERROR_FAILURE; }
370
371 NS_IMETHODIMP
GetPort(int32_t * aPort)372 nsJARURI::GetPort(int32_t* aPort) { return NS_ERROR_FAILURE; }
373
SetPort(int32_t aPort)374 nsresult nsJARURI::SetPort(int32_t aPort) { return NS_ERROR_FAILURE; }
375
GetPathQueryRef(nsACString & aPath)376 nsresult nsJARURI::GetPathQueryRef(nsACString& aPath) {
377 nsAutoCString entrySpec;
378 mJAREntry->GetSpec(entrySpec);
379 return FormatSpec(entrySpec, aPath, false);
380 }
381
SetPathQueryRef(const nsACString & aPath)382 nsresult nsJARURI::SetPathQueryRef(const nsACString& aPath) {
383 return NS_ERROR_FAILURE;
384 }
385
386 NS_IMETHODIMP
GetAsciiSpec(nsACString & aSpec)387 nsJARURI::GetAsciiSpec(nsACString& aSpec) {
388 // XXX Shouldn't this like... make sure it returns ASCII or something?
389 return GetSpec(aSpec);
390 }
391
392 NS_IMETHODIMP
GetAsciiHostPort(nsACString & aHostPort)393 nsJARURI::GetAsciiHostPort(nsACString& aHostPort) { return NS_ERROR_FAILURE; }
394
395 NS_IMETHODIMP
GetAsciiHost(nsACString & aHost)396 nsJARURI::GetAsciiHost(nsACString& aHost) { return NS_ERROR_FAILURE; }
397
398 NS_IMETHODIMP
Equals(nsIURI * other,bool * result)399 nsJARURI::Equals(nsIURI* other, bool* result) {
400 return EqualsInternal(other, eHonorRef, result);
401 }
402
403 NS_IMETHODIMP
EqualsExceptRef(nsIURI * other,bool * result)404 nsJARURI::EqualsExceptRef(nsIURI* other, bool* result) {
405 return EqualsInternal(other, eIgnoreRef, result);
406 }
407
408 // Helper method:
409 /* virtual */
EqualsInternal(nsIURI * other,nsJARURI::RefHandlingEnum refHandlingMode,bool * result)410 nsresult nsJARURI::EqualsInternal(nsIURI* other,
411 nsJARURI::RefHandlingEnum refHandlingMode,
412 bool* result) {
413 *result = false;
414
415 if (!other) return NS_OK; // not equal
416
417 RefPtr<nsJARURI> otherJAR = do_QueryObject(other);
418 if (!otherJAR) return NS_OK; // not equal
419
420 bool equal;
421 nsresult rv = mJARFile->Equals(otherJAR->mJARFile, &equal);
422 if (NS_FAILED(rv) || !equal) {
423 return rv; // not equal
424 }
425
426 return refHandlingMode == eHonorRef
427 ? mJAREntry->Equals(otherJAR->mJAREntry, result)
428 : mJAREntry->EqualsExceptRef(otherJAR->mJAREntry, result);
429 }
430
431 NS_IMETHODIMP
SchemeIs(const char * i_Scheme,bool * o_Equals)432 nsJARURI::SchemeIs(const char* i_Scheme, bool* o_Equals) {
433 MOZ_ASSERT(o_Equals);
434 if (!i_Scheme) {
435 *o_Equals = false;
436 return NS_OK;
437 }
438
439 *o_Equals = PL_strcasecmp("jar", i_Scheme) ? false : true;
440 return NS_OK;
441 }
442
Clone(nsIURI ** result)443 nsresult nsJARURI::Clone(nsIURI** result) {
444 RefPtr<nsJARURI> uri = new nsJARURI();
445 uri->mJARFile = mJARFile;
446 uri->mJAREntry = mJAREntry;
447 uri.forget(result);
448
449 return NS_OK;
450 }
451
452 NS_IMETHODIMP
Resolve(const nsACString & relativePath,nsACString & result)453 nsJARURI::Resolve(const nsACString& relativePath, nsACString& result) {
454 nsresult rv;
455
456 nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
457 if (NS_FAILED(rv)) return rv;
458
459 nsAutoCString scheme;
460 rv = ioServ->ExtractScheme(relativePath, scheme);
461 if (NS_SUCCEEDED(rv)) {
462 // then aSpec is absolute
463 result = relativePath;
464 return NS_OK;
465 }
466
467 nsAutoCString resolvedPath;
468 mJAREntry->Resolve(relativePath, resolvedPath);
469
470 return FormatSpec(resolvedPath, result);
471 }
472
473 ////////////////////////////////////////////////////////////////////////////////
474 // nsIURL methods:
475
476 NS_IMETHODIMP
GetFilePath(nsACString & filePath)477 nsJARURI::GetFilePath(nsACString& filePath) {
478 return mJAREntry->GetFilePath(filePath);
479 }
480
SetFilePath(const nsACString & filePath)481 nsresult nsJARURI::SetFilePath(const nsACString& filePath) {
482 return NS_MutateURI(mJAREntry).SetFilePath(filePath).Finalize(mJAREntry);
483 }
484
485 NS_IMETHODIMP
GetQuery(nsACString & query)486 nsJARURI::GetQuery(nsACString& query) { return mJAREntry->GetQuery(query); }
487
SetQuery(const nsACString & query)488 nsresult nsJARURI::SetQuery(const nsACString& query) {
489 return NS_MutateURI(mJAREntry).SetQuery(query).Finalize(mJAREntry);
490 }
491
SetQueryWithEncoding(const nsACString & query,const Encoding * encoding)492 nsresult nsJARURI::SetQueryWithEncoding(const nsACString& query,
493 const Encoding* encoding) {
494 return NS_MutateURI(mJAREntry)
495 .SetQueryWithEncoding(query, encoding)
496 .Finalize(mJAREntry);
497 }
498
499 NS_IMETHODIMP
GetRef(nsACString & ref)500 nsJARURI::GetRef(nsACString& ref) { return mJAREntry->GetRef(ref); }
501
SetRef(const nsACString & ref)502 nsresult nsJARURI::SetRef(const nsACString& ref) {
503 return NS_MutateURI(mJAREntry).SetRef(ref).Finalize(mJAREntry);
504 }
505
506 NS_IMETHODIMP
GetDirectory(nsACString & directory)507 nsJARURI::GetDirectory(nsACString& directory) {
508 return mJAREntry->GetDirectory(directory);
509 }
510
511 NS_IMETHODIMP
GetFileName(nsACString & fileName)512 nsJARURI::GetFileName(nsACString& fileName) {
513 return mJAREntry->GetFileName(fileName);
514 }
515
SetFileNameInternal(const nsACString & fileName)516 nsresult nsJARURI::SetFileNameInternal(const nsACString& fileName) {
517 return NS_MutateURI(mJAREntry)
518 .Apply(NS_MutatorMethod(&nsIURLMutator::SetFileName, nsCString(fileName),
519 nullptr))
520 .Finalize(mJAREntry);
521 }
522
523 NS_IMETHODIMP
GetFileBaseName(nsACString & fileBaseName)524 nsJARURI::GetFileBaseName(nsACString& fileBaseName) {
525 return mJAREntry->GetFileBaseName(fileBaseName);
526 }
527
SetFileBaseNameInternal(const nsACString & fileBaseName)528 nsresult nsJARURI::SetFileBaseNameInternal(const nsACString& fileBaseName) {
529 return NS_MutateURI(mJAREntry)
530 .Apply(NS_MutatorMethod(&nsIURLMutator::SetFileBaseName,
531 nsCString(fileBaseName), nullptr))
532 .Finalize(mJAREntry);
533 }
534
535 NS_IMETHODIMP
GetFileExtension(nsACString & fileExtension)536 nsJARURI::GetFileExtension(nsACString& fileExtension) {
537 return mJAREntry->GetFileExtension(fileExtension);
538 }
539
SetFileExtensionInternal(const nsACString & fileExtension)540 nsresult nsJARURI::SetFileExtensionInternal(const nsACString& fileExtension) {
541 return NS_MutateURI(mJAREntry)
542 .Apply(NS_MutatorMethod(&nsIURLMutator::SetFileExtension,
543 nsCString(fileExtension), nullptr))
544 .Finalize(mJAREntry);
545 }
546
547 NS_IMETHODIMP
GetCommonBaseSpec(nsIURI * uriToCompare,nsACString & commonSpec)548 nsJARURI::GetCommonBaseSpec(nsIURI* uriToCompare, nsACString& commonSpec) {
549 commonSpec.Truncate();
550
551 NS_ENSURE_ARG_POINTER(uriToCompare);
552
553 commonSpec.Truncate();
554 nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
555 if (!otherJARURI) {
556 // Nothing in common
557 return NS_OK;
558 }
559
560 nsCOMPtr<nsIURI> otherJARFile;
561 nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
562 if (NS_FAILED(rv)) return rv;
563
564 bool equal;
565 rv = mJARFile->Equals(otherJARFile, &equal);
566 if (NS_FAILED(rv)) return rv;
567
568 if (!equal) {
569 // See what the JAR file URIs have in common
570 nsCOMPtr<nsIURL> ourJARFileURL(do_QueryInterface(mJARFile));
571 if (!ourJARFileURL) {
572 // Not a URL, so nothing in common
573 return NS_OK;
574 }
575 nsAutoCString common;
576 rv = ourJARFileURL->GetCommonBaseSpec(otherJARFile, common);
577 if (NS_FAILED(rv)) return rv;
578
579 commonSpec = NS_JAR_SCHEME + common;
580 return NS_OK;
581 }
582
583 // At this point we have the same JAR file. Compare the JAREntrys
584 nsAutoCString otherEntry;
585 rv = otherJARURI->GetJAREntry(otherEntry);
586 if (NS_FAILED(rv)) return rv;
587
588 nsCOMPtr<nsIURL> url;
589 rv = CreateEntryURL(otherEntry, nullptr, getter_AddRefs(url));
590 if (NS_FAILED(rv)) return rv;
591
592 nsAutoCString common;
593 rv = mJAREntry->GetCommonBaseSpec(url, common);
594 if (NS_FAILED(rv)) return rv;
595
596 rv = FormatSpec(common, commonSpec);
597 return rv;
598 }
599
600 NS_IMETHODIMP
GetRelativeSpec(nsIURI * uriToCompare,nsACString & relativeSpec)601 nsJARURI::GetRelativeSpec(nsIURI* uriToCompare, nsACString& relativeSpec) {
602 GetSpec(relativeSpec);
603
604 NS_ENSURE_ARG_POINTER(uriToCompare);
605
606 nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
607 if (!otherJARURI) {
608 // Nothing in common
609 return NS_OK;
610 }
611
612 nsCOMPtr<nsIURI> otherJARFile;
613 nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
614 if (NS_FAILED(rv)) return rv;
615
616 bool equal;
617 rv = mJARFile->Equals(otherJARFile, &equal);
618 if (NS_FAILED(rv)) return rv;
619
620 if (!equal) {
621 // We live in different JAR files. Nothing in common.
622 return rv;
623 }
624
625 // Same JAR file. Compare the JAREntrys
626 nsAutoCString otherEntry;
627 rv = otherJARURI->GetJAREntry(otherEntry);
628 if (NS_FAILED(rv)) return rv;
629
630 nsCOMPtr<nsIURL> url;
631 rv = CreateEntryURL(otherEntry, nullptr, getter_AddRefs(url));
632 if (NS_FAILED(rv)) return rv;
633
634 nsAutoCString relativeEntrySpec;
635 rv = mJAREntry->GetRelativeSpec(url, relativeEntrySpec);
636 if (NS_FAILED(rv)) return rv;
637
638 if (!StringBeginsWith(relativeEntrySpec, NS_BOGUS_ENTRY_SCHEME)) {
639 // An actual relative spec!
640 relativeSpec = relativeEntrySpec;
641 }
642 return rv;
643 }
644
645 ////////////////////////////////////////////////////////////////////////////////
646 // nsIJARURI methods:
647
648 NS_IMETHODIMP
GetJARFile(nsIURI ** jarFile)649 nsJARURI::GetJARFile(nsIURI** jarFile) { return GetInnerURI(jarFile); }
650
651 NS_IMETHODIMP
GetJAREntry(nsACString & entryPath)652 nsJARURI::GetJAREntry(nsACString& entryPath) {
653 nsAutoCString filePath;
654 mJAREntry->GetFilePath(filePath);
655 NS_ASSERTION(filePath.Length() > 0, "path should never be empty!");
656 // Trim off the leading '/'
657 entryPath = Substring(filePath, 1, filePath.Length() - 1);
658 return NS_OK;
659 }
660
SetJAREntry(const nsACString & entryPath)661 nsresult nsJARURI::SetJAREntry(const nsACString& entryPath) {
662 return CreateEntryURL(entryPath, mCharsetHint.get(),
663 getter_AddRefs(mJAREntry));
664 }
665
666 ////////////////////////////////////////////////////////////////////////////////
667
668 NS_IMETHODIMP
GetInnerURI(nsIURI ** aURI)669 nsJARURI::GetInnerURI(nsIURI** aURI) {
670 nsCOMPtr<nsIURI> uri = mJARFile;
671 uri.forget(aURI);
672 return NS_OK;
673 }
674
675 NS_IMETHODIMP
GetInnermostURI(nsIURI ** uri)676 nsJARURI::GetInnermostURI(nsIURI** uri) {
677 return NS_ImplGetInnermostURI(this, uri);
678 }
679
Serialize(URIParams & aParams)680 void nsJARURI::Serialize(URIParams& aParams) {
681 JARURIParams params;
682
683 SerializeURI(mJARFile, params.jarFile());
684 SerializeURI(mJAREntry, params.jarEntry());
685 params.charset() = mCharsetHint;
686
687 aParams = params;
688 }
689
Deserialize(const URIParams & aParams)690 bool nsJARURI::Deserialize(const URIParams& aParams) {
691 if (aParams.type() != URIParams::TJARURIParams) {
692 NS_ERROR("Received unknown parameters from the other process!");
693 return false;
694 }
695
696 const JARURIParams& params = aParams.get_JARURIParams();
697
698 nsCOMPtr<nsIURI> file = DeserializeURI(params.jarFile());
699 if (!file) {
700 NS_ERROR("Couldn't deserialize jar file URI!");
701 return false;
702 }
703
704 nsCOMPtr<nsIURI> entry = DeserializeURI(params.jarEntry());
705 if (!entry) {
706 NS_ERROR("Couldn't deserialize jar entry URI!");
707 return false;
708 }
709
710 nsCOMPtr<nsIURL> entryURL = do_QueryInterface(entry);
711 if (!entryURL) {
712 NS_ERROR("Couldn't QI jar entry URI to nsIURL!");
713 return false;
714 }
715
716 mJARFile.swap(file);
717 mJAREntry.swap(entryURL);
718 mCharsetHint = params.charset();
719
720 return true;
721 }
722