netwerk/base/public/nsNetUtil.h

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:a8be10bfba61
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 et cin: */
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 #ifndef nsNetUtil_h__
8 #define nsNetUtil_h__
9
10 #include "nsError.h"
11 #include "nsNetCID.h"
12 #include "nsStringGlue.h"
13 #include "nsMemory.h"
14 #include "nsCOMPtr.h"
15 #include "prio.h" // for read/write flags, permissions, etc.
16 #include "nsHashKeys.h"
17
18 #include "plstr.h"
19 #include "nsIURI.h"
20 #include "nsIStandardURL.h"
21 #include "nsIURLParser.h"
22 #include "nsIUUIDGenerator.h"
23 #include "nsIInputStream.h"
24 #include "nsIOutputStream.h"
25 #include "nsISafeOutputStream.h"
26 #include "nsIStreamListener.h"
27 #include "nsIRequestObserverProxy.h"
28 #include "nsISimpleStreamListener.h"
29 #include "nsILoadGroup.h"
30 #include "nsIInterfaceRequestor.h"
31 #include "nsIInterfaceRequestorUtils.h"
32 #include "nsIIOService.h"
33 #include "nsIServiceManager.h"
34 #include "nsIChannel.h"
35 #include "nsChannelProperties.h"
36 #include "nsIInputStreamChannel.h"
37 #include "nsITransport.h"
38 #include "nsIStreamTransportService.h"
39 #include "nsIHttpChannel.h"
40 #include "nsIDownloader.h"
41 #include "nsIStreamLoader.h"
42 #include "nsIUnicharStreamLoader.h"
43 #include "nsIPipe.h"
44 #include "nsIProtocolHandler.h"
45 #include "nsIFileProtocolHandler.h"
46 #include "nsIStringStream.h"
47 #include "nsIFile.h"
48 #include "nsIFileStreams.h"
49 #include "nsIFileURL.h"
50 #include "nsIProtocolProxyService.h"
51 #include "nsIProxyInfo.h"
52 #include "nsIFileStreams.h"
53 #include "nsIBufferedStreams.h"
54 #include "nsIInputStreamPump.h"
55 #include "nsIAsyncStreamCopier.h"
56 #include "nsIPersistentProperties2.h"
57 #include "nsISyncStreamListener.h"
58 #include "nsInterfaceRequestorAgg.h"
59 #include "nsINetUtil.h"
60 #include "nsIURIWithPrincipal.h"
61 #include "nsIAuthPrompt.h"
62 #include "nsIAuthPrompt2.h"
63 #include "nsIAuthPromptAdapterFactory.h"
64 #include "nsComponentManagerUtils.h"
65 #include "nsServiceManagerUtils.h"
66 #include "nsINestedURI.h"
67 #include "nsIMutable.h"
68 #include "nsIPropertyBag2.h"
69 #include "nsIWritablePropertyBag2.h"
70 #include "nsIIDNService.h"
71 #include "nsIChannelEventSink.h"
72 #include "nsIChannelPolicy.h"
73 #include "nsISocketProviderService.h"
74 #include "nsISocketProvider.h"
75 #include "nsIRedirectChannelRegistrar.h"
76 #include "nsIMIMEHeaderParam.h"
77 #include "nsILoadContext.h"
78 #include "mozilla/Services.h"
79 #include "nsIPrivateBrowsingChannel.h"
80 #include "mozIApplicationClearPrivateDataParams.h"
81 #include "nsIOfflineCacheUpdate.h"
82 #include "nsIContentSniffer.h"
83 #include "nsCategoryCache.h"
84 #include "nsStringStream.h"
85 #include "nsIViewSourceChannel.h"
86
87 #include <limits>
88
89 #ifdef MOZILLA_INTERNAL_API
90
91 #include "nsReadableUtils.h"
92
93 inline already_AddRefed<nsIIOService>
94 do_GetIOService(nsresult* error = 0)
95 {
96 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
97 if (error)
98 *error = io ? NS_OK : NS_ERROR_FAILURE;
99 return io.forget();
100 }
101
102 inline already_AddRefed<nsINetUtil>
103 do_GetNetUtil(nsresult *error = 0)
104 {
105 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
106 nsCOMPtr<nsINetUtil> util;
107 if (io)
108 util = do_QueryInterface(io);
109
110 if (error)
111 *error = !!util ? NS_OK : NS_ERROR_FAILURE;
112 return util.forget();
113 }
114 #else
115 // Helper, to simplify getting the I/O service.
116 inline const nsGetServiceByContractIDWithError
117 do_GetIOService(nsresult* error = 0)
118 {
119 return nsGetServiceByContractIDWithError(NS_IOSERVICE_CONTRACTID, error);
120 }
121
122 // An alias to do_GetIOService
123 inline const nsGetServiceByContractIDWithError
124 do_GetNetUtil(nsresult* error = 0)
125 {
126 return do_GetIOService(error);
127 }
128 #endif
129
130 // private little helper function... don't call this directly!
131 inline nsresult
132 net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip)
133 {
134 nsresult rv = NS_OK;
135 if (!*ios) {
136 grip = do_GetIOService(&rv);
137 *ios = grip;
138 }
139 return rv;
140 }
141
142 inline nsresult
143 NS_NewURI(nsIURI **result,
144 const nsACString &spec,
145 const char *charset = nullptr,
146 nsIURI *baseURI = nullptr,
147 nsIIOService *ioService = nullptr) // pass in nsIIOService to optimize callers
148 {
149 nsresult rv;
150 nsCOMPtr<nsIIOService> grip;
151 rv = net_EnsureIOService(&ioService, grip);
152 if (ioService)
153 rv = ioService->NewURI(spec, charset, baseURI, result);
154 return rv;
155 }
156
157 inline nsresult
158 NS_NewURI(nsIURI* *result,
159 const nsAString& spec,
160 const char *charset = nullptr,
161 nsIURI* baseURI = nullptr,
162 nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers
163 {
164 return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI, ioService);
165 }
166
167 inline nsresult
168 NS_NewURI(nsIURI* *result,
169 const char *spec,
170 nsIURI* baseURI = nullptr,
171 nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers
172 {
173 return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI, ioService);
174 }
175
176 inline nsresult
177 NS_NewFileURI(nsIURI* *result,
178 nsIFile* spec,
179 nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers
180 {
181 nsresult rv;
182 nsCOMPtr<nsIIOService> grip;
183 rv = net_EnsureIOService(&ioService, grip);
184 if (ioService)
185 rv = ioService->NewFileURI(spec, result);
186 return rv;
187 }
188
189 inline nsresult
190 NS_NewChannel(nsIChannel **result,
191 nsIURI *uri,
192 nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers
193 nsILoadGroup *loadGroup = nullptr,
194 nsIInterfaceRequestor *callbacks = nullptr,
195 uint32_t loadFlags = nsIRequest::LOAD_NORMAL,
196 nsIChannelPolicy *channelPolicy = nullptr)
197 {
198 nsresult rv;
199 nsCOMPtr<nsIIOService> grip;
200 rv = net_EnsureIOService(&ioService, grip);
201 if (ioService) {
202 nsCOMPtr<nsIChannel> chan;
203 rv = ioService->NewChannelFromURI(uri, getter_AddRefs(chan));
204 if (NS_SUCCEEDED(rv)) {
205 if (loadGroup) {
206 rv = chan->SetLoadGroup(loadGroup);
207 }
208 if (callbacks) {
209 nsresult tmp = chan->SetNotificationCallbacks(callbacks);
210 if (NS_FAILED(tmp)) {
211 rv = tmp;
212 }
213 }
214 if (loadFlags != nsIRequest::LOAD_NORMAL) {
215 // Retain the LOAD_REPLACE load flag if set.
216 nsLoadFlags normalLoadFlags = 0;
217 chan->GetLoadFlags(&normalLoadFlags);
218 nsresult tmp = chan->SetLoadFlags(loadFlags |
219 (normalLoadFlags &
220 nsIChannel::LOAD_REPLACE));
221 if (NS_FAILED(tmp)) {
222 rv = tmp;
223 }
224 }
225 if (channelPolicy) {
226 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(chan);
227 if (props) {
228 props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
229 channelPolicy);
230 }
231 }
232 if (NS_SUCCEEDED(rv))
233 chan.forget(result);
234 }
235 }
236 return rv;
237 }
238
239 // Use this function with CAUTION. It creates a stream that blocks when you
240 // Read() from it and blocking the UI thread is a bad idea. If you don't want
241 // to implement a full blown asynchronous consumer (via nsIStreamListener) look
242 // at nsIStreamLoader instead.
243 inline nsresult
244 NS_OpenURI(nsIInputStream **result,
245 nsIURI *uri,
246 nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers
247 nsILoadGroup *loadGroup = nullptr,
248 nsIInterfaceRequestor *callbacks = nullptr,
249 uint32_t loadFlags = nsIRequest::LOAD_NORMAL,
250 nsIChannel **channelOut = nullptr)
251 {
252 nsresult rv;
253 nsCOMPtr<nsIChannel> channel;
254 rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
255 loadGroup, callbacks, loadFlags);
256 if (NS_SUCCEEDED(rv)) {
257 nsIInputStream *stream;
258 rv = channel->Open(&stream);
259 if (NS_SUCCEEDED(rv)) {
260 *result = stream;
261 if (channelOut) {
262 *channelOut = nullptr;
263 channel.swap(*channelOut);
264 }
265 }
266 }
267 return rv;
268 }
269
270 inline nsresult
271 NS_OpenURI(nsIStreamListener *listener,
272 nsISupports *context,
273 nsIURI *uri,
274 nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers
275 nsILoadGroup *loadGroup = nullptr,
276 nsIInterfaceRequestor *callbacks = nullptr,
277 uint32_t loadFlags = nsIRequest::LOAD_NORMAL)
278 {
279 nsresult rv;
280 nsCOMPtr<nsIChannel> channel;
281 rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
282 loadGroup, callbacks, loadFlags);
283 if (NS_SUCCEEDED(rv))
284 rv = channel->AsyncOpen(listener, context);
285 return rv;
286 }
287
288 inline nsresult
289 NS_MakeAbsoluteURI(nsACString &result,
290 const nsACString &spec,
291 nsIURI *baseURI)
292 {
293 nsresult rv;
294 if (!baseURI) {
295 NS_WARNING("It doesn't make sense to not supply a base URI");
296 result = spec;
297 rv = NS_OK;
298 }
299 else if (spec.IsEmpty())
300 rv = baseURI->GetSpec(result);
301 else
302 rv = baseURI->Resolve(spec, result);
303 return rv;
304 }
305
306 inline nsresult
307 NS_MakeAbsoluteURI(char **result,
308 const char *spec,
309 nsIURI *baseURI)
310 {
311 nsresult rv;
312 nsAutoCString resultBuf;
313 rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
314 if (NS_SUCCEEDED(rv)) {
315 *result = ToNewCString(resultBuf);
316 if (!*result)
317 rv = NS_ERROR_OUT_OF_MEMORY;
318 }
319 return rv;
320 }
321
322 inline nsresult
323 NS_MakeAbsoluteURI(nsAString &result,
324 const nsAString &spec,
325 nsIURI *baseURI)
326 {
327 nsresult rv;
328 if (!baseURI) {
329 NS_WARNING("It doesn't make sense to not supply a base URI");
330 result = spec;
331 rv = NS_OK;
332 }
333 else {
334 nsAutoCString resultBuf;
335 if (spec.IsEmpty())
336 rv = baseURI->GetSpec(resultBuf);
337 else
338 rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
339 if (NS_SUCCEEDED(rv))
340 CopyUTF8toUTF16(resultBuf, result);
341 }
342 return rv;
343 }
344
345 /**
346 * This function is a helper function to get a scheme's default port.
347 */
348 inline int32_t
349 NS_GetDefaultPort(const char *scheme,
350 nsIIOService* ioService = nullptr)
351 {
352 nsresult rv;
353
354 nsCOMPtr<nsIIOService> grip;
355 net_EnsureIOService(&ioService, grip);
356 if (!ioService)
357 return -1;
358
359 nsCOMPtr<nsIProtocolHandler> handler;
360 rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
361 if (NS_FAILED(rv))
362 return -1;
363 int32_t port;
364 rv = handler->GetDefaultPort(&port);
365 return NS_SUCCEEDED(rv) ? port : -1;
366 }
367
368 /**
369 * This function is a helper function to apply the ToAscii conversion
370 * to a string
371 */
372 inline bool
373 NS_StringToACE(const nsACString &idn, nsACString &result)
374 {
375 nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
376 if (!idnSrv)
377 return false;
378 nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
379 if (NS_FAILED(rv))
380 return false;
381
382 return true;
383 }
384
385 /**
386 * This function is a helper function to get a protocol's default port if the
387 * URI does not specify a port explicitly. Returns -1 if this protocol has no
388 * concept of ports or if there was an error getting the port.
389 */
390 inline int32_t
391 NS_GetRealPort(nsIURI* aURI)
392 {
393 int32_t port;
394 nsresult rv = aURI->GetPort(&port);
395 if (NS_FAILED(rv))
396 return -1;
397
398 if (port != -1)
399 return port; // explicitly specified
400
401 // Otherwise, we have to get the default port from the protocol handler
402
403 // Need the scheme first
404 nsAutoCString scheme;
405 rv = aURI->GetScheme(scheme);
406 if (NS_FAILED(rv))
407 return -1;
408
409 return NS_GetDefaultPort(scheme.get());
410 }
411
412 inline nsresult
413 NS_NewInputStreamChannel(nsIChannel **result,
414 nsIURI *uri,
415 nsIInputStream *stream,
416 const nsACString &contentType,
417 const nsACString *contentCharset)
418 {
419 nsresult rv;
420 nsCOMPtr<nsIInputStreamChannel> isc =
421 do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
422 if (NS_FAILED(rv))
423 return rv;
424 rv = isc->SetURI(uri);
425 nsresult tmp = isc->SetContentStream(stream);
426 if (NS_FAILED(tmp)) {
427 rv = tmp;
428 }
429 if (NS_FAILED(rv))
430 return rv;
431 nsCOMPtr<nsIChannel> chan = do_QueryInterface(isc, &rv);
432 if (NS_FAILED(rv))
433 return rv;
434 if (!contentType.IsEmpty())
435 rv = chan->SetContentType(contentType);
436 if (contentCharset && !contentCharset->IsEmpty()) {
437 tmp = chan->SetContentCharset(*contentCharset);
438 if (NS_FAILED(tmp)) {
439 rv = tmp;
440 }
441 }
442 if (NS_SUCCEEDED(rv)) {
443 *result = nullptr;
444 chan.swap(*result);
445 }
446 return rv;
447 }
448
449 inline nsresult
450 NS_NewInputStreamChannel(nsIChannel **result,
451 nsIURI *uri,
452 nsIInputStream *stream,
453 const nsACString &contentType = EmptyCString())
454 {
455 return NS_NewInputStreamChannel(result, uri, stream, contentType, nullptr);
456 }
457
458 inline nsresult
459 NS_NewInputStreamChannel(nsIChannel **result,
460 nsIURI *uri,
461 nsIInputStream *stream,
462 const nsACString &contentType,
463 const nsACString &contentCharset)
464 {
465 return NS_NewInputStreamChannel(result, uri, stream, contentType,
466 &contentCharset);
467 }
468
469 inline nsresult
470 NS_NewInputStreamChannel(nsIChannel **result,
471 nsIURI *uri,
472 const nsAString &data,
473 const nsACString &contentType,
474 bool isSrcdocChannel = false)
475 {
476
477 nsresult rv;
478
479 nsCOMPtr<nsIStringInputStream> stream;
480 stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
481 NS_ENSURE_SUCCESS(rv, rv);
482
483 #ifdef MOZILLA_INTERNAL_API
484 uint32_t len;
485 char* utf8Bytes = ToNewUTF8String(data, &len);
486 rv = stream->AdoptData(utf8Bytes, len);
487 #else
488 char* utf8Bytes = ToNewUTF8String(data);
489 rv = stream->AdoptData(utf8Bytes, strlen(utf8Bytes));
490 #endif
491
492 nsCOMPtr<nsIChannel> chan;
493
494 rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream,
495 contentType, NS_LITERAL_CSTRING("UTF-8"));
496 NS_ENSURE_SUCCESS(rv, rv);
497
498 if (isSrcdocChannel) {
499 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(chan);
500 NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
501 inStrmChan->SetSrcdocData(data);
502 }
503
504 *result = nullptr;
505 chan.swap(*result);
506
507 return NS_OK;
508 }
509
510 inline nsresult
511 NS_NewInputStreamPump(nsIInputStreamPump **result,
512 nsIInputStream *stream,
513 int64_t streamPos = int64_t(-1),
514 int64_t streamLen = int64_t(-1),
515 uint32_t segsize = 0,
516 uint32_t segcount = 0,
517 bool closeWhenDone = false)
518 {
519 nsresult rv;
520 nsCOMPtr<nsIInputStreamPump> pump =
521 do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
522 if (NS_SUCCEEDED(rv)) {
523 rv = pump->Init(stream, streamPos, streamLen,
524 segsize, segcount, closeWhenDone);
525 if (NS_SUCCEEDED(rv)) {
526 *result = nullptr;
527 pump.swap(*result);
528 }
529 }
530 return rv;
531 }
532
533 // NOTE: you will need to specify whether or not your streams are buffered
534 // (i.e., do they implement ReadSegments/WriteSegments). the default
535 // assumption of TRUE for both streams might not be right for you!
536 inline nsresult
537 NS_NewAsyncStreamCopier(nsIAsyncStreamCopier **result,
538 nsIInputStream *source,
539 nsIOutputStream *sink,
540 nsIEventTarget *target,
541 bool sourceBuffered = true,
542 bool sinkBuffered = true,
543 uint32_t chunkSize = 0,
544 bool closeSource = true,
545 bool closeSink = true)
546 {
547 nsresult rv;
548 nsCOMPtr<nsIAsyncStreamCopier> copier =
549 do_CreateInstance(NS_ASYNCSTREAMCOPIER_CONTRACTID, &rv);
550 if (NS_SUCCEEDED(rv)) {
551 rv = copier->Init(source, sink, target, sourceBuffered, sinkBuffered,
552 chunkSize, closeSource, closeSink);
553 if (NS_SUCCEEDED(rv)) {
554 *result = nullptr;
555 copier.swap(*result);
556 }
557 }
558 return rv;
559 }
560
561 inline nsresult
562 NS_NewLoadGroup(nsILoadGroup **result,
563 nsIRequestObserver *obs)
564 {
565 nsresult rv;
566 nsCOMPtr<nsILoadGroup> group =
567 do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
568 if (NS_SUCCEEDED(rv)) {
569 rv = group->SetGroupObserver(obs);
570 if (NS_SUCCEEDED(rv)) {
571 *result = nullptr;
572 group.swap(*result);
573 }
574 }
575 return rv;
576 }
577
578 inline nsresult
579 NS_NewDownloader(nsIStreamListener **result,
580 nsIDownloadObserver *observer,
581 nsIFile *downloadLocation = nullptr)
582 {
583 nsresult rv;
584 nsCOMPtr<nsIDownloader> downloader =
585 do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
586 if (NS_SUCCEEDED(rv)) {
587 rv = downloader->Init(observer, downloadLocation);
588 if (NS_SUCCEEDED(rv))
589 NS_ADDREF(*result = downloader);
590 }
591 return rv;
592 }
593
594 inline nsresult
595 NS_NewStreamLoader(nsIStreamLoader **result,
596 nsIStreamLoaderObserver *observer)
597 {
598 nsresult rv;
599 nsCOMPtr<nsIStreamLoader> loader =
600 do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
601 if (NS_SUCCEEDED(rv)) {
602 rv = loader->Init(observer);
603 if (NS_SUCCEEDED(rv)) {
604 *result = nullptr;
605 loader.swap(*result);
606 }
607 }
608 return rv;
609 }
610
611 inline nsresult
612 NS_NewStreamLoader(nsIStreamLoader **result,
613 nsIURI *uri,
614 nsIStreamLoaderObserver *observer,
615 nsISupports *context = nullptr,
616 nsILoadGroup *loadGroup = nullptr,
617 nsIInterfaceRequestor *callbacks = nullptr,
618 uint32_t loadFlags = nsIRequest::LOAD_NORMAL,
619 nsIURI *referrer = nullptr)
620 {
621 nsresult rv;
622 nsCOMPtr<nsIChannel> channel;
623 rv = NS_NewChannel(getter_AddRefs(channel),
624 uri,
625 nullptr,
626 loadGroup,
627 callbacks,
628 loadFlags);
629 if (NS_SUCCEEDED(rv)) {
630 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
631 if (httpChannel)
632 httpChannel->SetReferrer(referrer);
633 rv = NS_NewStreamLoader(result, observer);
634 if (NS_SUCCEEDED(rv))
635 rv = channel->AsyncOpen(*result, context);
636 }
637 return rv;
638 }
639
640 inline nsresult
641 NS_NewUnicharStreamLoader(nsIUnicharStreamLoader **result,
642 nsIUnicharStreamLoaderObserver *observer)
643 {
644 nsresult rv;
645 nsCOMPtr<nsIUnicharStreamLoader> loader =
646 do_CreateInstance(NS_UNICHARSTREAMLOADER_CONTRACTID, &rv);
647 if (NS_SUCCEEDED(rv)) {
648 rv = loader->Init(observer);
649 if (NS_SUCCEEDED(rv)) {
650 *result = nullptr;
651 loader.swap(*result);
652 }
653 }
654 return rv;
655 }
656
657 inline nsresult
658 NS_NewSyncStreamListener(nsIStreamListener **result,
659 nsIInputStream **stream)
660 {
661 nsresult rv;
662 nsCOMPtr<nsISyncStreamListener> listener =
663 do_CreateInstance(NS_SYNCSTREAMLISTENER_CONTRACTID, &rv);
664 if (NS_SUCCEEDED(rv)) {
665 rv = listener->GetInputStream(stream);
666 if (NS_SUCCEEDED(rv))
667 NS_ADDREF(*result = listener); // cannot use nsCOMPtr::swap
668 }
669 return rv;
670 }
671
672 /**
673 * Implement the nsIChannel::Open(nsIInputStream**) method using the channel's
674 * AsyncOpen method.
675 *
676 * NOTE: Reading from the returned nsIInputStream may spin the current
677 * thread's event queue, which could result in any event being processed.
678 */
679 inline nsresult
680 NS_ImplementChannelOpen(nsIChannel *channel,
681 nsIInputStream **result)
682 {
683 nsCOMPtr<nsIStreamListener> listener;
684 nsCOMPtr<nsIInputStream> stream;
685 nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
686 getter_AddRefs(stream));
687 if (NS_SUCCEEDED(rv)) {
688 rv = channel->AsyncOpen(listener, nullptr);
689 if (NS_SUCCEEDED(rv)) {
690 uint64_t n;
691 // block until the initial response is received or an error occurs.
692 rv = stream->Available(&n);
693 if (NS_SUCCEEDED(rv)) {
694 *result = nullptr;
695 stream.swap(*result);
696 }
697 }
698 }
699 return rv;
700 }
701
702 inline nsresult
703 NS_NewRequestObserverProxy(nsIRequestObserver **result,
704 nsIRequestObserver *observer,
705 nsISupports *context)
706 {
707 nsresult rv;
708 nsCOMPtr<nsIRequestObserverProxy> proxy =
709 do_CreateInstance(NS_REQUESTOBSERVERPROXY_CONTRACTID, &rv);
710 if (NS_SUCCEEDED(rv)) {
711 rv = proxy->Init(observer, context);
712 if (NS_SUCCEEDED(rv))
713 NS_ADDREF(*result = proxy); // cannot use nsCOMPtr::swap
714 }
715 return rv;
716 }
717
718 inline nsresult
719 NS_NewSimpleStreamListener(nsIStreamListener **result,
720 nsIOutputStream *sink,
721 nsIRequestObserver *observer = nullptr)
722 {
723 nsresult rv;
724 nsCOMPtr<nsISimpleStreamListener> listener =
725 do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
726 if (NS_SUCCEEDED(rv)) {
727 rv = listener->Init(sink, observer);
728 if (NS_SUCCEEDED(rv))
729 NS_ADDREF(*result = listener); // cannot use nsCOMPtr::swap
730 }
731 return rv;
732 }
733
734 inline nsresult
735 NS_CheckPortSafety(int32_t port,
736 const char *scheme,
737 nsIIOService *ioService = nullptr)
738 {
739 nsresult rv;
740 nsCOMPtr<nsIIOService> grip;
741 rv = net_EnsureIOService(&ioService, grip);
742 if (ioService) {
743 bool allow;
744 rv = ioService->AllowPort(port, scheme, &allow);
745 if (NS_SUCCEEDED(rv) && !allow) {
746 NS_WARNING("port blocked");
747 rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
748 }
749 }
750 return rv;
751 }
752
753 // Determine if this URI is using a safe port.
754 inline nsresult
755 NS_CheckPortSafety(nsIURI *uri) {
756 int32_t port;
757 nsresult rv = uri->GetPort(&port);
758 if (NS_FAILED(rv) || port == -1) // port undefined or default-valued
759 return NS_OK;
760 nsAutoCString scheme;
761 uri->GetScheme(scheme);
762 return NS_CheckPortSafety(port, scheme.get());
763 }
764
765 inline nsresult
766 NS_NewProxyInfo(const nsACString &type,
767 const nsACString &host,
768 int32_t port,
769 uint32_t flags,
770 nsIProxyInfo **result)
771 {
772 nsresult rv;
773 nsCOMPtr<nsIProtocolProxyService> pps =
774 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
775 if (NS_SUCCEEDED(rv))
776 rv = pps->NewProxyInfo(type, host, port, flags, UINT32_MAX, nullptr,
777 result);
778 return rv;
779 }
780
781 inline nsresult
782 NS_GetFileProtocolHandler(nsIFileProtocolHandler **result,
783 nsIIOService *ioService = nullptr)
784 {
785 nsresult rv;
786 nsCOMPtr<nsIIOService> grip;
787 rv = net_EnsureIOService(&ioService, grip);
788 if (ioService) {
789 nsCOMPtr<nsIProtocolHandler> handler;
790 rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
791 if (NS_SUCCEEDED(rv))
792 rv = CallQueryInterface(handler, result);
793 }
794 return rv;
795 }
796
797 inline nsresult
798 NS_GetFileFromURLSpec(const nsACString &inURL,
799 nsIFile **result,
800 nsIIOService *ioService = nullptr)
801 {
802 nsresult rv;
803 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
804 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
805 if (NS_SUCCEEDED(rv))
806 rv = fileHandler->GetFileFromURLSpec(inURL, result);
807 return rv;
808 }
809
810 inline nsresult
811 NS_GetURLSpecFromFile(nsIFile *file,
812 nsACString &url,
813 nsIIOService *ioService = nullptr)
814 {
815 nsresult rv;
816 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
817 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
818 if (NS_SUCCEEDED(rv))
819 rv = fileHandler->GetURLSpecFromFile(file, url);
820 return rv;
821 }
822
823 /**
824 * Converts the nsIFile to the corresponding URL string.
825 * Should only be called on files which are not directories,
826 * is otherwise identical to NS_GetURLSpecFromFile, but is
827 * usually more efficient.
828 * Warning: this restriction may not be enforced at runtime!
829 */
830 inline nsresult
831 NS_GetURLSpecFromActualFile(nsIFile *file,
832 nsACString &url,
833 nsIIOService *ioService = nullptr)
834 {
835 nsresult rv;
836 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
837 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
838 if (NS_SUCCEEDED(rv))
839 rv = fileHandler->GetURLSpecFromActualFile(file, url);
840 return rv;
841 }
842
843 /**
844 * Converts the nsIFile to the corresponding URL string.
845 * Should only be called on files which are directories,
846 * is otherwise identical to NS_GetURLSpecFromFile, but is
847 * usually more efficient.
848 * Warning: this restriction may not be enforced at runtime!
849 */
850 inline nsresult
851 NS_GetURLSpecFromDir(nsIFile *file,
852 nsACString &url,
853 nsIIOService *ioService = nullptr)
854 {
855 nsresult rv;
856 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
857 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
858 if (NS_SUCCEEDED(rv))
859 rv = fileHandler->GetURLSpecFromDir(file, url);
860 return rv;
861 }
862
863 /**
864 * Obtains the referrer for a given channel. This first tries to obtain the
865 * referrer from the property docshell.internalReferrer, and if that doesn't
866 * work and the channel is an nsIHTTPChannel, we check it's referrer property.
867 *
868 * @returns NS_ERROR_NOT_AVAILABLE if no referrer is available.
869 */
870 inline nsresult
871 NS_GetReferrerFromChannel(nsIChannel *channel,
872 nsIURI **referrer)
873 {
874 nsresult rv = NS_ERROR_NOT_AVAILABLE;
875 *referrer = nullptr;
876
877 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
878 if (props) {
879 // We have to check for a property on a property bag because the
880 // referrer may be empty for security reasons (for example, when loading
881 // an http page with an https referrer).
882 rv = props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
883 NS_GET_IID(nsIURI),
884 reinterpret_cast<void **>(referrer));
885 if (NS_FAILED(rv))
886 *referrer = nullptr;
887 }
888
889 // if that didn't work, we can still try to get the referrer from the
890 // nsIHttpChannel (if we can QI to it)
891 if (!(*referrer)) {
892 nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
893 if (chan) {
894 rv = chan->GetReferrer(referrer);
895 if (NS_FAILED(rv))
896 *referrer = nullptr;
897 }
898 }
899 return rv;
900 }
901
902 inline nsresult
903 NS_ParseContentType(const nsACString &rawContentType,
904 nsCString &contentType,
905 nsCString &contentCharset)
906 {
907 // contentCharset is left untouched if not present in rawContentType
908 nsresult rv;
909 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
910 NS_ENSURE_SUCCESS(rv, rv);
911 nsCString charset;
912 bool hadCharset;
913 rv = util->ParseContentType(rawContentType, charset, &hadCharset,
914 contentType);
915 if (NS_SUCCEEDED(rv) && hadCharset)
916 contentCharset = charset;
917 return rv;
918 }
919
920 inline nsresult
921 NS_ExtractCharsetFromContentType(const nsACString &rawContentType,
922 nsCString &contentCharset,
923 bool *hadCharset,
924 int32_t *charsetStart,
925 int32_t *charsetEnd)
926 {
927 // contentCharset is left untouched if not present in rawContentType
928 nsresult rv;
929 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
930 NS_ENSURE_SUCCESS(rv, rv);
931
932 return util->ExtractCharsetFromContentType(rawContentType,
933 contentCharset,
934 charsetStart,
935 charsetEnd,
936 hadCharset);
937 }
938
939 inline nsresult
940 NS_NewLocalFileInputStream(nsIInputStream **result,
941 nsIFile *file,
942 int32_t ioFlags = -1,
943 int32_t perm = -1,
944 int32_t behaviorFlags = 0)
945 {
946 nsresult rv;
947 nsCOMPtr<nsIFileInputStream> in =
948 do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
949 if (NS_SUCCEEDED(rv)) {
950 rv = in->Init(file, ioFlags, perm, behaviorFlags);
951 if (NS_SUCCEEDED(rv))
952 in.forget(result);
953 }
954 return rv;
955 }
956
957 inline nsresult
958 NS_NewPartialLocalFileInputStream(nsIInputStream **result,
959 nsIFile *file,
960 uint64_t offset,
961 uint64_t length,
962 int32_t ioFlags = -1,
963 int32_t perm = -1,
964 int32_t behaviorFlags = 0)
965 {
966 nsresult rv;
967 nsCOMPtr<nsIPartialFileInputStream> in =
968 do_CreateInstance(NS_PARTIALLOCALFILEINPUTSTREAM_CONTRACTID, &rv);
969 if (NS_SUCCEEDED(rv)) {
970 rv = in->Init(file, offset, length, ioFlags, perm, behaviorFlags);
971 if (NS_SUCCEEDED(rv))
972 rv = CallQueryInterface(in, result);
973 }
974 return rv;
975 }
976
977 inline nsresult
978 NS_NewLocalFileOutputStream(nsIOutputStream **result,
979 nsIFile *file,
980 int32_t ioFlags = -1,
981 int32_t perm = -1,
982 int32_t behaviorFlags = 0)
983 {
984 nsresult rv;
985 nsCOMPtr<nsIFileOutputStream> out =
986 do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
987 if (NS_SUCCEEDED(rv)) {
988 rv = out->Init(file, ioFlags, perm, behaviorFlags);
989 if (NS_SUCCEEDED(rv))
990 out.forget(result);
991 }
992 return rv;
993 }
994
995 // returns a file output stream which can be QI'ed to nsISafeOutputStream.
996 inline nsresult
997 NS_NewAtomicFileOutputStream(nsIOutputStream **result,
998 nsIFile *file,
999 int32_t ioFlags = -1,
1000 int32_t perm = -1,
1001 int32_t behaviorFlags = 0)
1002 {
1003 nsresult rv;
1004 nsCOMPtr<nsIFileOutputStream> out =
1005 do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1006 if (NS_SUCCEEDED(rv)) {
1007 rv = out->Init(file, ioFlags, perm, behaviorFlags);
1008 if (NS_SUCCEEDED(rv))
1009 out.forget(result);
1010 }
1011 return rv;
1012 }
1013
1014 // returns a file output stream which can be QI'ed to nsISafeOutputStream.
1015 inline nsresult
1016 NS_NewSafeLocalFileOutputStream(nsIOutputStream **result,
1017 nsIFile *file,
1018 int32_t ioFlags = -1,
1019 int32_t perm = -1,
1020 int32_t behaviorFlags = 0)
1021 {
1022 nsresult rv;
1023 nsCOMPtr<nsIFileOutputStream> out =
1024 do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1025 if (NS_SUCCEEDED(rv)) {
1026 rv = out->Init(file, ioFlags, perm, behaviorFlags);
1027 if (NS_SUCCEEDED(rv))
1028 out.forget(result);
1029 }
1030 return rv;
1031 }
1032
1033 inline nsresult
1034 NS_NewLocalFileStream(nsIFileStream **result,
1035 nsIFile *file,
1036 int32_t ioFlags = -1,
1037 int32_t perm = -1,
1038 int32_t behaviorFlags = 0)
1039 {
1040 nsresult rv;
1041 nsCOMPtr<nsIFileStream> stream =
1042 do_CreateInstance(NS_LOCALFILESTREAM_CONTRACTID, &rv);
1043 if (NS_SUCCEEDED(rv)) {
1044 rv = stream->Init(file, ioFlags, perm, behaviorFlags);
1045 if (NS_SUCCEEDED(rv))
1046 stream.forget(result);
1047 }
1048 return rv;
1049 }
1050
1051 // returns the input end of a pipe. the output end of the pipe
1052 // is attached to the original stream. data from the original
1053 // stream is read into the pipe on a background thread.
1054 inline nsresult
1055 NS_BackgroundInputStream(nsIInputStream **result,
1056 nsIInputStream *stream,
1057 uint32_t segmentSize = 0,
1058 uint32_t segmentCount = 0)
1059 {
1060 nsresult rv;
1061 nsCOMPtr<nsIStreamTransportService> sts =
1062 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
1063 if (NS_SUCCEEDED(rv)) {
1064 nsCOMPtr<nsITransport> inTransport;
1065 rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1),
1066 true, getter_AddRefs(inTransport));
1067 if (NS_SUCCEEDED(rv))
1068 rv = inTransport->OpenInputStream(nsITransport::OPEN_BLOCKING,
1069 segmentSize, segmentCount,
1070 result);
1071 }
1072 return rv;
1073 }
1074
1075 // returns the output end of a pipe. the input end of the pipe
1076 // is attached to the original stream. data written to the pipe
1077 // is copied to the original stream on a background thread.
1078 inline nsresult
1079 NS_BackgroundOutputStream(nsIOutputStream **result,
1080 nsIOutputStream *stream,
1081 uint32_t segmentSize = 0,
1082 uint32_t segmentCount = 0)
1083 {
1084 nsresult rv;
1085 nsCOMPtr<nsIStreamTransportService> sts =
1086 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
1087 if (NS_SUCCEEDED(rv)) {
1088 nsCOMPtr<nsITransport> inTransport;
1089 rv = sts->CreateOutputTransport(stream, int64_t(-1), int64_t(-1),
1090 true, getter_AddRefs(inTransport));
1091 if (NS_SUCCEEDED(rv))
1092 rv = inTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
1093 segmentSize, segmentCount,
1094 result);
1095 }
1096 return rv;
1097 }
1098
1099 MOZ_WARN_UNUSED_RESULT inline nsresult
1100 NS_NewBufferedInputStream(nsIInputStream **result,
1101 nsIInputStream *str,
1102 uint32_t bufferSize)
1103 {
1104 nsresult rv;
1105 nsCOMPtr<nsIBufferedInputStream> in =
1106 do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
1107 if (NS_SUCCEEDED(rv)) {
1108 rv = in->Init(str, bufferSize);
1109 if (NS_SUCCEEDED(rv))
1110 NS_ADDREF(*result = in); // cannot use nsCOMPtr::swap
1111 }
1112 return rv;
1113 }
1114
1115 // note: the resulting stream can be QI'ed to nsISafeOutputStream iff the
1116 // provided stream supports it.
1117 inline nsresult
1118 NS_NewBufferedOutputStream(nsIOutputStream **result,
1119 nsIOutputStream *str,
1120 uint32_t bufferSize)
1121 {
1122 nsresult rv;
1123 nsCOMPtr<nsIBufferedOutputStream> out =
1124 do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
1125 if (NS_SUCCEEDED(rv)) {
1126 rv = out->Init(str, bufferSize);
1127 if (NS_SUCCEEDED(rv))
1128 NS_ADDREF(*result = out); // cannot use nsCOMPtr::swap
1129 }
1130 return rv;
1131 }
1132
1133 /**
1134 * Attempts to buffer a given output stream. If this fails, it returns the
1135 * passed-in output stream.
1136 *
1137 * @param aOutputStream
1138 * The output stream we want to buffer. This cannot be null.
1139 * @param aBufferSize
1140 * The size of the buffer for the buffered output stream.
1141 * @returns an nsIOutputStream that is buffered with the specified buffer size,
1142 * or is aOutputStream if creating the new buffered stream failed.
1143 */
1144 inline already_AddRefed<nsIOutputStream>
1145 NS_BufferOutputStream(nsIOutputStream *aOutputStream,
1146 uint32_t aBufferSize)
1147 {
1148 NS_ASSERTION(aOutputStream, "No output stream given!");
1149
1150 nsCOMPtr<nsIOutputStream> bos;
1151 nsresult rv = NS_NewBufferedOutputStream(getter_AddRefs(bos), aOutputStream,
1152 aBufferSize);
1153 if (NS_SUCCEEDED(rv))
1154 return bos.forget();
1155
1156 bos = aOutputStream;
1157 return bos.forget();
1158 }
1159
1160 // returns an input stream compatible with nsIUploadChannel::SetUploadStream()
1161 inline nsresult
1162 NS_NewPostDataStream(nsIInputStream **result,
1163 bool isFile,
1164 const nsACString &data)
1165 {
1166 nsresult rv;
1167
1168 if (isFile) {
1169 nsCOMPtr<nsIFile> file;
1170 nsCOMPtr<nsIInputStream> fileStream;
1171
1172 rv = NS_NewNativeLocalFile(data, false, getter_AddRefs(file));
1173 if (NS_SUCCEEDED(rv)) {
1174 rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
1175 if (NS_SUCCEEDED(rv)) {
1176 // wrap the file stream with a buffered input stream
1177 rv = NS_NewBufferedInputStream(result, fileStream, 8192);
1178 }
1179 }
1180 return rv;
1181 }
1182
1183 // otherwise, create a string stream for the data (copies)
1184 nsCOMPtr<nsIStringInputStream> stream
1185 (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
1186 if (NS_FAILED(rv))
1187 return rv;
1188
1189 rv = stream->SetData(data.BeginReading(), data.Length());
1190 if (NS_FAILED(rv))
1191 return rv;
1192
1193 NS_ADDREF(*result = stream);
1194 return NS_OK;
1195 }
1196
1197 inline nsresult
1198 NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream,
1199 void** aDest,
1200 uint32_t aCount)
1201 {
1202 nsresult rv;
1203
1204 if (!*aDest) {
1205 *aDest = malloc(aCount);
1206 if (!*aDest)
1207 return NS_ERROR_OUT_OF_MEMORY;
1208 }
1209
1210 char * p = reinterpret_cast<char*>(*aDest);
1211 uint32_t bytesRead;
1212 uint32_t totalRead = 0;
1213 while (1) {
1214 rv = aInputStream->Read(p + totalRead, aCount - totalRead, &bytesRead);
1215 if (!NS_SUCCEEDED(rv))
1216 return rv;
1217 totalRead += bytesRead;
1218 if (totalRead == aCount)
1219 break;
1220 // if Read reads 0 bytes, we've hit EOF
1221 if (bytesRead == 0)
1222 return NS_ERROR_UNEXPECTED;
1223 }
1224 return rv;
1225 }
1226
1227 // external code can't see fallible_t
1228 #ifdef MOZILLA_INTERNAL_API
1229
1230 inline nsresult
1231 NS_ReadInputStreamToString(nsIInputStream *aInputStream,
1232 nsACString &aDest,
1233 uint32_t aCount)
1234 {
1235 if (!aDest.SetLength(aCount, mozilla::fallible_t()))
1236 return NS_ERROR_OUT_OF_MEMORY;
1237 void* dest = aDest.BeginWriting();
1238 return NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount);
1239 }
1240
1241 #endif
1242
1243 inline nsresult
1244 NS_LoadPersistentPropertiesFromURI(nsIPersistentProperties **result,
1245 nsIURI *uri,
1246 nsIIOService *ioService = nullptr)
1247 {
1248 nsCOMPtr<nsIInputStream> in;
1249 nsresult rv = NS_OpenURI(getter_AddRefs(in), uri, ioService);
1250 if (NS_SUCCEEDED(rv)) {
1251 nsCOMPtr<nsIPersistentProperties> properties =
1252 do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID, &rv);
1253 if (NS_SUCCEEDED(rv)) {
1254 rv = properties->Load(in);
1255 if (NS_SUCCEEDED(rv)) {
1256 *result = nullptr;
1257 properties.swap(*result);
1258 }
1259 }
1260 }
1261 return rv;
1262 }
1263
1264 inline nsresult
1265 NS_LoadPersistentPropertiesFromURISpec(nsIPersistentProperties **result,
1266 const nsACString &spec,
1267 const char *charset = nullptr,
1268 nsIURI *baseURI = nullptr,
1269 nsIIOService *ioService = nullptr)
1270 {
1271 nsCOMPtr<nsIURI> uri;
1272 nsresult rv =
1273 NS_NewURI(getter_AddRefs(uri), spec, charset, baseURI, ioService);
1274
1275 if (NS_SUCCEEDED(rv))
1276 rv = NS_LoadPersistentPropertiesFromURI(result, uri, ioService);
1277
1278 return rv;
1279 }
1280
1281 /**
1282 * NS_QueryNotificationCallbacks implements the canonical algorithm for
1283 * querying interfaces from a channel's notification callbacks. It first
1284 * searches the channel's notificationCallbacks attribute, and if the interface
1285 * is not found there, then it inspects the notificationCallbacks attribute of
1286 * the channel's loadGroup.
1287 *
1288 * Note: templatized only because nsIWebSocketChannel is currently not an
1289 * nsIChannel.
1290 */
1291 template <class T> inline void
1292 NS_QueryNotificationCallbacks(T *channel,
1293 const nsIID &iid,
1294 void **result)
1295 {
1296 NS_PRECONDITION(channel, "null channel");
1297 *result = nullptr;
1298
1299 nsCOMPtr<nsIInterfaceRequestor> cbs;
1300 channel->GetNotificationCallbacks(getter_AddRefs(cbs));
1301 if (cbs)
1302 cbs->GetInterface(iid, result);
1303 if (!*result) {
1304 // try load group's notification callbacks...
1305 nsCOMPtr<nsILoadGroup> loadGroup;
1306 channel->GetLoadGroup(getter_AddRefs(loadGroup));
1307 if (loadGroup) {
1308 loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
1309 if (cbs)
1310 cbs->GetInterface(iid, result);
1311 }
1312 }
1313 }
1314
1315 // template helper:
1316 // Note: "class C" templatized only because nsIWebSocketChannel is currently not
1317 // an nsIChannel.
1318
1319 template <class C, class T> inline void
1320 NS_QueryNotificationCallbacks(C *channel,
1321 nsCOMPtr<T> &result)
1322 {
1323 NS_QueryNotificationCallbacks(channel, NS_GET_TEMPLATE_IID(T),
1324 getter_AddRefs(result));
1325 }
1326
1327 /**
1328 * Alternate form of NS_QueryNotificationCallbacks designed for use by
1329 * nsIChannel implementations.
1330 */
1331 inline void
1332 NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks,
1333 nsILoadGroup *loadGroup,
1334 const nsIID &iid,
1335 void **result)
1336 {
1337 *result = nullptr;
1338
1339 if (callbacks)
1340 callbacks->GetInterface(iid, result);
1341 if (!*result) {
1342 // try load group's notification callbacks...
1343 if (loadGroup) {
1344 nsCOMPtr<nsIInterfaceRequestor> cbs;
1345 loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
1346 if (cbs)
1347 cbs->GetInterface(iid, result);
1348 }
1349 }
1350 }
1351
1352 /**
1353 * Returns true if channel is using Private Browsing, or false if not.
1354 * Returns false if channel's callbacks don't implement nsILoadContext.
1355 */
1356 inline bool
1357 NS_UsePrivateBrowsing(nsIChannel *channel)
1358 {
1359 bool isPrivate = false;
1360 bool isOverriden = false;
1361 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
1362 if (pbChannel &&
1363 NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) &&
1364 isOverriden) {
1365 return isPrivate;
1366 }
1367 nsCOMPtr<nsILoadContext> loadContext;
1368 NS_QueryNotificationCallbacks(channel, loadContext);
1369 return loadContext && loadContext->UsePrivateBrowsing();
1370 }
1371
1372 // Constants duplicated from nsIScriptSecurityManager so we avoid having necko
1373 // know about script security manager.
1374 #define NECKO_NO_APP_ID 0
1375 #define NECKO_UNKNOWN_APP_ID UINT32_MAX
1376 // special app id reserved for separating the safebrowsing cookie
1377 #define NECKO_SAFEBROWSING_APP_ID UINT32_MAX - 1
1378
1379 /**
1380 * Gets AppId and isInBrowserElement from channel's nsILoadContext.
1381 * Returns false if error or channel's callbacks don't implement nsILoadContext.
1382 */
1383 inline bool
1384 NS_GetAppInfo(nsIChannel *aChannel, uint32_t *aAppID, bool *aIsInBrowserElement)
1385 {
1386 nsCOMPtr<nsILoadContext> loadContext;
1387 NS_QueryNotificationCallbacks(aChannel, loadContext);
1388 if (!loadContext) {
1389 return false;
1390 }
1391
1392 nsresult rv = loadContext->GetAppId(aAppID);
1393 NS_ENSURE_SUCCESS(rv, false);
1394
1395 rv = loadContext->GetIsInBrowserElement(aIsInBrowserElement);
1396 NS_ENSURE_SUCCESS(rv, false);
1397
1398 return true;
1399 }
1400
1401 /**
1402 * Gets appId and browserOnly parameters from the TOPIC_WEB_APP_CLEAR_DATA
1403 * nsIObserverService notification. Used when clearing user data or
1404 * uninstalling web apps.
1405 */
1406 inline nsresult
1407 NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject,
1408 uint32_t *aAppID, bool* aBrowserOnly)
1409 {
1410 nsresult rv;
1411
1412 nsCOMPtr<mozIApplicationClearPrivateDataParams>
1413 clearParams(do_QueryInterface(aSubject));
1414 MOZ_ASSERT(clearParams);
1415 if (!clearParams) {
1416 return NS_ERROR_UNEXPECTED;
1417 }
1418
1419 uint32_t appId;
1420 rv = clearParams->GetAppId(&appId);
1421 MOZ_ASSERT(NS_SUCCEEDED(rv));
1422 MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
1423 NS_ENSURE_SUCCESS(rv, rv);
1424 if (appId == NECKO_UNKNOWN_APP_ID) {
1425 return NS_ERROR_UNEXPECTED;
1426 }
1427
1428 bool browserOnly = false;
1429 rv = clearParams->GetBrowserOnly(&browserOnly);
1430 MOZ_ASSERT(NS_SUCCEEDED(rv));
1431 NS_ENSURE_SUCCESS(rv, rv);
1432
1433 *aAppID = appId;
1434 *aBrowserOnly = browserOnly;
1435 return NS_OK;
1436 }
1437
1438 /**
1439 * Determines whether appcache should be checked for a given URI.
1440 */
1441 inline bool
1442 NS_ShouldCheckAppCache(nsIURI *aURI, bool usePrivateBrowsing)
1443 {
1444 if (usePrivateBrowsing) {
1445 return false;
1446 }
1447
1448 nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
1449 do_GetService("@mozilla.org/offlinecacheupdate-service;1");
1450 if (!offlineService) {
1451 return false;
1452 }
1453
1454 bool allowed;
1455 nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
1456 nullptr,
1457 &allowed);
1458 return NS_SUCCEEDED(rv) && allowed;
1459 }
1460
1461 inline bool
1462 NS_ShouldCheckAppCache(nsIPrincipal * aPrincipal, bool usePrivateBrowsing)
1463 {
1464 if (usePrivateBrowsing) {
1465 return false;
1466 }
1467
1468 nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
1469 do_GetService("@mozilla.org/offlinecacheupdate-service;1");
1470 if (!offlineService) {
1471 return false;
1472 }
1473
1474 bool allowed;
1475 nsresult rv = offlineService->OfflineAppAllowed(aPrincipal,
1476 nullptr,
1477 &allowed);
1478 return NS_SUCCEEDED(rv) && allowed;
1479 }
1480
1481 /**
1482 * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This
1483 * method is provided mainly for use by other methods in this file.
1484 *
1485 * *aAuthPrompt2 should be set to null before calling this function.
1486 */
1487 inline void
1488 NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt, nsIAuthPrompt2** aAuthPrompt2)
1489 {
1490 nsCOMPtr<nsIAuthPromptAdapterFactory> factory =
1491 do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID);
1492 if (!factory)
1493 return;
1494
1495 NS_WARNING("Using deprecated nsIAuthPrompt");
1496 factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
1497 }
1498
1499 /**
1500 * Gets an auth prompt from an interface requestor. This takes care of wrapping
1501 * an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2.
1502 */
1503 inline void
1504 NS_QueryAuthPrompt2(nsIInterfaceRequestor *aCallbacks,
1505 nsIAuthPrompt2 **aAuthPrompt)
1506 {
1507 CallGetInterface(aCallbacks, aAuthPrompt);
1508 if (*aAuthPrompt)
1509 return;
1510
1511 // Maybe only nsIAuthPrompt is provided and we have to wrap it.
1512 nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
1513 if (!prompt)
1514 return;
1515
1516 NS_WrapAuthPrompt(prompt, aAuthPrompt);
1517 }
1518
1519 /**
1520 * Gets an nsIAuthPrompt2 from a channel. Use this instead of
1521 * NS_QueryNotificationCallbacks for better backwards compatibility.
1522 */
1523 inline void
1524 NS_QueryAuthPrompt2(nsIChannel *aChannel,
1525 nsIAuthPrompt2 **aAuthPrompt)
1526 {
1527 *aAuthPrompt = nullptr;
1528
1529 // We want to use any auth prompt we can find on the channel's callbacks,
1530 // and if that fails use the loadgroup's prompt (if any)
1531 // Therefore, we can't just use NS_QueryNotificationCallbacks, because
1532 // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
1533 // nsIAuthPrompt.
1534 nsCOMPtr<nsIInterfaceRequestor> callbacks;
1535 aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
1536 if (callbacks) {
1537 NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
1538 if (*aAuthPrompt)
1539 return;
1540 }
1541
1542 nsCOMPtr<nsILoadGroup> group;
1543 aChannel->GetLoadGroup(getter_AddRefs(group));
1544 if (!group)
1545 return;
1546
1547 group->GetNotificationCallbacks(getter_AddRefs(callbacks));
1548 if (!callbacks)
1549 return;
1550 NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
1551 }
1552
1553 /* template helper */
1554 template <class T> inline void
1555 NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks,
1556 nsILoadGroup *loadGroup,
1557 nsCOMPtr<T> &result)
1558 {
1559 NS_QueryNotificationCallbacks(callbacks, loadGroup,
1560 NS_GET_TEMPLATE_IID(T),
1561 getter_AddRefs(result));
1562 }
1563
1564 /* template helper */
1565 template <class T> inline void
1566 NS_QueryNotificationCallbacks(const nsCOMPtr<nsIInterfaceRequestor> &aCallbacks,
1567 const nsCOMPtr<nsILoadGroup> &aLoadGroup,
1568 nsCOMPtr<T> &aResult)
1569 {
1570 NS_QueryNotificationCallbacks(aCallbacks.get(), aLoadGroup.get(), aResult);
1571 }
1572
1573 /* template helper */
1574 template <class T> inline void
1575 NS_QueryNotificationCallbacks(const nsCOMPtr<nsIChannel> &aChannel,
1576 nsCOMPtr<T> &aResult)
1577 {
1578 NS_QueryNotificationCallbacks(aChannel.get(), aResult);
1579 }
1580
1581 /**
1582 * This function returns a nsIInterfaceRequestor instance that returns the
1583 * same result as NS_QueryNotificationCallbacks when queried. It is useful
1584 * as the value for nsISocketTransport::securityCallbacks.
1585 */
1586 inline nsresult
1587 NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks,
1588 nsILoadGroup *loadGroup,
1589 nsIEventTarget *target,
1590 nsIInterfaceRequestor **result)
1591 {
1592 nsCOMPtr<nsIInterfaceRequestor> cbs;
1593 if (loadGroup)
1594 loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
1595 return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
1596 }
1597
1598 inline nsresult
1599 NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks,
1600 nsILoadGroup *loadGroup,
1601 nsIInterfaceRequestor **result)
1602 {
1603 return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr, result);
1604 }
1605
1606 /**
1607 * Helper function for testing online/offline state of the browser.
1608 */
1609 inline bool
1610 NS_IsOffline()
1611 {
1612 bool offline = true;
1613 nsCOMPtr<nsIIOService> ios = do_GetIOService();
1614 if (ios)
1615 ios->GetOffline(&offline);
1616 return offline;
1617 }
1618
1619 /**
1620 * Helper functions for implementing nsINestedURI::innermostURI.
1621 *
1622 * Note that NS_DoImplGetInnermostURI is "private" -- call
1623 * NS_ImplGetInnermostURI instead.
1624 */
1625 inline nsresult
1626 NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
1627 {
1628 NS_PRECONDITION(nestedURI, "Must have a nested URI!");
1629 NS_PRECONDITION(!*result, "Must have null *result");
1630
1631 nsCOMPtr<nsIURI> inner;
1632 nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
1633 NS_ENSURE_SUCCESS(rv, rv);
1634
1635 // We may need to loop here until we reach the innermost
1636 // URI.
1637 nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
1638 while (nestedInner) {
1639 rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
1640 NS_ENSURE_SUCCESS(rv, rv);
1641 nestedInner = do_QueryInterface(inner);
1642 }
1643
1644 // Found the innermost one if we reach here.
1645 inner.swap(*result);
1646
1647 return rv;
1648 }
1649
1650 inline nsresult
1651 NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
1652 {
1653 // Make it safe to use swap()
1654 *result = nullptr;
1655
1656 return NS_DoImplGetInnermostURI(nestedURI, result);
1657 }
1658
1659 /**
1660 * Helper function that ensures that |result| is a URI that's safe to
1661 * return. If |uri| is immutable, just returns it, otherwise returns
1662 * a clone. |uri| must not be null.
1663 */
1664 inline nsresult
1665 NS_EnsureSafeToReturn(nsIURI* uri, nsIURI** result)
1666 {
1667 NS_PRECONDITION(uri, "Must have a URI");
1668
1669 // Assume mutable until told otherwise
1670 bool isMutable = true;
1671 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
1672 if (mutableObj) {
1673 nsresult rv = mutableObj->GetMutable(&isMutable);
1674 isMutable = NS_FAILED(rv) || isMutable;
1675 }
1676
1677 if (!isMutable) {
1678 NS_ADDREF(*result = uri);
1679 return NS_OK;
1680 }
1681
1682 nsresult rv = uri->Clone(result);
1683 if (NS_SUCCEEDED(rv) && !*result) {
1684 NS_ERROR("nsIURI.clone contract was violated");
1685 return NS_ERROR_UNEXPECTED;
1686 }
1687
1688 return rv;
1689 }
1690
1691 /**
1692 * Helper function that tries to set the argument URI to be immutable
1693 */
1694 inline void
1695 NS_TryToSetImmutable(nsIURI* uri)
1696 {
1697 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
1698 if (mutableObj) {
1699 mutableObj->SetMutable(false);
1700 }
1701 }
1702
1703 /**
1704 * Helper function for calling ToImmutableURI. If all else fails, returns
1705 * the input URI. The optional second arg indicates whether we had to fall
1706 * back to the input URI. Passing in a null URI is ok.
1707 */
1708 inline already_AddRefed<nsIURI>
1709 NS_TryToMakeImmutable(nsIURI* uri,
1710 nsresult* outRv = nullptr)
1711 {
1712 nsresult rv;
1713 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1714
1715 nsCOMPtr<nsIURI> result;
1716 if (NS_SUCCEEDED(rv)) {
1717 NS_ASSERTION(util, "do_GetNetUtil lied");
1718 rv = util->ToImmutableURI(uri, getter_AddRefs(result));
1719 }
1720
1721 if (NS_FAILED(rv)) {
1722 result = uri;
1723 }
1724
1725 if (outRv) {
1726 *outRv = rv;
1727 }
1728
1729 return result.forget();
1730 }
1731
1732 /**
1733 * Helper function for testing whether the given URI, or any of its
1734 * inner URIs, has all the given protocol flags.
1735 */
1736 inline nsresult
1737 NS_URIChainHasFlags(nsIURI *uri,
1738 uint32_t flags,
1739 bool *result)
1740 {
1741 nsresult rv;
1742 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1743 NS_ENSURE_SUCCESS(rv, rv);
1744
1745 return util->URIChainHasFlags(uri, flags, result);
1746 }
1747
1748 /**
1749 * Helper function for getting the innermost URI for a given URI. The return
1750 * value could be just the object passed in if it's not a nested URI.
1751 */
1752 inline already_AddRefed<nsIURI>
1753 NS_GetInnermostURI(nsIURI* aURI)
1754 {
1755 NS_PRECONDITION(aURI, "Must have URI");
1756
1757 nsCOMPtr<nsIURI> uri = aURI;
1758
1759 nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
1760 if (!nestedURI) {
1761 return uri.forget();
1762 }
1763
1764 nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
1765 if (NS_FAILED(rv)) {
1766 return nullptr;
1767 }
1768
1769 return uri.forget();
1770 }
1771
1772 /**
1773 * Get the "final" URI for a channel. This is either the same as GetURI or
1774 * GetOriginalURI, depending on whether this channel has
1775 * nsIChanel::LOAD_REPLACE set. For channels without that flag set, the final
1776 * URI is the original URI, while for ones with the flag the final URI is the
1777 * channel URI.
1778 */
1779 inline nsresult
1780 NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri)
1781 {
1782 *uri = nullptr;
1783 nsLoadFlags loadFlags = 0;
1784 nsresult rv = channel->GetLoadFlags(&loadFlags);
1785 NS_ENSURE_SUCCESS(rv, rv);
1786
1787 if (loadFlags & nsIChannel::LOAD_REPLACE) {
1788 return channel->GetURI(uri);
1789 }
1790
1791 return channel->GetOriginalURI(uri);
1792 }
1793
1794 // NS_SecurityHashURI must return the same hash value for any two URIs that
1795 // compare equal according to NS_SecurityCompareURIs. Unfortunately, in the
1796 // case of files, it's not clear we can do anything better than returning
1797 // the schemeHash, so hashing files degenerates to storing them in a list.
1798 inline uint32_t
1799 NS_SecurityHashURI(nsIURI* aURI)
1800 {
1801 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
1802
1803 nsAutoCString scheme;
1804 uint32_t schemeHash = 0;
1805 if (NS_SUCCEEDED(baseURI->GetScheme(scheme)))
1806 schemeHash = mozilla::HashString(scheme);
1807
1808 // TODO figure out how to hash file:// URIs
1809 if (scheme.EqualsLiteral("file"))
1810 return schemeHash; // sad face
1811
1812 if (scheme.EqualsLiteral("imap") ||
1813 scheme.EqualsLiteral("mailbox") ||
1814 scheme.EqualsLiteral("news"))
1815 {
1816 nsAutoCString spec;
1817 uint32_t specHash;
1818 nsresult res = baseURI->GetSpec(spec);
1819 if (NS_SUCCEEDED(res))
1820 specHash = mozilla::HashString(spec);
1821 else
1822 specHash = static_cast<uint32_t>(res);
1823 return specHash;
1824 }
1825
1826 nsAutoCString host;
1827 uint32_t hostHash = 0;
1828 if (NS_SUCCEEDED(baseURI->GetAsciiHost(host)))
1829 hostHash = mozilla::HashString(host);
1830
1831 return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
1832 }
1833
1834 inline bool
1835 NS_SecurityCompareURIs(nsIURI* aSourceURI,
1836 nsIURI* aTargetURI,
1837 bool aStrictFileOriginPolicy)
1838 {
1839 // Note that this is not an Equals() test on purpose -- for URIs that don't
1840 // support host/port, we want equality to basically be object identity, for
1841 // security purposes. Otherwise, for example, two javascript: URIs that
1842 // are otherwise unrelated could end up "same origin", which would be
1843 // unfortunate.
1844 if (aSourceURI && aSourceURI == aTargetURI)
1845 {
1846 return true;
1847 }
1848
1849 if (!aTargetURI || !aSourceURI)
1850 {
1851 return false;
1852 }
1853
1854 // If either URI is a nested URI, get the base URI
1855 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
1856 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
1857
1858 // If either uri is an nsIURIWithPrincipal
1859 nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(sourceBaseURI);
1860 if (uriPrinc) {
1861 uriPrinc->GetPrincipalUri(getter_AddRefs(sourceBaseURI));
1862 }
1863
1864 uriPrinc = do_QueryInterface(targetBaseURI);
1865 if (uriPrinc) {
1866 uriPrinc->GetPrincipalUri(getter_AddRefs(targetBaseURI));
1867 }
1868
1869 if (!sourceBaseURI || !targetBaseURI)
1870 return false;
1871
1872 // Compare schemes
1873 nsAutoCString targetScheme;
1874 bool sameScheme = false;
1875 if (NS_FAILED( targetBaseURI->GetScheme(targetScheme) ) ||
1876 NS_FAILED( sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme) ) ||
1877 !sameScheme)
1878 {
1879 // Not same-origin if schemes differ
1880 return false;
1881 }
1882
1883 // For file scheme, reject unless the files are identical. See
1884 // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking
1885 if (targetScheme.EqualsLiteral("file"))
1886 {
1887 // in traditional unsafe behavior all files are the same origin
1888 if (!aStrictFileOriginPolicy)
1889 return true;
1890
1891 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
1892 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
1893
1894 if (!sourceFileURL || !targetFileURL)
1895 return false;
1896
1897 nsCOMPtr<nsIFile> sourceFile, targetFile;
1898
1899 sourceFileURL->GetFile(getter_AddRefs(sourceFile));
1900 targetFileURL->GetFile(getter_AddRefs(targetFile));
1901
1902 if (!sourceFile || !targetFile)
1903 return false;
1904
1905 // Otherwise they had better match
1906 bool filesAreEqual = false;
1907 nsresult rv = sourceFile->Equals(targetFile, &filesAreEqual);
1908 return NS_SUCCEEDED(rv) && filesAreEqual;
1909 }
1910
1911 // Special handling for mailnews schemes
1912 if (targetScheme.EqualsLiteral("imap") ||
1913 targetScheme.EqualsLiteral("mailbox") ||
1914 targetScheme.EqualsLiteral("news"))
1915 {
1916 // Each message is a distinct trust domain; use the
1917 // whole spec for comparison
1918 nsAutoCString targetSpec;
1919 nsAutoCString sourceSpec;
1920 return ( NS_SUCCEEDED( targetBaseURI->GetSpec(targetSpec) ) &&
1921 NS_SUCCEEDED( sourceBaseURI->GetSpec(sourceSpec) ) &&
1922 targetSpec.Equals(sourceSpec) );
1923 }
1924
1925 // Compare hosts
1926 nsAutoCString targetHost;
1927 nsAutoCString sourceHost;
1928 if (NS_FAILED( targetBaseURI->GetAsciiHost(targetHost) ) ||
1929 NS_FAILED( sourceBaseURI->GetAsciiHost(sourceHost) ))
1930 {
1931 return false;
1932 }
1933
1934 nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
1935 nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
1936 if (!targetURL || !sourceURL)
1937 {
1938 return false;
1939 }
1940
1941 #ifdef MOZILLA_INTERNAL_API
1942 if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator() ))
1943 #else
1944 if (!targetHost.Equals(sourceHost, CaseInsensitiveCompare))
1945 #endif
1946 {
1947 return false;
1948 }
1949
1950 return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
1951 }
1952
1953 inline bool
1954 NS_URIIsLocalFile(nsIURI *aURI)
1955 {
1956 nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
1957
1958 bool isFile;
1959 return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
1960 nsIProtocolHandler::URI_IS_LOCAL_FILE,
1961 &isFile)) &&
1962 isFile;
1963 }
1964
1965 // When strict file origin policy is enabled, SecurityCompareURIs will fail for
1966 // file URIs that do not point to the same local file. This call provides an
1967 // alternate file-specific origin check that allows target files that are
1968 // contained in the same directory as the source.
1969 //
1970 // https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
1971 inline bool
1972 NS_RelaxStrictFileOriginPolicy(nsIURI *aTargetURI,
1973 nsIURI *aSourceURI,
1974 bool aAllowDirectoryTarget = false)
1975 {
1976 if (!NS_URIIsLocalFile(aTargetURI)) {
1977 // This is probably not what the caller intended
1978 NS_NOTREACHED("NS_RelaxStrictFileOriginPolicy called with non-file URI");
1979 return false;
1980 }
1981
1982 if (!NS_URIIsLocalFile(aSourceURI)) {
1983 // If the source is not also a file: uri then forget it
1984 // (don't want resource: principals in a file: doc)
1985 //
1986 // note: we're not de-nesting jar: uris here, we want to
1987 // keep archive content bottled up in its own little island
1988 return false;
1989 }
1990
1991 //
1992 // pull out the internal files
1993 //
1994 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI));
1995 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI));
1996 nsCOMPtr<nsIFile> targetFile;
1997 nsCOMPtr<nsIFile> sourceFile;
1998 bool targetIsDir;
1999
2000 // Make sure targetFile is not a directory (bug 209234)
2001 // and that it exists w/out unescaping (bug 395343)
2002 if (!sourceFileURL || !targetFileURL ||
2003 NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) ||
2004 NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) ||
2005 !targetFile || !sourceFile ||
2006 NS_FAILED(targetFile->Normalize()) ||
2007 #ifndef MOZ_WIDGET_ANDROID
2008 NS_FAILED(sourceFile->Normalize()) ||
2009 #endif
2010 (!aAllowDirectoryTarget &&
2011 (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) {
2012 return false;
2013 }
2014
2015 //
2016 // If the file to be loaded is in a subdirectory of the source
2017 // (or same-dir if source is not a directory) then it will
2018 // inherit its source principal and be scriptable by that source.
2019 //
2020 bool sourceIsDir;
2021 bool allowed = false;
2022 nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
2023 if (NS_SUCCEEDED(rv) && sourceIsDir) {
2024 rv = sourceFile->Contains(targetFile, true, &allowed);
2025 } else {
2026 nsCOMPtr<nsIFile> sourceParent;
2027 rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
2028 if (NS_SUCCEEDED(rv) && sourceParent) {
2029 rv = sourceParent->Equals(targetFile, &allowed);
2030 if (NS_FAILED(rv) || !allowed) {
2031 rv = sourceParent->Contains(targetFile, true, &allowed);
2032 } else {
2033 MOZ_ASSERT(aAllowDirectoryTarget,
2034 "sourceFile->Parent == targetFile, but targetFile "
2035 "should've been disallowed if it is a directory");
2036 }
2037 }
2038 }
2039
2040 if (NS_SUCCEEDED(rv) && allowed) {
2041 return true;
2042 }
2043
2044 return false;
2045 }
2046
2047 inline bool
2048 NS_IsInternalSameURIRedirect(nsIChannel *aOldChannel,
2049 nsIChannel *aNewChannel,
2050 uint32_t aFlags)
2051 {
2052 if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
2053 return false;
2054 }
2055
2056 nsCOMPtr<nsIURI> oldURI, newURI;
2057 aOldChannel->GetURI(getter_AddRefs(oldURI));
2058 aNewChannel->GetURI(getter_AddRefs(newURI));
2059
2060 if (!oldURI || !newURI) {
2061 return false;
2062 }
2063
2064 bool res;
2065 return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
2066 }
2067
2068 inline nsresult
2069 NS_LinkRedirectChannels(uint32_t channelId,
2070 nsIParentChannel *parentChannel,
2071 nsIChannel** _result)
2072 {
2073 nsresult rv;
2074
2075 nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
2076 do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
2077 NS_ENSURE_SUCCESS(rv, rv);
2078
2079 return registrar->LinkChannels(channelId,
2080 parentChannel,
2081 _result);
2082 }
2083
2084 /**
2085 * Helper function to create a random URL string that's properly formed
2086 * but guaranteed to be invalid.
2087 */
2088 #define NS_FAKE_SCHEME "http://"
2089 #define NS_FAKE_TLD ".invalid"
2090 inline nsresult
2091 NS_MakeRandomInvalidURLString(nsCString& result)
2092 {
2093 nsresult rv;
2094 nsCOMPtr<nsIUUIDGenerator> uuidgen =
2095 do_GetService("@mozilla.org/uuid-generator;1", &rv);
2096 NS_ENSURE_SUCCESS(rv, rv);
2097
2098 nsID idee;
2099 rv = uuidgen->GenerateUUIDInPlace(&idee);
2100 NS_ENSURE_SUCCESS(rv, rv);
2101
2102 char chars[NSID_LENGTH];
2103 idee.ToProvidedString(chars);
2104
2105 result.AssignLiteral(NS_FAKE_SCHEME);
2106 // Strip off the '{' and '}' at the beginning and end of the UUID
2107 result.Append(chars + 1, NSID_LENGTH - 3);
2108 result.AppendLiteral(NS_FAKE_TLD);
2109
2110 return NS_OK;
2111 }
2112 #undef NS_FAKE_SCHEME
2113 #undef NS_FAKE_TLD
2114
2115 /**
2116 * Helper function to determine whether urlString is Java-compatible --
2117 * whether it can be passed to the Java URL(String) constructor without the
2118 * latter throwing a MalformedURLException, or without Java otherwise
2119 * mishandling it. This function (in effect) implements a scheme whitelist
2120 * for Java.
2121 */
2122 inline nsresult
2123 NS_CheckIsJavaCompatibleURLString(nsCString& urlString, bool *result)
2124 {
2125 *result = false; // Default to "no"
2126
2127 nsresult rv = NS_OK;
2128 nsCOMPtr<nsIURLParser> urlParser =
2129 do_GetService(NS_STDURLPARSER_CONTRACTID, &rv);
2130 if (NS_FAILED(rv) || !urlParser)
2131 return NS_ERROR_FAILURE;
2132
2133 bool compatible = true;
2134 uint32_t schemePos = 0;
2135 int32_t schemeLen = 0;
2136 urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen,
2137 nullptr, nullptr, nullptr, nullptr);
2138 if (schemeLen != -1) {
2139 nsCString scheme;
2140 scheme.Assign(urlString.get() + schemePos, schemeLen);
2141 // By default Java only understands a small number of URL schemes, and of
2142 // these only some can legitimately represent a browser page's "origin"
2143 // (and be something we can legitimately expect Java to handle ... or not
2144 // to mishandle).
2145 //
2146 // Besides those listed below, the OJI plugin understands the "jar",
2147 // "mailto", "netdoc", "javascript" and "rmi" schemes, and Java Plugin2
2148 // also understands the "about" scheme. We actually pass "about" URLs
2149 // to Java ("about:blank" when processing a javascript: URL (one that
2150 // calls Java) from the location bar of a blank page, and (in FF4 and up)
2151 // "about:home" when processing a javascript: URL from the home page).
2152 // And Java doesn't appear to mishandle them (for example it doesn't allow
2153 // connections to "about" URLs). But it doesn't make any sense to do
2154 // same-origin checks on "about" URLs, so we don't include them in our
2155 // scheme whitelist.
2156 //
2157 // The OJI plugin doesn't understand "chrome" URLs (only Java Plugin2
2158 // does) -- so we mustn't pass them to the OJI plugin. But we do need to
2159 // pass "chrome" URLs to Java Plugin2: Java Plugin2 grants additional
2160 // privileges to chrome "origins", and some extensions take advantage of
2161 // this. For more information see bug 620773.
2162 //
2163 // As of FF4, we no longer support the OJI plugin.
2164 if (PL_strcasecmp(scheme.get(), "http") &&
2165 PL_strcasecmp(scheme.get(), "https") &&
2166 PL_strcasecmp(scheme.get(), "file") &&
2167 PL_strcasecmp(scheme.get(), "ftp") &&
2168 PL_strcasecmp(scheme.get(), "gopher") &&
2169 PL_strcasecmp(scheme.get(), "chrome"))
2170 compatible = false;
2171 } else {
2172 compatible = false;
2173 }
2174
2175 *result = compatible;
2176
2177 return NS_OK;
2178 }
2179
2180 /** Given the first (disposition) token from a Content-Disposition header,
2181 * tell whether it indicates the content is inline or attachment
2182 * @param aDispToken the disposition token from the content-disposition header
2183 */
2184 inline uint32_t
2185 NS_GetContentDispositionFromToken(const nsAString& aDispToken)
2186 {
2187 // RFC 2183, section 2.8 says that an unknown disposition
2188 // value should be treated as "attachment"
2189 // If all of these tests eval to false, then we have a content-disposition of
2190 // "attachment" or unknown
2191 if (aDispToken.IsEmpty() ||
2192 aDispToken.LowerCaseEqualsLiteral("inline") ||
2193 // Broken sites just send
2194 // Content-Disposition: filename="file"
2195 // without a disposition token... screen those out.
2196 StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename"))
2197 return nsIChannel::DISPOSITION_INLINE;
2198
2199 return nsIChannel::DISPOSITION_ATTACHMENT;
2200 }
2201
2202 /** Determine the disposition (inline/attachment) of the content based on the
2203 * Content-Disposition header
2204 * @param aHeader the content-disposition header (full value)
2205 * @param aChan the channel the header came from
2206 */
2207 inline uint32_t
2208 NS_GetContentDispositionFromHeader(const nsACString& aHeader, nsIChannel *aChan = nullptr)
2209 {
2210 nsresult rv;
2211 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
2212 if (NS_FAILED(rv))
2213 return nsIChannel::DISPOSITION_ATTACHMENT;
2214
2215 nsAutoCString fallbackCharset;
2216 if (aChan) {
2217 nsCOMPtr<nsIURI> uri;
2218 aChan->GetURI(getter_AddRefs(uri));
2219 if (uri)
2220 uri->GetOriginCharset(fallbackCharset);
2221 }
2222
2223 nsAutoString dispToken;
2224 rv = mimehdrpar->GetParameterHTTP(aHeader, "", fallbackCharset, true, nullptr,
2225 dispToken);
2226
2227 if (NS_FAILED(rv)) {
2228 // special case (see bug 272541): empty disposition type handled as "inline"
2229 if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY)
2230 return nsIChannel::DISPOSITION_INLINE;
2231 return nsIChannel::DISPOSITION_ATTACHMENT;
2232 }
2233
2234 return NS_GetContentDispositionFromToken(dispToken);
2235 }
2236
2237 /** Extracts the filename out of a content-disposition header
2238 * @param aFilename [out] The filename. Can be empty on error.
2239 * @param aDisposition Value of a Content-Disposition header
2240 * @param aURI Optional. Will be used to get a fallback charset for the
2241 * filename, if it is QI'able to nsIURL
2242 */
2243 inline nsresult
2244 NS_GetFilenameFromDisposition(nsAString& aFilename,
2245 const nsACString& aDisposition,
2246 nsIURI* aURI = nullptr)
2247 {
2248 aFilename.Truncate();
2249
2250 nsresult rv;
2251 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
2252 do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
2253 if (NS_FAILED(rv))
2254 return rv;
2255
2256 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
2257
2258 nsAutoCString fallbackCharset;
2259 if (url)
2260 url->GetOriginCharset(fallbackCharset);
2261 // Get the value of 'filename' parameter
2262 rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename",
2263 fallbackCharset, true, nullptr,
2264 aFilename);
2265
2266 if (NS_FAILED(rv)) {
2267 aFilename.Truncate();
2268 return rv;
2269 }
2270
2271 if (aFilename.IsEmpty())
2272 return NS_ERROR_NOT_AVAILABLE;
2273
2274 return NS_OK;
2275 }
2276
2277 /**
2278 * Make sure Personal Security Manager is initialized
2279 */
2280 inline void
2281 net_EnsurePSMInit()
2282 {
2283 nsCOMPtr<nsISocketProviderService> spserv =
2284 do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
2285 if (spserv) {
2286 nsCOMPtr<nsISocketProvider> provider;
2287 spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
2288 }
2289 }
2290
2291 /**
2292 * Test whether a URI is "about:blank". |uri| must not be null
2293 */
2294 inline bool
2295 NS_IsAboutBlank(nsIURI *uri)
2296 {
2297 // GetSpec can be expensive for some URIs, so check the scheme first.
2298 bool isAbout = false;
2299 if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) {
2300 return false;
2301 }
2302
2303 nsAutoCString str;
2304 uri->GetSpec(str);
2305 return str.EqualsLiteral("about:blank");
2306 }
2307
2308
2309 inline nsresult
2310 NS_GenerateHostPort(const nsCString& host, int32_t port,
2311 nsCString& hostLine)
2312 {
2313 if (strchr(host.get(), ':')) {
2314 // host is an IPv6 address literal and must be encapsulated in []'s
2315 hostLine.Assign('[');
2316 // scope id is not needed for Host header.
2317 int scopeIdPos = host.FindChar('%');
2318 if (scopeIdPos == -1)
2319 hostLine.Append(host);
2320 else if (scopeIdPos > 0)
2321 hostLine.Append(Substring(host, 0, scopeIdPos));
2322 else
2323 return NS_ERROR_MALFORMED_URI;
2324 hostLine.Append(']');
2325 }
2326 else
2327 hostLine.Assign(host);
2328 if (port != -1) {
2329 hostLine.Append(':');
2330 hostLine.AppendInt(port);
2331 }
2332 return NS_OK;
2333 }
2334
2335 /**
2336 * Sniff the content type for a given request or a given buffer.
2337 *
2338 * aSnifferType can be either NS_CONTENT_SNIFFER_CATEGORY or
2339 * NS_DATA_SNIFFER_CATEGORY. The function returns the sniffed content type
2340 * in the aSniffedType argument. This argument will not be modified if the
2341 * content type could not be sniffed.
2342 */
2343 inline void
2344 NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest,
2345 const uint8_t* aData, uint32_t aLength,
2346 nsACString& aSniffedType)
2347 {
2348 typedef nsCategoryCache<nsIContentSniffer> ContentSnifferCache;
2349 extern NS_HIDDEN_(ContentSnifferCache*) gNetSniffers;
2350 extern NS_HIDDEN_(ContentSnifferCache*) gDataSniffers;
2351 ContentSnifferCache* cache = nullptr;
2352 if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
2353 if (!gNetSniffers) {
2354 gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
2355 }
2356 cache = gNetSniffers;
2357 } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
2358 if (!gDataSniffers) {
2359 gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
2360 }
2361 cache = gDataSniffers;
2362 } else {
2363 // Invalid content sniffer type was requested
2364 MOZ_ASSERT(false);
2365 return;
2366 }
2367
2368 nsCOMArray<nsIContentSniffer> sniffers;
2369 cache->GetEntries(sniffers);
2370 for (int32_t i = 0; i < sniffers.Count(); ++i) {
2371 nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength, aSniffedType);
2372 if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
2373 return;
2374 }
2375 }
2376
2377 aSniffedType.Truncate();
2378 }
2379
2380 /**
2381 * Whether the channel was created to load a srcdoc document.
2382 * Note that view-source:about:srcdoc is classified as a srcdoc document by
2383 * this function, which may not be applicable everywhere.
2384 */
2385 inline bool
2386 NS_IsSrcdocChannel(nsIChannel *aChannel)
2387 {
2388 bool isSrcdoc;
2389 nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
2390 if (isr) {
2391 isr->GetIsSrcdocChannel(&isSrcdoc);
2392 return isSrcdoc;
2393 }
2394 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
2395 if (vsc) {
2396 vsc->GetIsSrcdocChannel(&isSrcdoc);
2397 return isSrcdoc;
2398 }
2399 return false;
2400 }
2401
2402 #endif // !nsNetUtil_h__

mercurial