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_inl
8 #define nsNetUtil_inl
9 
10 #include "mozilla/Services.h"
11 
12 #include "nsComponentManagerUtils.h"
13 #include "nsIBufferedStreams.h"
14 #include "nsIChannel.h"
15 #include "nsIFile.h"
16 #include "nsIFileStreams.h"
17 #include "nsIFileURL.h"
18 #include "nsIHttpChannel.h"
19 #include "nsIInputStreamChannel.h"
20 #include "nsIIOService.h"
21 #include "nsINestedURI.h"
22 #include "nsINode.h"
23 #include "nsIProtocolHandler.h"
24 #include "nsIStandardURL.h"
25 #include "nsIStreamLoader.h"
26 #include "nsIIncrementalStreamLoader.h"
27 #include "nsIURI.h"
28 #include "nsIURIWithPrincipal.h"
29 #include "nsIWritablePropertyBag2.h"
30 #include "nsNetCID.h"
31 #include "nsStringStream.h"
32 
33 #ifdef MOZILLA_INTERNAL_API
34 // Don't allow functions that end up in nsNetUtil.cpp to be inlined out.
35 #define INLINE_IF_EXTERN MOZ_NEVER_INLINE
36 #else
37 // Make sure that functions included via nsNetUtil.h don't get multiply defined.
38 #define INLINE_IF_EXTERN MOZ_ALWAYS_INLINE
39 #endif
40 
41 #ifdef MOZILLA_INTERNAL_API
42 
43 INLINE_IF_EXTERN already_AddRefed<nsIIOService>
do_GetIOService(nsresult * error)44 do_GetIOService(nsresult *error /* = 0 */)
45 {
46     nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
47     if (error)
48         *error = io ? NS_OK : NS_ERROR_FAILURE;
49     return io.forget();
50 }
51 
52 INLINE_IF_EXTERN already_AddRefed<nsINetUtil>
do_GetNetUtil(nsresult * error)53 do_GetNetUtil(nsresult *error /* = 0 */)
54 {
55     nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
56     nsCOMPtr<nsINetUtil> util;
57     if (io)
58         util = do_QueryInterface(io);
59 
60     if (error)
61         *error = !!util ? NS_OK : NS_ERROR_FAILURE;
62     return util.forget();
63 }
64 
65 #else
66 
67 INLINE_IF_EXTERN const nsGetServiceByContractIDWithError
do_GetIOService(nsresult * error)68 do_GetIOService(nsresult *error /* = 0 */)
69 {
70     return nsGetServiceByContractIDWithError(NS_IOSERVICE_CONTRACTID, error);
71 }
72 
73 INLINE_IF_EXTERN const nsGetServiceByContractIDWithError
do_GetNetUtil(nsresult * error)74 do_GetNetUtil(nsresult *error /* = 0 */)
75 {
76     return do_GetIOService(error);
77 }
78 #endif
79 
80 // private little helper function... don't call this directly!
81 MOZ_ALWAYS_INLINE nsresult
net_EnsureIOService(nsIIOService ** ios,nsCOMPtr<nsIIOService> & grip)82 net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip)
83 {
84     nsresult rv = NS_OK;
85     if (!*ios) {
86         grip = do_GetIOService(&rv);
87         *ios = grip;
88     }
89     return rv;
90 }
91 
92 INLINE_IF_EXTERN nsresult
NS_URIChainHasFlags(nsIURI * uri,uint32_t flags,bool * result)93 NS_URIChainHasFlags(nsIURI   *uri,
94                     uint32_t  flags,
95                     bool     *result)
96 {
97     nsresult rv;
98     nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
99     NS_ENSURE_SUCCESS(rv, rv);
100 
101     return util->URIChainHasFlags(uri, flags, result);
102 }
103 
104 INLINE_IF_EXTERN nsresult
NS_NewURI(nsIURI ** result,const nsACString & spec,const char * charset,nsIURI * baseURI,nsIIOService * ioService)105 NS_NewURI(nsIURI **result,
106           const nsACString &spec,
107           const char *charset /* = nullptr */,
108           nsIURI *baseURI /* = nullptr */,
109           nsIIOService *ioService /* = nullptr */)     // pass in nsIIOService to optimize callers
110 {
111     nsresult rv;
112     nsCOMPtr<nsIIOService> grip;
113     rv = net_EnsureIOService(&ioService, grip);
114     if (ioService)
115         rv = ioService->NewURI(spec, charset, baseURI, result);
116     return rv;
117 }
118 
119 INLINE_IF_EXTERN nsresult
NS_NewURI(nsIURI ** result,const nsAString & spec,const char * charset,nsIURI * baseURI,nsIIOService * ioService)120 NS_NewURI(nsIURI **result,
121           const nsAString &spec,
122           const char *charset /* = nullptr */,
123           nsIURI *baseURI /* = nullptr */,
124           nsIIOService *ioService /* = nullptr */)     // pass in nsIIOService to optimize callers
125 {
126     return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI, ioService);
127 }
128 
129 INLINE_IF_EXTERN nsresult
NS_NewURI(nsIURI ** result,const char * spec,nsIURI * baseURI,nsIIOService * ioService)130 NS_NewURI(nsIURI **result,
131           const char *spec,
132           nsIURI *baseURI /* = nullptr */,
133           nsIIOService *ioService /* = nullptr */)     // pass in nsIIOService to optimize callers
134 {
135     return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI, ioService);
136 }
137 
138 INLINE_IF_EXTERN nsresult
NS_NewFileURI(nsIURI ** result,nsIFile * spec,nsIIOService * ioService)139 NS_NewFileURI(nsIURI **result,
140               nsIFile *spec,
141               nsIIOService *ioService /* = nullptr */)     // pass in nsIIOService to optimize callers
142 {
143     nsresult rv;
144     nsCOMPtr<nsIIOService> grip;
145     rv = net_EnsureIOService(&ioService, grip);
146     if (ioService)
147         rv = ioService->NewFileURI(spec, result);
148     return rv;
149 }
150 
151 INLINE_IF_EXTERN nsresult
NS_NewChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,nsINode * aLoadingNode,nsIPrincipal * aLoadingPrincipal,nsIPrincipal * aTriggeringPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)152 NS_NewChannelInternal(nsIChannel           **outChannel,
153                       nsIURI                *aUri,
154                       nsINode               *aLoadingNode,
155                       nsIPrincipal          *aLoadingPrincipal,
156                       nsIPrincipal          *aTriggeringPrincipal,
157                       nsSecurityFlags        aSecurityFlags,
158                       nsContentPolicyType    aContentPolicyType,
159                       nsILoadGroup          *aLoadGroup /* = nullptr */,
160                       nsIInterfaceRequestor *aCallbacks /* = nullptr */,
161                       nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
162                       nsIIOService          *aIoService /* = nullptr */)
163 {
164   NS_ENSURE_ARG_POINTER(outChannel);
165 
166   nsCOMPtr<nsIIOService> grip;
167   nsresult rv = net_EnsureIOService(&aIoService, grip);
168   NS_ENSURE_SUCCESS(rv, rv);
169 
170   nsCOMPtr<nsIChannel> channel;
171   rv = aIoService->NewChannelFromURI2(
172          aUri,
173          aLoadingNode ?
174            aLoadingNode->AsDOMNode() : nullptr,
175          aLoadingPrincipal,
176          aTriggeringPrincipal,
177          aSecurityFlags,
178          aContentPolicyType,
179          getter_AddRefs(channel));
180   NS_ENSURE_SUCCESS(rv, rv);
181 
182   if (aLoadGroup) {
183     rv = channel->SetLoadGroup(aLoadGroup);
184     NS_ENSURE_SUCCESS(rv, rv);
185   }
186 
187   if (aCallbacks) {
188     rv = channel->SetNotificationCallbacks(aCallbacks);
189     NS_ENSURE_SUCCESS(rv, rv);
190   }
191 
192   if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
193     // Retain the LOAD_REPLACE load flag if set.
194     nsLoadFlags normalLoadFlags = 0;
195     channel->GetLoadFlags(&normalLoadFlags);
196     rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
197     NS_ENSURE_SUCCESS(rv, rv);
198   }
199 
200   channel.forget(outChannel);
201   return NS_OK;
202 }
203 
204 INLINE_IF_EXTERN nsresult
NS_NewChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,nsILoadInfo * aLoadInfo,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)205 NS_NewChannelInternal(nsIChannel           **outChannel,
206                       nsIURI                *aUri,
207                       nsILoadInfo           *aLoadInfo,
208                       nsILoadGroup          *aLoadGroup /* = nullptr */,
209                       nsIInterfaceRequestor *aCallbacks /* = nullptr */,
210                       nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
211                       nsIIOService          *aIoService /* = nullptr */)
212 {
213   // NS_NewChannelInternal is mostly called for channel redirects. We should allow
214   // the creation of a channel even if the original channel did not have a loadinfo
215   // attached.
216   NS_ENSURE_ARG_POINTER(outChannel);
217 
218   nsCOMPtr<nsIIOService> grip;
219   nsresult rv = net_EnsureIOService(&aIoService, grip);
220   NS_ENSURE_SUCCESS(rv, rv);
221 
222   nsCOMPtr<nsIChannel> channel;
223   rv = aIoService->NewChannelFromURIWithLoadInfo(
224          aUri,
225          aLoadInfo,
226          getter_AddRefs(channel));
227   NS_ENSURE_SUCCESS(rv, rv);
228 
229   if (aLoadGroup) {
230     rv = channel->SetLoadGroup(aLoadGroup);
231     NS_ENSURE_SUCCESS(rv, rv);
232   }
233 
234   if (aCallbacks) {
235     rv = channel->SetNotificationCallbacks(aCallbacks);
236     NS_ENSURE_SUCCESS(rv, rv);
237   }
238 
239   if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
240     // Retain the LOAD_REPLACE load flag if set.
241     nsLoadFlags normalLoadFlags = 0;
242     channel->GetLoadFlags(&normalLoadFlags);
243     rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
244     NS_ENSURE_SUCCESS(rv, rv);
245   }
246 
247   channel.forget(outChannel);
248   return NS_OK;
249 }
250 
251 INLINE_IF_EXTERN nsresult /* NS_NewChannelPrincipal */
NS_NewChannel(nsIChannel ** outChannel,nsIURI * aUri,nsIPrincipal * aLoadingPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)252 NS_NewChannel(nsIChannel           **outChannel,
253               nsIURI                *aUri,
254               nsIPrincipal          *aLoadingPrincipal,
255               nsSecurityFlags        aSecurityFlags,
256               nsContentPolicyType    aContentPolicyType,
257               nsILoadGroup          *aLoadGroup /* = nullptr */,
258               nsIInterfaceRequestor *aCallbacks /* = nullptr */,
259               nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
260               nsIIOService          *aIoService /* = nullptr */)
261 {
262   return NS_NewChannelInternal(outChannel,
263                                aUri,
264                                nullptr, // aLoadingNode,
265                                aLoadingPrincipal,
266                                nullptr, // aTriggeringPrincipal
267                                aSecurityFlags,
268                                aContentPolicyType,
269                                aLoadGroup,
270                                aCallbacks,
271                                aLoadFlags,
272                                aIoService);
273 }
274 
275 INLINE_IF_EXTERN nsresult
NS_NewStreamLoader(nsIStreamLoader ** result,nsIStreamLoaderObserver * observer,nsIRequestObserver * requestObserver)276 NS_NewStreamLoader(nsIStreamLoader        **result,
277                    nsIStreamLoaderObserver *observer,
278                    nsIRequestObserver      *requestObserver /* = nullptr */)
279 {
280     nsresult rv;
281     nsCOMPtr<nsIStreamLoader> loader =
282         do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
283     if (NS_SUCCEEDED(rv)) {
284         rv = loader->Init(observer, requestObserver);
285         if (NS_SUCCEEDED(rv)) {
286             *result = nullptr;
287             loader.swap(*result);
288         }
289     }
290     return rv;
291 }
292 
293 INLINE_IF_EXTERN nsresult
NS_NewLocalFileInputStream(nsIInputStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)294 NS_NewLocalFileInputStream(nsIInputStream **result,
295                            nsIFile         *file,
296                            int32_t          ioFlags       /* = -1 */,
297                            int32_t          perm          /* = -1 */,
298                            int32_t          behaviorFlags /* = 0 */)
299 {
300     nsresult rv;
301     nsCOMPtr<nsIFileInputStream> in =
302         do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
303     if (NS_SUCCEEDED(rv)) {
304         rv = in->Init(file, ioFlags, perm, behaviorFlags);
305         if (NS_SUCCEEDED(rv))
306             in.forget(result);
307     }
308     return rv;
309 }
310 
311 INLINE_IF_EXTERN nsresult
NS_NewLocalFileOutputStream(nsIOutputStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)312 NS_NewLocalFileOutputStream(nsIOutputStream **result,
313                             nsIFile          *file,
314                             int32_t           ioFlags       /* = -1 */,
315                             int32_t           perm          /* = -1 */,
316                             int32_t           behaviorFlags /* = 0 */)
317 {
318     nsresult rv;
319     nsCOMPtr<nsIFileOutputStream> out =
320         do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
321     if (NS_SUCCEEDED(rv)) {
322         rv = out->Init(file, ioFlags, perm, behaviorFlags);
323         if (NS_SUCCEEDED(rv))
324             out.forget(result);
325     }
326     return rv;
327 }
328 
329 INLINE_IF_EXTERN MOZ_MUST_USE nsresult
NS_NewBufferedInputStream(nsIInputStream ** result,nsIInputStream * str,uint32_t bufferSize)330 NS_NewBufferedInputStream(nsIInputStream **result,
331                           nsIInputStream  *str,
332                           uint32_t         bufferSize)
333 {
334     nsresult rv;
335     nsCOMPtr<nsIBufferedInputStream> in =
336         do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
337     if (NS_SUCCEEDED(rv)) {
338         rv = in->Init(str, bufferSize);
339         if (NS_SUCCEEDED(rv)) {
340             in.forget(result);
341         }
342     }
343     return rv;
344 }
345 
346 INLINE_IF_EXTERN nsresult
NS_NewPostDataStream(nsIInputStream ** result,bool isFile,const nsACString & data)347 NS_NewPostDataStream(nsIInputStream  **result,
348                      bool              isFile,
349                      const nsACString &data)
350 {
351     nsresult rv;
352 
353     if (isFile) {
354         nsCOMPtr<nsIFile> file;
355         nsCOMPtr<nsIInputStream> fileStream;
356 
357         rv = NS_NewNativeLocalFile(data, false, getter_AddRefs(file));
358         if (NS_SUCCEEDED(rv)) {
359             rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
360             if (NS_SUCCEEDED(rv)) {
361                 // wrap the file stream with a buffered input stream
362                 rv = NS_NewBufferedInputStream(result, fileStream, 8192);
363             }
364         }
365         return rv;
366     }
367 
368     // otherwise, create a string stream for the data (copies)
369     nsCOMPtr<nsIStringInputStream> stream
370         (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
371     if (NS_FAILED(rv))
372         return rv;
373 
374     rv = stream->SetData(data.BeginReading(), data.Length());
375     if (NS_FAILED(rv))
376         return rv;
377 
378     stream.forget(result);
379     return NS_OK;
380 }
381 
382 INLINE_IF_EXTERN bool
NS_IsOffline()383 NS_IsOffline()
384 {
385     bool offline = true;
386     bool connectivity = true;
387     nsCOMPtr<nsIIOService> ios = do_GetIOService();
388     if (ios) {
389         ios->GetOffline(&offline);
390         ios->GetConnectivity(&connectivity);
391     }
392     return offline || !connectivity;
393 }
394 
395 #endif // nsNetUtil_inl
396