netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:29adbefb1ad0
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "nsWyciwyg.h"
6
7 #include "base/compiler_specific.h"
8
9 #include "mozilla/net/ChannelEventQueue.h"
10 #include "WyciwygChannelChild.h"
11 #include "mozilla/dom/TabChild.h"
12
13 #include "nsCharsetSource.h"
14 #include "nsStringStream.h"
15 #include "nsNetUtil.h"
16 #include "nsISerializable.h"
17 #include "nsSerializationHelper.h"
18 #include "nsIProgressEventSink.h"
19 #include "mozilla/ipc/URIUtils.h"
20 #include "SerializedLoadContext.h"
21
22 using namespace mozilla::ipc;
23
24 namespace mozilla {
25 namespace net {
26
27 NS_IMPL_ISUPPORTS(WyciwygChannelChild,
28 nsIRequest,
29 nsIChannel,
30 nsIWyciwygChannel,
31 nsIPrivateBrowsingChannel)
32
33
34 WyciwygChannelChild::WyciwygChannelChild()
35 : mStatus(NS_OK)
36 , mIsPending(false)
37 , mCanceled(false)
38 , mLoadFlags(LOAD_NORMAL)
39 , mContentLength(-1)
40 , mCharsetSource(kCharsetUninitialized)
41 , mState(WCC_NEW)
42 , mIPCOpen(false)
43 , mSentAppData(false)
44 {
45 LOG(("Creating WyciwygChannelChild @%x\n", this));
46 mEventQ = new ChannelEventQueue(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this));
47 }
48
49 WyciwygChannelChild::~WyciwygChannelChild()
50 {
51 LOG(("Destroying WyciwygChannelChild @%x\n", this));
52 }
53
54 void
55 WyciwygChannelChild::AddIPDLReference()
56 {
57 NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
58 mIPCOpen = true;
59 AddRef();
60 }
61
62 void
63 WyciwygChannelChild::ReleaseIPDLReference()
64 {
65 NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
66 mIPCOpen = false;
67 Release();
68 }
69
70 nsresult
71 WyciwygChannelChild::Init(nsIURI* uri)
72 {
73 NS_ENSURE_ARG_POINTER(uri);
74
75 mState = WCC_INIT;
76
77 mURI = uri;
78 mOriginalURI = uri;
79
80 URIParams serializedUri;
81 SerializeURI(uri, serializedUri);
82
83 SendInit(serializedUri);
84 return NS_OK;
85 }
86
87 //-----------------------------------------------------------------------------
88 // WyciwygChannelChild::PWyciwygChannelChild
89 //-----------------------------------------------------------------------------
90
91 class WyciwygStartRequestEvent : public ChannelEvent
92 {
93 public:
94 WyciwygStartRequestEvent(WyciwygChannelChild* child,
95 const nsresult& statusCode,
96 const int64_t& contentLength,
97 const int32_t& source,
98 const nsCString& charset,
99 const nsCString& securityInfo)
100 : mChild(child), mStatusCode(statusCode), mContentLength(contentLength),
101 mSource(source), mCharset(charset), mSecurityInfo(securityInfo) {}
102 void Run() { mChild->OnStartRequest(mStatusCode, mContentLength, mSource,
103 mCharset, mSecurityInfo); }
104 private:
105 WyciwygChannelChild* mChild;
106 nsresult mStatusCode;
107 int64_t mContentLength;
108 int32_t mSource;
109 nsCString mCharset;
110 nsCString mSecurityInfo;
111 };
112
113 bool
114 WyciwygChannelChild::RecvOnStartRequest(const nsresult& statusCode,
115 const int64_t& contentLength,
116 const int32_t& source,
117 const nsCString& charset,
118 const nsCString& securityInfo)
119 {
120 if (mEventQ->ShouldEnqueue()) {
121 mEventQ->Enqueue(new WyciwygStartRequestEvent(this, statusCode,
122 contentLength, source,
123 charset, securityInfo));
124 } else {
125 OnStartRequest(statusCode, contentLength, source, charset, securityInfo);
126 }
127 return true;
128 }
129
130 void
131 WyciwygChannelChild::OnStartRequest(const nsresult& statusCode,
132 const int64_t& contentLength,
133 const int32_t& source,
134 const nsCString& charset,
135 const nsCString& securityInfo)
136 {
137 LOG(("WyciwygChannelChild::RecvOnStartRequest [this=%p]\n", this));
138
139 mState = WCC_ONSTART;
140
141 mStatus = statusCode;
142 mContentLength = contentLength;
143 mCharsetSource = source;
144 mCharset = charset;
145
146 if (!securityInfo.IsEmpty()) {
147 NS_DeserializeObject(securityInfo, getter_AddRefs(mSecurityInfo));
148 }
149
150 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
151
152 nsresult rv = mListener->OnStartRequest(this, mListenerContext);
153 if (NS_FAILED(rv))
154 Cancel(rv);
155 }
156
157 class WyciwygDataAvailableEvent : public ChannelEvent
158 {
159 public:
160 WyciwygDataAvailableEvent(WyciwygChannelChild* child,
161 const nsCString& data,
162 const uint64_t& offset)
163 : mChild(child), mData(data), mOffset(offset) {}
164 void Run() { mChild->OnDataAvailable(mData, mOffset); }
165 private:
166 WyciwygChannelChild* mChild;
167 nsCString mData;
168 uint64_t mOffset;
169 };
170
171 bool
172 WyciwygChannelChild::RecvOnDataAvailable(const nsCString& data,
173 const uint64_t& offset)
174 {
175 if (mEventQ->ShouldEnqueue()) {
176 mEventQ->Enqueue(new WyciwygDataAvailableEvent(this, data, offset));
177 } else {
178 OnDataAvailable(data, offset);
179 }
180 return true;
181 }
182
183 void
184 WyciwygChannelChild::OnDataAvailable(const nsCString& data,
185 const uint64_t& offset)
186 {
187 LOG(("WyciwygChannelChild::RecvOnDataAvailable [this=%p]\n", this));
188
189 if (mCanceled)
190 return;
191
192 mState = WCC_ONDATA;
193
194 // NOTE: the OnDataAvailable contract requires the client to read all the data
195 // in the inputstream. This code relies on that ('data' will go away after
196 // this function). Apparently the previous, non-e10s behavior was to actually
197 // support only reading part of the data, allowing later calls to read the
198 // rest.
199 nsCOMPtr<nsIInputStream> stringStream;
200 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
201 data.get(),
202 data.Length(),
203 NS_ASSIGNMENT_DEPEND);
204 if (NS_FAILED(rv)) {
205 Cancel(rv);
206 return;
207 }
208
209 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
210
211 rv = mListener->OnDataAvailable(this, mListenerContext,
212 stringStream, offset, data.Length());
213 if (NS_FAILED(rv))
214 Cancel(rv);
215
216 if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
217 mProgressSink->OnProgress(this, nullptr, offset + data.Length(),
218 uint64_t(mContentLength));
219 }
220
221 class WyciwygStopRequestEvent : public ChannelEvent
222 {
223 public:
224 WyciwygStopRequestEvent(WyciwygChannelChild* child,
225 const nsresult& statusCode)
226 : mChild(child), mStatusCode(statusCode) {}
227 void Run() { mChild->OnStopRequest(mStatusCode); }
228 private:
229 WyciwygChannelChild* mChild;
230 nsresult mStatusCode;
231 };
232
233 bool
234 WyciwygChannelChild::RecvOnStopRequest(const nsresult& statusCode)
235 {
236 if (mEventQ->ShouldEnqueue()) {
237 mEventQ->Enqueue(new WyciwygStopRequestEvent(this, statusCode));
238 } else {
239 OnStopRequest(statusCode);
240 }
241 return true;
242 }
243
244 void
245 WyciwygChannelChild::OnStopRequest(const nsresult& statusCode)
246 {
247 LOG(("WyciwygChannelChild::RecvOnStopRequest [this=%p status=%u]\n",
248 this, statusCode));
249
250 { // We need to ensure that all IPDL message dispatching occurs
251 // before we delete the protocol below
252 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
253
254 mState = WCC_ONSTOP;
255
256 mIsPending = false;
257
258 if (!mCanceled)
259 mStatus = statusCode;
260
261 mListener->OnStopRequest(this, mListenerContext, statusCode);
262
263 mListener = 0;
264 mListenerContext = 0;
265
266 if (mLoadGroup)
267 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
268
269 mCallbacks = 0;
270 mProgressSink = 0;
271 }
272
273 if (mIPCOpen)
274 PWyciwygChannelChild::Send__delete__(this);
275 }
276
277 class WyciwygCancelEvent : public ChannelEvent
278 {
279 public:
280 WyciwygCancelEvent(WyciwygChannelChild* child, const nsresult& status)
281 : mChild(child)
282 , mStatus(status) {}
283
284 void Run() { mChild->CancelEarly(mStatus); }
285 private:
286 WyciwygChannelChild* mChild;
287 nsresult mStatus;
288 };
289
290 bool
291 WyciwygChannelChild::RecvCancelEarly(const nsresult& statusCode)
292 {
293 if (mEventQ->ShouldEnqueue()) {
294 mEventQ->Enqueue(new WyciwygCancelEvent(this, statusCode));
295 } else {
296 CancelEarly(statusCode);
297 }
298 return true;
299 }
300
301 void WyciwygChannelChild::CancelEarly(const nsresult& statusCode)
302 {
303 LOG(("WyciwygChannelChild::CancelEarly [this=%p]\n", this));
304
305 if (mCanceled)
306 return;
307
308 mCanceled = true;
309 mStatus = statusCode;
310
311 mIsPending = false;
312 if (mLoadGroup)
313 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
314
315 if (mListener) {
316 mListener->OnStartRequest(this, mListenerContext);
317 mListener->OnStopRequest(this, mListenerContext, mStatus);
318 }
319 mListener = nullptr;
320 mListenerContext = nullptr;
321
322 if (mIPCOpen)
323 PWyciwygChannelChild::Send__delete__(this);
324 }
325
326 //-----------------------------------------------------------------------------
327 // nsIRequest
328 //-----------------------------------------------------------------------------
329
330 /* readonly attribute AUTF8String name; */
331 NS_IMETHODIMP
332 WyciwygChannelChild::GetName(nsACString & aName)
333 {
334 return mURI->GetSpec(aName);
335 }
336
337 /* boolean isPending (); */
338 NS_IMETHODIMP
339 WyciwygChannelChild::IsPending(bool *aIsPending)
340 {
341 *aIsPending = mIsPending;
342 return NS_OK;
343 }
344
345 /* readonly attribute nsresult status; */
346 NS_IMETHODIMP
347 WyciwygChannelChild::GetStatus(nsresult *aStatus)
348 {
349 *aStatus = mStatus;
350 return NS_OK;
351 }
352
353 /* void cancel (in nsresult aStatus); */
354 NS_IMETHODIMP
355 WyciwygChannelChild::Cancel(nsresult aStatus)
356 {
357 if (mCanceled)
358 return NS_OK;
359
360 mCanceled = true;
361 mStatus = aStatus;
362 if (mIPCOpen)
363 SendCancel(aStatus);
364 return NS_OK;
365 }
366
367 /* void suspend (); */
368 NS_IMETHODIMP
369 WyciwygChannelChild::Suspend()
370 {
371 return NS_ERROR_NOT_IMPLEMENTED;
372 }
373
374 /* void resume (); */
375 NS_IMETHODIMP
376 WyciwygChannelChild::Resume()
377 {
378 return NS_ERROR_NOT_IMPLEMENTED;
379 }
380
381 /* attribute nsILoadGroup loadGroup; */
382 NS_IMETHODIMP
383 WyciwygChannelChild::GetLoadGroup(nsILoadGroup * *aLoadGroup)
384 {
385 *aLoadGroup = mLoadGroup;
386 NS_IF_ADDREF(*aLoadGroup);
387 return NS_OK;
388 }
389 NS_IMETHODIMP
390 WyciwygChannelChild::SetLoadGroup(nsILoadGroup * aLoadGroup)
391 {
392 if (!CanSetLoadGroup(aLoadGroup)) {
393 return NS_ERROR_FAILURE;
394 }
395
396 mLoadGroup = aLoadGroup;
397 NS_QueryNotificationCallbacks(mCallbacks,
398 mLoadGroup,
399 NS_GET_IID(nsIProgressEventSink),
400 getter_AddRefs(mProgressSink));
401 return NS_OK;
402 }
403
404 /* attribute nsLoadFlags loadFlags; */
405 NS_IMETHODIMP
406 WyciwygChannelChild::GetLoadFlags(nsLoadFlags *aLoadFlags)
407 {
408 *aLoadFlags = mLoadFlags;
409 return NS_OK;
410 }
411 NS_IMETHODIMP
412 WyciwygChannelChild::SetLoadFlags(nsLoadFlags aLoadFlags)
413 {
414 mLoadFlags = aLoadFlags;
415 return NS_OK;
416 }
417
418
419 //-----------------------------------------------------------------------------
420 // nsIChannel
421 //-----------------------------------------------------------------------------
422
423 /* attribute nsIURI originalURI; */
424 NS_IMETHODIMP
425 WyciwygChannelChild::GetOriginalURI(nsIURI * *aOriginalURI)
426 {
427 *aOriginalURI = mOriginalURI;
428 NS_ADDREF(*aOriginalURI);
429 return NS_OK;
430 }
431 NS_IMETHODIMP
432 WyciwygChannelChild::SetOriginalURI(nsIURI * aOriginalURI)
433 {
434 NS_ENSURE_TRUE(mState == WCC_INIT, NS_ERROR_UNEXPECTED);
435
436 NS_ENSURE_ARG_POINTER(aOriginalURI);
437 mOriginalURI = aOriginalURI;
438 return NS_OK;
439 }
440
441 /* readonly attribute nsIURI URI; */
442 NS_IMETHODIMP
443 WyciwygChannelChild::GetURI(nsIURI * *aURI)
444 {
445 *aURI = mURI;
446 NS_IF_ADDREF(*aURI);
447 return NS_OK;
448 }
449
450 /* attribute nsISupports owner; */
451 NS_IMETHODIMP
452 WyciwygChannelChild::GetOwner(nsISupports * *aOwner)
453 {
454 NS_PRECONDITION(mOwner, "Must have a principal!");
455 NS_ENSURE_STATE(mOwner);
456
457 NS_ADDREF(*aOwner = mOwner);
458 return NS_OK;
459 }
460 NS_IMETHODIMP
461 WyciwygChannelChild::SetOwner(nsISupports * aOwner)
462 {
463 mOwner = aOwner;
464 return NS_OK;
465 }
466
467 /* attribute nsIInterfaceRequestor notificationCallbacks; */
468 NS_IMETHODIMP
469 WyciwygChannelChild::GetNotificationCallbacks(nsIInterfaceRequestor * *aCallbacks)
470 {
471 *aCallbacks = mCallbacks;
472 NS_IF_ADDREF(*aCallbacks);
473 return NS_OK;
474 }
475 NS_IMETHODIMP
476 WyciwygChannelChild::SetNotificationCallbacks(nsIInterfaceRequestor * aCallbacks)
477 {
478 if (!CanSetCallbacks(aCallbacks)) {
479 return NS_ERROR_FAILURE;
480 }
481
482 mCallbacks = aCallbacks;
483 NS_QueryNotificationCallbacks(mCallbacks,
484 mLoadGroup,
485 NS_GET_IID(nsIProgressEventSink),
486 getter_AddRefs(mProgressSink));
487 return NS_OK;
488 }
489
490 /* readonly attribute nsISupports securityInfo; */
491 NS_IMETHODIMP
492 WyciwygChannelChild::GetSecurityInfo(nsISupports * *aSecurityInfo)
493 {
494 NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
495
496 return NS_OK;
497 }
498
499 /* attribute ACString contentType; */
500 NS_IMETHODIMP
501 WyciwygChannelChild::GetContentType(nsACString & aContentType)
502 {
503 aContentType.AssignLiteral(WYCIWYG_TYPE);
504 return NS_OK;
505 }
506 NS_IMETHODIMP
507 WyciwygChannelChild::SetContentType(const nsACString & aContentType)
508 {
509 return NS_ERROR_NOT_IMPLEMENTED;
510 }
511
512 /* attribute ACString contentCharset; */
513 NS_IMETHODIMP
514 WyciwygChannelChild::GetContentCharset(nsACString & aContentCharset)
515 {
516 aContentCharset.Assign("UTF-16");
517 return NS_OK;
518 }
519 NS_IMETHODIMP
520 WyciwygChannelChild::SetContentCharset(const nsACString & aContentCharset)
521 {
522 return NS_ERROR_NOT_IMPLEMENTED;
523 }
524
525 NS_IMETHODIMP
526 WyciwygChannelChild::GetContentDisposition(uint32_t *aContentDisposition)
527 {
528 return NS_ERROR_NOT_AVAILABLE;
529 }
530
531 NS_IMETHODIMP
532 WyciwygChannelChild::SetContentDisposition(uint32_t aContentDisposition)
533 {
534 return NS_ERROR_NOT_AVAILABLE;
535 }
536
537 NS_IMETHODIMP
538 WyciwygChannelChild::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
539 {
540 return NS_ERROR_NOT_AVAILABLE;
541 }
542
543 NS_IMETHODIMP
544 WyciwygChannelChild::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
545 {
546 return NS_ERROR_NOT_AVAILABLE;
547 }
548
549 NS_IMETHODIMP
550 WyciwygChannelChild::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
551 {
552 return NS_ERROR_NOT_AVAILABLE;
553 }
554
555 /* attribute int64_t contentLength; */
556 NS_IMETHODIMP
557 WyciwygChannelChild::GetContentLength(int64_t *aContentLength)
558 {
559 return NS_ERROR_NOT_IMPLEMENTED;
560 }
561 NS_IMETHODIMP
562 WyciwygChannelChild::SetContentLength(int64_t aContentLength)
563 {
564 return NS_ERROR_NOT_IMPLEMENTED;
565 }
566
567 /* nsIInputStream open (); */
568 NS_IMETHODIMP
569 WyciwygChannelChild::Open(nsIInputStream **_retval)
570 {
571 return NS_ERROR_NOT_IMPLEMENTED;
572 }
573
574 static mozilla::dom::TabChild*
575 GetTabChild(nsIChannel* aChannel)
576 {
577 nsCOMPtr<nsITabChild> iTabChild;
578 NS_QueryNotificationCallbacks(aChannel, iTabChild);
579 return iTabChild ? static_cast<mozilla::dom::TabChild*>(iTabChild.get()) : nullptr;
580 }
581
582 /* void asyncOpen (in nsIStreamListener aListener, in nsISupports aContext); */
583 NS_IMETHODIMP
584 WyciwygChannelChild::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
585 {
586 LOG(("WyciwygChannelChild::AsyncOpen [this=%p]\n", this));
587
588 // The only places creating wyciwyg: channels should be
589 // HTMLDocument::OpenCommon and session history. Both should be setting an
590 // owner.
591 NS_PRECONDITION(mOwner, "Must have a principal");
592 NS_ENSURE_STATE(mOwner);
593
594 NS_ENSURE_ARG_POINTER(aListener);
595 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
596
597 mListener = aListener;
598 mListenerContext = aContext;
599 mIsPending = true;
600
601 if (mLoadGroup)
602 mLoadGroup->AddRequest(this, nullptr);
603
604 URIParams originalURI;
605 SerializeURI(mOriginalURI, originalURI);
606
607 mozilla::dom::TabChild* tabChild = GetTabChild(this);
608 if (MissingRequiredTabChild(tabChild, "wyciwyg")) {
609 return NS_ERROR_ILLEGAL_VALUE;
610 }
611
612 SendAsyncOpen(originalURI, mLoadFlags, IPC::SerializedLoadContext(this), tabChild);
613
614 mSentAppData = true;
615 mState = WCC_OPENED;
616
617 return NS_OK;
618 }
619
620 //-----------------------------------------------------------------------------
621 // nsIWyciwygChannel
622 //-----------------------------------------------------------------------------
623
624 /* void writeToCacheEntry (in AString aData); */
625 NS_IMETHODIMP
626 WyciwygChannelChild::WriteToCacheEntry(const nsAString & aData)
627 {
628 NS_ENSURE_TRUE((mState == WCC_INIT) ||
629 (mState == WCC_ONWRITE), NS_ERROR_UNEXPECTED);
630
631 if (!mSentAppData) {
632 mozilla::dom::TabChild* tabChild = GetTabChild(this);
633 SendAppData(IPC::SerializedLoadContext(this), tabChild);
634 mSentAppData = true;
635 }
636
637 SendWriteToCacheEntry(PromiseFlatString(aData));
638 mState = WCC_ONWRITE;
639 return NS_OK;
640 }
641
642 /* void closeCacheEntry (in nsresult reason); */
643 NS_IMETHODIMP
644 WyciwygChannelChild::CloseCacheEntry(nsresult reason)
645 {
646 NS_ENSURE_TRUE(mState == WCC_ONWRITE, NS_ERROR_UNEXPECTED);
647
648 SendCloseCacheEntry(reason);
649 mState = WCC_ONCLOSED;
650
651 if (mIPCOpen)
652 PWyciwygChannelChild::Send__delete__(this);
653
654 return NS_OK;
655 }
656
657 /* void setSecurityInfo (in nsISupports aSecurityInfo); */
658 NS_IMETHODIMP
659 WyciwygChannelChild::SetSecurityInfo(nsISupports *aSecurityInfo)
660 {
661 mSecurityInfo = aSecurityInfo;
662
663 if (mSecurityInfo) {
664 nsCOMPtr<nsISerializable> serializable = do_QueryInterface(mSecurityInfo);
665 if (serializable) {
666 nsCString secInfoStr;
667 NS_SerializeToString(serializable, secInfoStr);
668 SendSetSecurityInfo(secInfoStr);
669 }
670 else {
671 NS_WARNING("Can't serialize security info");
672 }
673 }
674
675 return NS_OK;
676 }
677
678 /* void setCharsetAndSource (in long aSource, in ACString aCharset); */
679 NS_IMETHODIMP
680 WyciwygChannelChild::SetCharsetAndSource(int32_t aSource, const nsACString & aCharset)
681 {
682 // mState == WCC_ONSTART when reading from the channel
683 // mState == WCC_INIT when writing to the cache
684 NS_ENSURE_TRUE((mState == WCC_ONSTART) ||
685 (mState == WCC_INIT), NS_ERROR_UNEXPECTED);
686
687 mCharsetSource = aSource;
688 mCharset = aCharset;
689
690 // TODO ensure that nsWyciwygChannel in the parent has still the cache entry
691 SendSetCharsetAndSource(mCharsetSource, mCharset);
692 return NS_OK;
693 }
694
695 /* ACString getCharsetAndSource (out long aSource); */
696 NS_IMETHODIMP
697 WyciwygChannelChild::GetCharsetAndSource(int32_t *aSource, nsACString & _retval)
698 {
699 NS_ENSURE_TRUE((mState == WCC_ONSTART) ||
700 (mState == WCC_ONDATA) ||
701 (mState == WCC_ONSTOP), NS_ERROR_NOT_AVAILABLE);
702
703 if (mCharsetSource == kCharsetUninitialized)
704 return NS_ERROR_NOT_AVAILABLE;
705
706 *aSource = mCharsetSource;
707 _retval = mCharset;
708 return NS_OK;
709 }
710
711 //------------------------------------------------------------------------------
712 }} // mozilla::net

mercurial