Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 sts=4 et filetype=javascript
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/. */
7 this.EXPORTED_SYMBOLS = [
8 "NetUtil",
9 ];
11 /**
12 * Necko utilities
13 */
15 ////////////////////////////////////////////////////////////////////////////////
16 //// Constants
18 const Ci = Components.interfaces;
19 const Cc = Components.classes;
20 const Cr = Components.results;
21 const Cu = Components.utils;
23 const PR_UINT32_MAX = 0xffffffff;
25 ////////////////////////////////////////////////////////////////////////////////
26 //// NetUtil Object
28 this.NetUtil = {
29 /**
30 * Function to perform simple async copying from aSource (an input stream)
31 * to aSink (an output stream). The copy will happen on some background
32 * thread. Both streams will be closed when the copy completes.
33 *
34 * @param aSource
35 * The input stream to read from
36 * @param aSink
37 * The output stream to write to
38 * @param aCallback [optional]
39 * A function that will be called at copy completion with a single
40 * argument: the nsresult status code for the copy operation.
41 *
42 * @return An nsIRequest representing the copy operation (for example, this
43 * can be used to cancel the copying). The consumer can ignore the
44 * return value if desired.
45 */
46 asyncCopy: function NetUtil_asyncCopy(aSource, aSink,
47 aCallback = null)
48 {
49 if (!aSource || !aSink) {
50 let exception = new Components.Exception(
51 "Must have a source and a sink",
52 Cr.NS_ERROR_INVALID_ARG,
53 Components.stack.caller
54 );
55 throw exception;
56 }
58 // make a stream copier
59 var copier = Cc["@mozilla.org/network/async-stream-copier;1"].
60 createInstance(Ci.nsIAsyncStreamCopier2);
61 copier.init(aSource, aSink,
62 null /* Default event target */,
63 0 /* Default length */,
64 true, true /* Auto-close */);
66 var observer;
67 if (aCallback) {
68 observer = {
69 onStartRequest: function(aRequest, aContext) {},
70 onStopRequest: function(aRequest, aContext, aStatusCode) {
71 aCallback(aStatusCode);
72 }
73 }
74 } else {
75 observer = null;
76 }
78 // start the copying
79 copier.QueryInterface(Ci.nsIAsyncStreamCopier).asyncCopy(observer, null);
80 return copier;
81 },
83 /**
84 * Asynchronously opens a source and fetches the response. A source can be
85 * an nsIURI, nsIFile, string spec, nsIChannel, or nsIInputStream. The
86 * provided callback will get an input stream containing the response, the
87 * result code, and a reference to the request.
88 *
89 * @param aSource
90 * The nsIURI, nsIFile, string spec, nsIChannel, or nsIInputStream
91 * to open.
92 * @param aCallback
93 * The callback function that will be notified upon completion. It
94 * will get two arguments:
95 * 1) An nsIInputStream containing the data from aSource, if any.
96 * 2) The status code from opening the source.
97 * 3) Reference to the nsIRequest.
98 */
99 asyncFetch: function NetUtil_asyncOpen(aSource, aCallback)
100 {
101 if (!aSource || !aCallback) {
102 let exception = new Components.Exception(
103 "Must have a source and a callback",
104 Cr.NS_ERROR_INVALID_ARG,
105 Components.stack.caller
106 );
107 throw exception;
108 }
110 // Create a pipe that will create our output stream that we can use once
111 // we have gotten all the data.
112 let pipe = Cc["@mozilla.org/pipe;1"].
113 createInstance(Ci.nsIPipe);
114 pipe.init(true, true, 0, PR_UINT32_MAX, null);
116 // Create a listener that will give data to the pipe's output stream.
117 let listener = Cc["@mozilla.org/network/simple-stream-listener;1"].
118 createInstance(Ci.nsISimpleStreamListener);
119 listener.init(pipe.outputStream, {
120 onStartRequest: function(aRequest, aContext) {},
121 onStopRequest: function(aRequest, aContext, aStatusCode) {
122 pipe.outputStream.close();
123 aCallback(pipe.inputStream, aStatusCode, aRequest);
124 }
125 });
127 // Input streams are handled slightly differently from everything else.
128 if (aSource instanceof Ci.nsIInputStream) {
129 let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
130 createInstance(Ci.nsIInputStreamPump);
131 pump.init(aSource, -1, -1, 0, 0, true);
132 pump.asyncRead(listener, null);
133 return;
134 }
136 let channel = aSource;
137 if (!(channel instanceof Ci.nsIChannel)) {
138 channel = this.newChannel(aSource);
139 }
141 try {
142 channel.asyncOpen(listener, null);
143 }
144 catch (e) {
145 let exception = new Components.Exception(
146 "Failed to open input source '" + channel.originalURI.spec + "'",
147 e.result,
148 Components.stack.caller,
149 aSource,
150 e
151 );
152 throw exception;
153 }
154 },
156 /**
157 * Constructs a new URI for the given spec, character set, and base URI, or
158 * an nsIFile.
159 *
160 * @param aTarget
161 * The string spec for the desired URI or an nsIFile.
162 * @param aOriginCharset [optional]
163 * The character set for the URI. Only used if aTarget is not an
164 * nsIFile.
165 * @param aBaseURI [optional]
166 * The base URI for the spec. Only used if aTarget is not an
167 * nsIFile.
168 *
169 * @return an nsIURI object.
170 */
171 newURI: function NetUtil_newURI(aTarget, aOriginCharset, aBaseURI)
172 {
173 if (!aTarget) {
174 let exception = new Components.Exception(
175 "Must have a non-null string spec or nsIFile object",
176 Cr.NS_ERROR_INVALID_ARG,
177 Components.stack.caller
178 );
179 throw exception;
180 }
182 if (aTarget instanceof Ci.nsIFile) {
183 return this.ioService.newFileURI(aTarget);
184 }
186 return this.ioService.newURI(aTarget, aOriginCharset, aBaseURI);
187 },
189 /**
190 * Constructs a new channel for the given spec, character set, and base URI,
191 * or nsIURI, or nsIFile.
192 *
193 * @param aWhatToLoad
194 * The string spec for the desired URI, an nsIURI, or an nsIFile.
195 * @param aOriginCharset [optional]
196 * The character set for the URI. Only used if aWhatToLoad is a
197 * string.
198 * @param aBaseURI [optional]
199 * The base URI for the spec. Only used if aWhatToLoad is a string.
200 *
201 * @return an nsIChannel object.
202 */
203 newChannel: function NetUtil_newChannel(aWhatToLoad, aOriginCharset,
204 aBaseURI)
205 {
206 if (!aWhatToLoad) {
207 let exception = new Components.Exception(
208 "Must have a non-null string spec, nsIURI, or nsIFile object",
209 Cr.NS_ERROR_INVALID_ARG,
210 Components.stack.caller
211 );
212 throw exception;
213 }
215 let uri = aWhatToLoad;
216 if (!(aWhatToLoad instanceof Ci.nsIURI)) {
217 // We either have a string or an nsIFile that we'll need a URI for.
218 uri = this.newURI(aWhatToLoad, aOriginCharset, aBaseURI);
219 }
221 return this.ioService.newChannelFromURI(uri);
222 },
224 /**
225 * Reads aCount bytes from aInputStream into a string.
226 *
227 * @param aInputStream
228 * The input stream to read from.
229 * @param aCount
230 * The number of bytes to read from the stream.
231 * @param aOptions [optional]
232 * charset
233 * The character encoding of stream data.
234 * replacement
235 * The character to replace unknown byte sequences.
236 * If unset, it causes an exceptions to be thrown.
237 *
238 * @return the bytes from the input stream in string form.
239 *
240 * @throws NS_ERROR_INVALID_ARG if aInputStream is not an nsIInputStream.
241 * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from aInputStream would
242 * block the calling thread (non-blocking mode only).
243 * @throws NS_ERROR_FAILURE if there are not enough bytes available to read
244 * aCount amount of data.
245 * @throws NS_ERROR_ILLEGAL_INPUT if aInputStream has invalid sequences
246 */
247 readInputStreamToString: function NetUtil_readInputStreamToString(aInputStream,
248 aCount,
249 aOptions)
250 {
251 if (!(aInputStream instanceof Ci.nsIInputStream)) {
252 let exception = new Components.Exception(
253 "First argument should be an nsIInputStream",
254 Cr.NS_ERROR_INVALID_ARG,
255 Components.stack.caller
256 );
257 throw exception;
258 }
260 if (!aCount) {
261 let exception = new Components.Exception(
262 "Non-zero amount of bytes must be specified",
263 Cr.NS_ERROR_INVALID_ARG,
264 Components.stack.caller
265 );
266 throw exception;
267 }
269 if (aOptions && "charset" in aOptions) {
270 let cis = Cc["@mozilla.org/intl/converter-input-stream;1"].
271 createInstance(Ci.nsIConverterInputStream);
272 try {
273 // When replacement is set, the character that is unknown sequence
274 // replaces with aOptions.replacement character.
275 if (!("replacement" in aOptions)) {
276 // aOptions.replacement isn't set.
277 // If input stream has unknown sequences for aOptions.charset,
278 // throw NS_ERROR_ILLEGAL_INPUT.
279 aOptions.replacement = 0;
280 }
282 cis.init(aInputStream, aOptions.charset, aCount,
283 aOptions.replacement);
284 let str = {};
285 cis.readString(-1, str);
286 cis.close();
287 return str.value;
288 }
289 catch (e) {
290 // Adjust the stack so it throws at the caller's location.
291 throw new Components.Exception(e.message, e.result,
292 Components.stack.caller, e.data);
293 }
294 }
296 let sis = Cc["@mozilla.org/scriptableinputstream;1"].
297 createInstance(Ci.nsIScriptableInputStream);
298 sis.init(aInputStream);
299 try {
300 return sis.readBytes(aCount);
301 }
302 catch (e) {
303 // Adjust the stack so it throws at the caller's location.
304 throw new Components.Exception(e.message, e.result,
305 Components.stack.caller, e.data);
306 }
307 },
309 /**
310 * Returns a reference to nsIIOService.
311 *
312 * @return a reference to nsIIOService.
313 */
314 get ioService()
315 {
316 delete this.ioService;
317 return this.ioService = Cc["@mozilla.org/network/io-service;1"].
318 getService(Ci.nsIIOService);
319 },
320 };
322 ////////////////////////////////////////////////////////////////////////////////
323 //// Initialization
325 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
327 // Define our lazy getters.
328 XPCOMUtils.defineLazyServiceGetter(this, "ioUtil", "@mozilla.org/io-util;1",
329 "nsIIOUtil");