|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
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 "nsHostObjectProtocolHandler.h" |
|
8 #include "nsHostObjectURI.h" |
|
9 #include "nsError.h" |
|
10 #include "nsClassHashtable.h" |
|
11 #include "nsNetUtil.h" |
|
12 #include "nsIPrincipal.h" |
|
13 #include "nsIDOMFile.h" |
|
14 #include "nsIDOMMediaStream.h" |
|
15 #include "mozilla/dom/MediaSource.h" |
|
16 #include "nsIMemoryReporter.h" |
|
17 #include "mozilla/Preferences.h" |
|
18 |
|
19 // ----------------------------------------------------------------------- |
|
20 // Hash table |
|
21 struct DataInfo |
|
22 { |
|
23 // mObject is expected to be an nsIDOMBlob, nsIDOMMediaStream, or MediaSource |
|
24 nsCOMPtr<nsISupports> mObject; |
|
25 nsCOMPtr<nsIPrincipal> mPrincipal; |
|
26 nsCString mStack; |
|
27 }; |
|
28 |
|
29 static nsClassHashtable<nsCStringHashKey, DataInfo>* gDataTable; |
|
30 |
|
31 // Memory reporting for the hash table. |
|
32 namespace mozilla { |
|
33 |
|
34 class HostObjectURLsReporter MOZ_FINAL : public nsIMemoryReporter |
|
35 { |
|
36 public: |
|
37 NS_DECL_ISUPPORTS |
|
38 |
|
39 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, |
|
40 nsISupports* aData) |
|
41 { |
|
42 return MOZ_COLLECT_REPORT( |
|
43 "host-object-urls", KIND_OTHER, UNITS_COUNT, |
|
44 gDataTable ? gDataTable->Count() : 0, |
|
45 "The number of host objects stored for access via URLs " |
|
46 "(e.g. blobs passed to URL.createObjectURL)."); |
|
47 } |
|
48 }; |
|
49 |
|
50 NS_IMPL_ISUPPORTS(HostObjectURLsReporter, nsIMemoryReporter) |
|
51 |
|
52 class BlobURLsReporter MOZ_FINAL : public nsIMemoryReporter |
|
53 { |
|
54 public: |
|
55 NS_DECL_ISUPPORTS |
|
56 |
|
57 NS_IMETHOD CollectReports(nsIHandleReportCallback* aCallback, |
|
58 nsISupports* aData) |
|
59 { |
|
60 EnumArg env; |
|
61 env.mCallback = aCallback; |
|
62 env.mData = aData; |
|
63 |
|
64 if (gDataTable) { |
|
65 gDataTable->EnumerateRead(CountCallback, &env); |
|
66 gDataTable->EnumerateRead(ReportCallback, &env); |
|
67 } |
|
68 return NS_OK; |
|
69 } |
|
70 |
|
71 // Initialize info->mStack to record JS stack info, if enabled. |
|
72 // The string generated here is used in ReportCallback, below. |
|
73 static void GetJSStackForBlob(DataInfo* aInfo) |
|
74 { |
|
75 nsCString& stack = aInfo->mStack; |
|
76 MOZ_ASSERT(stack.IsEmpty()); |
|
77 const uint32_t maxFrames = Preferences::GetUint("memory.blob_report.stack_frames"); |
|
78 |
|
79 if (maxFrames == 0) { |
|
80 return; |
|
81 } |
|
82 |
|
83 nsresult rv; |
|
84 nsIXPConnect* xpc = nsContentUtils::XPConnect(); |
|
85 nsCOMPtr<nsIStackFrame> frame; |
|
86 rv = xpc->GetCurrentJSStack(getter_AddRefs(frame)); |
|
87 NS_ENSURE_SUCCESS_VOID(rv); |
|
88 |
|
89 nsAutoCString origin; |
|
90 nsCOMPtr<nsIURI> principalURI; |
|
91 if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI))) |
|
92 && principalURI) { |
|
93 principalURI->GetPrePath(origin); |
|
94 } |
|
95 |
|
96 for (uint32_t i = 0; i < maxFrames && frame; ++i) { |
|
97 nsString fileNameUTF16; |
|
98 int32_t lineNumber = 0; |
|
99 |
|
100 frame->GetFilename(fileNameUTF16); |
|
101 frame->GetLineNumber(&lineNumber); |
|
102 |
|
103 if (!fileNameUTF16.IsEmpty()) { |
|
104 NS_ConvertUTF16toUTF8 fileName(fileNameUTF16); |
|
105 stack += "js("; |
|
106 if (!origin.IsEmpty()) { |
|
107 // Make the file name root-relative for conciseness if possible. |
|
108 const char* originData; |
|
109 uint32_t originLen; |
|
110 |
|
111 originLen = origin.GetData(&originData); |
|
112 // If fileName starts with origin + "/", cut up to that "/". |
|
113 if (fileName.Length() >= originLen + 1 && |
|
114 memcmp(fileName.get(), originData, originLen) == 0 && |
|
115 fileName[originLen] == '/') { |
|
116 fileName.Cut(0, originLen); |
|
117 } |
|
118 } |
|
119 fileName.ReplaceChar('/', '\\'); |
|
120 stack += fileName; |
|
121 if (lineNumber > 0) { |
|
122 stack += ", line="; |
|
123 stack.AppendInt(lineNumber); |
|
124 } |
|
125 stack += ")/"; |
|
126 } |
|
127 |
|
128 rv = frame->GetCaller(getter_AddRefs(frame)); |
|
129 NS_ENSURE_SUCCESS_VOID(rv); |
|
130 } |
|
131 } |
|
132 |
|
133 private: |
|
134 struct EnumArg { |
|
135 nsIHandleReportCallback* mCallback; |
|
136 nsISupports* mData; |
|
137 nsDataHashtable<nsPtrHashKey<nsIDOMBlob>, uint32_t> mRefCounts; |
|
138 }; |
|
139 |
|
140 // Determine number of URLs per blob, to handle the case where it's > 1. |
|
141 static PLDHashOperator CountCallback(nsCStringHashKey::KeyType aKey, |
|
142 DataInfo* aInfo, |
|
143 void* aUserArg) |
|
144 { |
|
145 EnumArg* envp = static_cast<EnumArg*>(aUserArg); |
|
146 nsCOMPtr<nsIDOMBlob> blob; |
|
147 |
|
148 blob = do_QueryInterface(aInfo->mObject); |
|
149 if (blob) { |
|
150 envp->mRefCounts.Put(blob, envp->mRefCounts.Get(blob) + 1); |
|
151 } |
|
152 return PL_DHASH_NEXT; |
|
153 } |
|
154 |
|
155 static PLDHashOperator ReportCallback(nsCStringHashKey::KeyType aKey, |
|
156 DataInfo* aInfo, |
|
157 void* aUserArg) |
|
158 { |
|
159 EnumArg* envp = static_cast<EnumArg*>(aUserArg); |
|
160 nsCOMPtr<nsIDOMBlob> blob; |
|
161 |
|
162 blob = do_QueryInterface(aInfo->mObject); |
|
163 if (blob) { |
|
164 NS_NAMED_LITERAL_CSTRING |
|
165 (desc, "A blob URL allocated with URL.createObjectURL; the referenced " |
|
166 "blob cannot be freed until all URLs for it have been explicitly " |
|
167 "invalidated with URL.revokeObjectURL."); |
|
168 nsAutoCString path, url, owner, specialDesc; |
|
169 nsCOMPtr<nsIURI> principalURI; |
|
170 uint64_t size = 0; |
|
171 uint32_t refCount = 1; |
|
172 DebugOnly<bool> blobWasCounted; |
|
173 |
|
174 blobWasCounted = envp->mRefCounts.Get(blob, &refCount); |
|
175 MOZ_ASSERT(blobWasCounted); |
|
176 MOZ_ASSERT(refCount > 0); |
|
177 |
|
178 bool isMemoryFile = blob->IsMemoryFile(); |
|
179 |
|
180 if (isMemoryFile) { |
|
181 if (NS_FAILED(blob->GetSize(&size))) { |
|
182 size = 0; |
|
183 } |
|
184 } |
|
185 |
|
186 path = isMemoryFile ? "memory-blob-urls/" : "file-blob-urls/"; |
|
187 if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI))) && |
|
188 principalURI != nullptr && |
|
189 NS_SUCCEEDED(principalURI->GetSpec(owner)) && |
|
190 !owner.IsEmpty()) { |
|
191 owner.ReplaceChar('/', '\\'); |
|
192 path += "owner("; |
|
193 path += owner; |
|
194 path += ")"; |
|
195 } else { |
|
196 path += "owner unknown"; |
|
197 } |
|
198 path += "/"; |
|
199 path += aInfo->mStack; |
|
200 url = aKey; |
|
201 url.ReplaceChar('/', '\\'); |
|
202 path += url; |
|
203 if (refCount > 1) { |
|
204 nsAutoCString addrStr; |
|
205 |
|
206 addrStr = "0x"; |
|
207 addrStr.AppendInt((uint64_t)(nsIDOMBlob*)blob, 16); |
|
208 |
|
209 path += " "; |
|
210 path.AppendInt(refCount); |
|
211 path += "@"; |
|
212 path += addrStr; |
|
213 |
|
214 specialDesc = desc; |
|
215 specialDesc += "\n\nNOTE: This blob (address "; |
|
216 specialDesc += addrStr; |
|
217 specialDesc += ") has "; |
|
218 specialDesc.AppendInt(refCount); |
|
219 specialDesc += " URLs."; |
|
220 if (isMemoryFile) { |
|
221 specialDesc += " Its size is divided "; |
|
222 specialDesc += refCount > 2 ? "among" : "between"; |
|
223 specialDesc += " them in this report."; |
|
224 } |
|
225 } |
|
226 |
|
227 const nsACString& descString = specialDesc.IsEmpty() |
|
228 ? static_cast<const nsACString&>(desc) |
|
229 : static_cast<const nsACString&>(specialDesc); |
|
230 if (isMemoryFile) { |
|
231 envp->mCallback->Callback(EmptyCString(), |
|
232 path, |
|
233 KIND_OTHER, |
|
234 UNITS_BYTES, |
|
235 size / refCount, |
|
236 descString, |
|
237 envp->mData); |
|
238 } |
|
239 else { |
|
240 envp->mCallback->Callback(EmptyCString(), |
|
241 path, |
|
242 KIND_OTHER, |
|
243 UNITS_COUNT, |
|
244 1, |
|
245 descString, |
|
246 envp->mData); |
|
247 } |
|
248 } |
|
249 return PL_DHASH_NEXT; |
|
250 } |
|
251 }; |
|
252 |
|
253 NS_IMPL_ISUPPORTS(BlobURLsReporter, nsIMemoryReporter) |
|
254 |
|
255 } |
|
256 |
|
257 void |
|
258 nsHostObjectProtocolHandler::Init(void) |
|
259 { |
|
260 static bool initialized = false; |
|
261 |
|
262 if (!initialized) { |
|
263 initialized = true; |
|
264 RegisterStrongMemoryReporter(new mozilla::HostObjectURLsReporter()); |
|
265 RegisterStrongMemoryReporter(new mozilla::BlobURLsReporter()); |
|
266 } |
|
267 } |
|
268 |
|
269 nsHostObjectProtocolHandler::nsHostObjectProtocolHandler() |
|
270 { |
|
271 Init(); |
|
272 } |
|
273 |
|
274 nsresult |
|
275 nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme, |
|
276 nsISupports* aObject, |
|
277 nsIPrincipal* aPrincipal, |
|
278 nsACString& aUri) |
|
279 { |
|
280 Init(); |
|
281 |
|
282 nsresult rv = GenerateURIString(aScheme, aUri); |
|
283 NS_ENSURE_SUCCESS(rv, rv); |
|
284 |
|
285 if (!gDataTable) { |
|
286 gDataTable = new nsClassHashtable<nsCStringHashKey, DataInfo>; |
|
287 } |
|
288 |
|
289 DataInfo* info = new DataInfo; |
|
290 |
|
291 info->mObject = aObject; |
|
292 info->mPrincipal = aPrincipal; |
|
293 mozilla::BlobURLsReporter::GetJSStackForBlob(info); |
|
294 |
|
295 gDataTable->Put(aUri, info); |
|
296 return NS_OK; |
|
297 } |
|
298 |
|
299 void |
|
300 nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri) |
|
301 { |
|
302 if (gDataTable) { |
|
303 nsCString uriIgnoringRef; |
|
304 int32_t hashPos = aUri.FindChar('#'); |
|
305 if (hashPos < 0) { |
|
306 uriIgnoringRef = aUri; |
|
307 } |
|
308 else { |
|
309 uriIgnoringRef = StringHead(aUri, hashPos); |
|
310 } |
|
311 gDataTable->Remove(uriIgnoringRef); |
|
312 if (gDataTable->Count() == 0) { |
|
313 delete gDataTable; |
|
314 gDataTable = nullptr; |
|
315 } |
|
316 } |
|
317 } |
|
318 |
|
319 nsresult |
|
320 nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme, |
|
321 nsACString& aUri) |
|
322 { |
|
323 nsresult rv; |
|
324 nsCOMPtr<nsIUUIDGenerator> uuidgen = |
|
325 do_GetService("@mozilla.org/uuid-generator;1", &rv); |
|
326 NS_ENSURE_SUCCESS(rv, rv); |
|
327 |
|
328 nsID id; |
|
329 rv = uuidgen->GenerateUUIDInPlace(&id); |
|
330 NS_ENSURE_SUCCESS(rv, rv); |
|
331 |
|
332 char chars[NSID_LENGTH]; |
|
333 id.ToProvidedString(chars); |
|
334 |
|
335 aUri += aScheme; |
|
336 aUri += NS_LITERAL_CSTRING(":"); |
|
337 aUri += Substring(chars + 1, chars + NSID_LENGTH - 2); |
|
338 |
|
339 return NS_OK; |
|
340 } |
|
341 |
|
342 static DataInfo* |
|
343 GetDataInfo(const nsACString& aUri) |
|
344 { |
|
345 if (!gDataTable) { |
|
346 return nullptr; |
|
347 } |
|
348 |
|
349 DataInfo* res; |
|
350 nsCString uriIgnoringRef; |
|
351 int32_t hashPos = aUri.FindChar('#'); |
|
352 if (hashPos < 0) { |
|
353 uriIgnoringRef = aUri; |
|
354 } |
|
355 else { |
|
356 uriIgnoringRef = StringHead(aUri, hashPos); |
|
357 } |
|
358 gDataTable->Get(uriIgnoringRef, &res); |
|
359 |
|
360 return res; |
|
361 } |
|
362 |
|
363 nsIPrincipal* |
|
364 nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri) |
|
365 { |
|
366 if (!gDataTable) { |
|
367 return nullptr; |
|
368 } |
|
369 |
|
370 DataInfo* res = GetDataInfo(aUri); |
|
371 |
|
372 if (!res) { |
|
373 return nullptr; |
|
374 } |
|
375 |
|
376 return res->mPrincipal; |
|
377 } |
|
378 |
|
379 void |
|
380 nsHostObjectProtocolHandler::Traverse(const nsACString& aUri, |
|
381 nsCycleCollectionTraversalCallback& aCallback) |
|
382 { |
|
383 if (!gDataTable) { |
|
384 return; |
|
385 } |
|
386 |
|
387 DataInfo* res; |
|
388 gDataTable->Get(aUri, &res); |
|
389 if (!res) { |
|
390 return; |
|
391 } |
|
392 |
|
393 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mObject"); |
|
394 aCallback.NoteXPCOMChild(res->mObject); |
|
395 } |
|
396 |
|
397 static nsISupports* |
|
398 GetDataObject(nsIURI* aURI) |
|
399 { |
|
400 nsCString spec; |
|
401 aURI->GetSpec(spec); |
|
402 |
|
403 DataInfo* info = GetDataInfo(spec); |
|
404 return info ? info->mObject : nullptr; |
|
405 } |
|
406 |
|
407 // ----------------------------------------------------------------------- |
|
408 // Protocol handler |
|
409 |
|
410 NS_IMPL_ISUPPORTS(nsHostObjectProtocolHandler, nsIProtocolHandler) |
|
411 |
|
412 NS_IMETHODIMP |
|
413 nsHostObjectProtocolHandler::GetDefaultPort(int32_t *result) |
|
414 { |
|
415 *result = -1; |
|
416 return NS_OK; |
|
417 } |
|
418 |
|
419 NS_IMETHODIMP |
|
420 nsHostObjectProtocolHandler::GetProtocolFlags(uint32_t *result) |
|
421 { |
|
422 *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_SUBSUMERS | |
|
423 URI_IS_LOCAL_RESOURCE | URI_NON_PERSISTABLE; |
|
424 return NS_OK; |
|
425 } |
|
426 |
|
427 NS_IMETHODIMP |
|
428 nsHostObjectProtocolHandler::NewURI(const nsACString& aSpec, |
|
429 const char *aCharset, |
|
430 nsIURI *aBaseURI, |
|
431 nsIURI **aResult) |
|
432 { |
|
433 *aResult = nullptr; |
|
434 nsresult rv; |
|
435 |
|
436 DataInfo* info = GetDataInfo(aSpec); |
|
437 |
|
438 nsRefPtr<nsHostObjectURI> uri = |
|
439 new nsHostObjectURI(info ? info->mPrincipal.get() : nullptr); |
|
440 |
|
441 rv = uri->SetSpec(aSpec); |
|
442 NS_ENSURE_SUCCESS(rv, rv); |
|
443 |
|
444 NS_TryToSetImmutable(uri); |
|
445 uri.forget(aResult); |
|
446 |
|
447 return NS_OK; |
|
448 } |
|
449 |
|
450 NS_IMETHODIMP |
|
451 nsHostObjectProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) |
|
452 { |
|
453 *result = nullptr; |
|
454 |
|
455 nsCString spec; |
|
456 uri->GetSpec(spec); |
|
457 |
|
458 DataInfo* info = GetDataInfo(spec); |
|
459 |
|
460 if (!info) { |
|
461 return NS_ERROR_DOM_BAD_URI; |
|
462 } |
|
463 nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(info->mObject); |
|
464 if (!blob) { |
|
465 return NS_ERROR_DOM_BAD_URI; |
|
466 } |
|
467 |
|
468 #ifdef DEBUG |
|
469 { |
|
470 nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri); |
|
471 nsCOMPtr<nsIPrincipal> principal; |
|
472 uriPrinc->GetPrincipal(getter_AddRefs(principal)); |
|
473 NS_ASSERTION(info->mPrincipal == principal, "Wrong principal!"); |
|
474 } |
|
475 #endif |
|
476 |
|
477 nsCOMPtr<nsIInputStream> stream; |
|
478 nsresult rv = blob->GetInternalStream(getter_AddRefs(stream)); |
|
479 NS_ENSURE_SUCCESS(rv, rv); |
|
480 |
|
481 nsCOMPtr<nsIChannel> channel; |
|
482 rv = NS_NewInputStreamChannel(getter_AddRefs(channel), |
|
483 uri, |
|
484 stream); |
|
485 NS_ENSURE_SUCCESS(rv, rv); |
|
486 |
|
487 nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal); |
|
488 |
|
489 nsString type; |
|
490 rv = blob->GetType(type); |
|
491 NS_ENSURE_SUCCESS(rv, rv); |
|
492 |
|
493 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(info->mObject); |
|
494 if (file) { |
|
495 nsString filename; |
|
496 rv = file->GetName(filename); |
|
497 NS_ENSURE_SUCCESS(rv, rv); |
|
498 channel->SetContentDispositionFilename(filename); |
|
499 } |
|
500 |
|
501 uint64_t size; |
|
502 rv = blob->GetSize(&size); |
|
503 NS_ENSURE_SUCCESS(rv, rv); |
|
504 |
|
505 channel->SetOwner(owner); |
|
506 channel->SetOriginalURI(uri); |
|
507 channel->SetContentType(NS_ConvertUTF16toUTF8(type)); |
|
508 channel->SetContentLength(size); |
|
509 |
|
510 channel.forget(result); |
|
511 |
|
512 return NS_OK; |
|
513 } |
|
514 |
|
515 NS_IMETHODIMP |
|
516 nsHostObjectProtocolHandler::AllowPort(int32_t port, const char *scheme, |
|
517 bool *_retval) |
|
518 { |
|
519 // don't override anything. |
|
520 *_retval = false; |
|
521 return NS_OK; |
|
522 } |
|
523 |
|
524 NS_IMETHODIMP |
|
525 nsBlobProtocolHandler::GetScheme(nsACString &result) |
|
526 { |
|
527 result.AssignLiteral(BLOBURI_SCHEME); |
|
528 return NS_OK; |
|
529 } |
|
530 |
|
531 NS_IMETHODIMP |
|
532 nsMediaStreamProtocolHandler::GetScheme(nsACString &result) |
|
533 { |
|
534 result.AssignLiteral(MEDIASTREAMURI_SCHEME); |
|
535 return NS_OK; |
|
536 } |
|
537 |
|
538 NS_IMETHODIMP |
|
539 nsMediaSourceProtocolHandler::GetScheme(nsACString &result) |
|
540 { |
|
541 result.AssignLiteral(MEDIASOURCEURI_SCHEME); |
|
542 return NS_OK; |
|
543 } |
|
544 |
|
545 NS_IMETHODIMP |
|
546 nsFontTableProtocolHandler::GetScheme(nsACString &result) |
|
547 { |
|
548 result.AssignLiteral(FONTTABLEURI_SCHEME); |
|
549 return NS_OK; |
|
550 } |
|
551 |
|
552 nsresult |
|
553 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream) |
|
554 { |
|
555 NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs"); |
|
556 |
|
557 *aStream = nullptr; |
|
558 |
|
559 nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(GetDataObject(aURI)); |
|
560 if (!blob) { |
|
561 return NS_ERROR_DOM_BAD_URI; |
|
562 } |
|
563 |
|
564 return blob->GetInternalStream(aStream); |
|
565 } |
|
566 |
|
567 nsresult |
|
568 NS_GetStreamForMediaStreamURI(nsIURI* aURI, nsIDOMMediaStream** aStream) |
|
569 { |
|
570 NS_ASSERTION(IsMediaStreamURI(aURI), "Only call this with mediastream URIs"); |
|
571 |
|
572 *aStream = nullptr; |
|
573 |
|
574 nsCOMPtr<nsIDOMMediaStream> stream = do_QueryInterface(GetDataObject(aURI)); |
|
575 if (!stream) { |
|
576 return NS_ERROR_DOM_BAD_URI; |
|
577 } |
|
578 |
|
579 *aStream = stream; |
|
580 NS_ADDREF(*aStream); |
|
581 return NS_OK; |
|
582 } |
|
583 |
|
584 NS_IMETHODIMP |
|
585 nsFontTableProtocolHandler::NewURI(const nsACString& aSpec, |
|
586 const char *aCharset, |
|
587 nsIURI *aBaseURI, |
|
588 nsIURI **aResult) |
|
589 { |
|
590 nsRefPtr<nsIURI> uri; |
|
591 |
|
592 // Either you got here via a ref or a fonttable: uri |
|
593 if (aSpec.Length() && aSpec.CharAt(0) == '#') { |
|
594 nsresult rv = aBaseURI->CloneIgnoringRef(getter_AddRefs(uri)); |
|
595 NS_ENSURE_SUCCESS(rv, rv); |
|
596 |
|
597 uri->SetRef(aSpec); |
|
598 } else { |
|
599 // Relative URIs (other than #ref) are not meaningful within the |
|
600 // fonttable: scheme. |
|
601 // If aSpec is a relative URI -other- than a bare #ref, |
|
602 // this will leave uri empty, and we'll return a failure code below. |
|
603 uri = new nsSimpleURI(); |
|
604 uri->SetSpec(aSpec); |
|
605 } |
|
606 |
|
607 bool schemeIs; |
|
608 if (NS_FAILED(uri->SchemeIs(FONTTABLEURI_SCHEME, &schemeIs)) || !schemeIs) { |
|
609 NS_WARNING("Non-fonttable spec in nsFontTableProtocolHander"); |
|
610 return NS_ERROR_NOT_AVAILABLE; |
|
611 } |
|
612 |
|
613 uri.forget(aResult); |
|
614 return NS_OK; |
|
615 } |
|
616 |
|
617 nsresult |
|
618 NS_GetSourceForMediaSourceURI(nsIURI* aURI, mozilla::dom::MediaSource** aSource) |
|
619 { |
|
620 NS_ASSERTION(IsMediaSourceURI(aURI), "Only call this with mediasource URIs"); |
|
621 |
|
622 *aSource = nullptr; |
|
623 |
|
624 nsCOMPtr<mozilla::dom::MediaSource> source = do_QueryInterface(GetDataObject(aURI)); |
|
625 if (!source) { |
|
626 return NS_ERROR_DOM_BAD_URI; |
|
627 } |
|
628 |
|
629 source.forget(aSource); |
|
630 return NS_OK; |
|
631 } |