1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Radha Kulkarni(radha@netscape.com)
25 : * Michal Novotny <michal.novotny@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "nsWyciwyg.h"
42 : #include "nsWyciwygChannel.h"
43 : #include "nsIServiceManager.h"
44 : #include "nsILoadGroup.h"
45 : #include "nsIScriptSecurityManager.h"
46 : #include "nsNetUtil.h"
47 : #include "nsContentUtils.h"
48 : #include "nsICacheService.h"
49 : #include "nsICacheSession.h"
50 : #include "nsIParser.h"
51 : #include "nsThreadUtils.h"
52 : #include "nsProxyRelease.h"
53 :
54 : // Must release mChannel on the main thread
55 : class nsWyciwygAsyncEvent : public nsRunnable {
56 : public:
57 0 : nsWyciwygAsyncEvent(nsWyciwygChannel *aChannel) : mChannel(aChannel) {}
58 :
59 0 : ~nsWyciwygAsyncEvent()
60 0 : {
61 0 : nsCOMPtr<nsIThread> thread = do_GetMainThread();
62 0 : NS_WARN_IF_FALSE(thread, "Couldn't get the main thread!");
63 0 : if (thread) {
64 0 : nsIWyciwygChannel *chan = static_cast<nsIWyciwygChannel *>(mChannel);
65 0 : mChannel.forget();
66 0 : NS_ProxyRelease(thread, chan);
67 : }
68 0 : }
69 : protected:
70 : nsRefPtr<nsWyciwygChannel> mChannel;
71 : };
72 :
73 0 : class nsWyciwygSetCharsetandSourceEvent : public nsWyciwygAsyncEvent {
74 : public:
75 0 : nsWyciwygSetCharsetandSourceEvent(nsWyciwygChannel *aChannel)
76 0 : : nsWyciwygAsyncEvent(aChannel) {}
77 :
78 0 : NS_IMETHOD Run()
79 : {
80 0 : mChannel->SetCharsetAndSourceInternal();
81 0 : return NS_OK;
82 : }
83 : };
84 :
85 0 : class nsWyciwygWriteEvent : public nsWyciwygAsyncEvent {
86 : public:
87 0 : nsWyciwygWriteEvent(nsWyciwygChannel *aChannel, const nsAString &aData,
88 : const nsACString &spec)
89 0 : : nsWyciwygAsyncEvent(aChannel), mData(aData), mSpec(spec) {}
90 :
91 0 : NS_IMETHOD Run()
92 : {
93 0 : mChannel->WriteToCacheEntryInternal(mData, mSpec);
94 0 : return NS_OK;
95 : }
96 : private:
97 : nsString mData;
98 : nsCString mSpec;
99 : };
100 :
101 0 : class nsWyciwygCloseEvent : public nsWyciwygAsyncEvent {
102 : public:
103 0 : nsWyciwygCloseEvent(nsWyciwygChannel *aChannel, nsresult aReason)
104 0 : : nsWyciwygAsyncEvent(aChannel), mReason(aReason) {}
105 :
106 0 : NS_IMETHOD Run()
107 : {
108 0 : mChannel->CloseCacheEntryInternal(mReason);
109 0 : return NS_OK;
110 : }
111 : private:
112 : nsresult mReason;
113 : };
114 :
115 :
116 : // nsWyciwygChannel methods
117 0 : nsWyciwygChannel::nsWyciwygChannel()
118 : : mStatus(NS_OK),
119 : mIsPending(false),
120 : mCharsetAndSourceSet(false),
121 : mNeedToWriteCharset(false),
122 : mCharsetSource(kCharsetUninitialized),
123 : mContentLength(-1),
124 0 : mLoadFlags(LOAD_NORMAL)
125 : {
126 0 : }
127 :
128 0 : nsWyciwygChannel::~nsWyciwygChannel()
129 : {
130 0 : }
131 :
132 0 : NS_IMPL_THREADSAFE_ISUPPORTS6(nsWyciwygChannel,
133 : nsIChannel,
134 : nsIRequest,
135 : nsIStreamListener,
136 : nsIRequestObserver,
137 : nsICacheListener,
138 : nsIWyciwygChannel)
139 :
140 : nsresult
141 0 : nsWyciwygChannel::Init(nsIURI* uri)
142 : {
143 0 : NS_ENSURE_ARG_POINTER(uri);
144 :
145 : nsresult rv;
146 :
147 0 : mURI = uri;
148 0 : mOriginalURI = uri;
149 :
150 : nsCOMPtr<nsICacheService> serv =
151 0 : do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
152 0 : NS_ENSURE_SUCCESS(rv, rv);
153 :
154 0 : rv = serv->GetCacheIOTarget(getter_AddRefs(mCacheIOTarget));
155 0 : NS_ENSURE_SUCCESS(rv, rv);
156 :
157 0 : return NS_OK;
158 : }
159 :
160 : ///////////////////////////////////////////////////////////////////////////////
161 : // nsIRequest methods:
162 : ///////////////////////////////////////////////////////////////////////////////
163 :
164 : NS_IMETHODIMP
165 0 : nsWyciwygChannel::GetName(nsACString &aName)
166 : {
167 0 : return mURI->GetSpec(aName);
168 : }
169 :
170 : NS_IMETHODIMP
171 0 : nsWyciwygChannel::IsPending(bool *aIsPending)
172 : {
173 0 : *aIsPending = mIsPending;
174 0 : return NS_OK;
175 : }
176 :
177 : NS_IMETHODIMP
178 0 : nsWyciwygChannel::GetStatus(nsresult *aStatus)
179 : {
180 0 : if (NS_SUCCEEDED(mStatus) && mPump)
181 0 : mPump->GetStatus(aStatus);
182 : else
183 0 : *aStatus = mStatus;
184 0 : return NS_OK;
185 : }
186 :
187 : NS_IMETHODIMP
188 0 : nsWyciwygChannel::Cancel(nsresult status)
189 : {
190 0 : mStatus = status;
191 0 : if (mPump)
192 0 : mPump->Cancel(status);
193 : // else we're waiting for OnCacheEntryAvailable
194 0 : return NS_OK;
195 : }
196 :
197 : NS_IMETHODIMP
198 0 : nsWyciwygChannel::Suspend()
199 : {
200 0 : if (mPump)
201 0 : mPump->Suspend();
202 : // XXX else, we'll ignore this ... and that's probably bad!
203 0 : return NS_OK;
204 : }
205 :
206 : NS_IMETHODIMP
207 0 : nsWyciwygChannel::Resume()
208 : {
209 0 : if (mPump)
210 0 : mPump->Resume();
211 : // XXX else, we'll ignore this ... and that's probably bad!
212 0 : return NS_OK;
213 : }
214 :
215 : NS_IMETHODIMP
216 0 : nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
217 : {
218 0 : *aLoadGroup = mLoadGroup;
219 0 : NS_IF_ADDREF(*aLoadGroup);
220 0 : return NS_OK;
221 : }
222 :
223 : NS_IMETHODIMP
224 0 : nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
225 : {
226 0 : mLoadGroup = aLoadGroup;
227 : NS_QueryNotificationCallbacks(mCallbacks,
228 : mLoadGroup,
229 : NS_GET_IID(nsIProgressEventSink),
230 0 : getter_AddRefs(mProgressSink));
231 0 : return NS_OK;
232 : }
233 :
234 : NS_IMETHODIMP
235 0 : nsWyciwygChannel::SetLoadFlags(PRUint32 aLoadFlags)
236 : {
237 0 : mLoadFlags = aLoadFlags;
238 0 : return NS_OK;
239 : }
240 :
241 : NS_IMETHODIMP
242 0 : nsWyciwygChannel::GetLoadFlags(PRUint32 * aLoadFlags)
243 : {
244 0 : *aLoadFlags = mLoadFlags;
245 0 : return NS_OK;
246 : }
247 :
248 : ////////////////////////////////////////////////////////////////////////////////
249 : // nsIChannel methods:
250 : ///////////////////////////////////////////////////////////////////////////////
251 :
252 : NS_IMETHODIMP
253 0 : nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI)
254 : {
255 0 : *aURI = mOriginalURI;
256 0 : NS_ADDREF(*aURI);
257 0 : return NS_OK;
258 : }
259 :
260 : NS_IMETHODIMP
261 0 : nsWyciwygChannel::SetOriginalURI(nsIURI* aURI)
262 : {
263 0 : NS_ENSURE_ARG_POINTER(aURI);
264 0 : mOriginalURI = aURI;
265 0 : return NS_OK;
266 : }
267 :
268 : NS_IMETHODIMP
269 0 : nsWyciwygChannel::GetURI(nsIURI* *aURI)
270 : {
271 0 : *aURI = mURI;
272 0 : NS_IF_ADDREF(*aURI);
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : nsWyciwygChannel::GetOwner(nsISupports **aOwner)
278 : {
279 0 : NS_PRECONDITION(mOwner, "Must have a principal!");
280 0 : NS_ENSURE_STATE(mOwner);
281 :
282 0 : NS_ADDREF(*aOwner = mOwner);
283 0 : return NS_OK;
284 : }
285 :
286 : NS_IMETHODIMP
287 0 : nsWyciwygChannel::SetOwner(nsISupports* aOwner)
288 : {
289 0 : mOwner = aOwner;
290 0 : return NS_OK;
291 : }
292 :
293 : NS_IMETHODIMP
294 0 : nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
295 : {
296 0 : *aCallbacks = mCallbacks.get();
297 0 : NS_IF_ADDREF(*aCallbacks);
298 0 : return NS_OK;
299 : }
300 :
301 : NS_IMETHODIMP
302 0 : nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
303 : {
304 0 : mCallbacks = aNotificationCallbacks;
305 : NS_QueryNotificationCallbacks(mCallbacks,
306 : mLoadGroup,
307 : NS_GET_IID(nsIProgressEventSink),
308 0 : getter_AddRefs(mProgressSink));
309 0 : return NS_OK;
310 : }
311 :
312 : NS_IMETHODIMP
313 0 : nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
314 : {
315 0 : NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
316 :
317 0 : return NS_OK;
318 : }
319 :
320 : NS_IMETHODIMP
321 0 : nsWyciwygChannel::GetContentType(nsACString &aContentType)
322 : {
323 0 : aContentType.AssignLiteral(WYCIWYG_TYPE);
324 0 : return NS_OK;
325 : }
326 :
327 : NS_IMETHODIMP
328 0 : nsWyciwygChannel::SetContentType(const nsACString &aContentType)
329 : {
330 0 : return NS_ERROR_NOT_IMPLEMENTED;
331 : }
332 :
333 : NS_IMETHODIMP
334 0 : nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset)
335 : {
336 0 : aContentCharset.Assign("UTF-16");
337 0 : return NS_OK;
338 : }
339 :
340 : NS_IMETHODIMP
341 0 : nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
342 : {
343 0 : return NS_ERROR_NOT_IMPLEMENTED;
344 : }
345 :
346 : NS_IMETHODIMP
347 0 : nsWyciwygChannel::GetContentDisposition(PRUint32 *aContentDisposition)
348 : {
349 0 : return NS_ERROR_NOT_AVAILABLE;
350 : }
351 :
352 : NS_IMETHODIMP
353 0 : nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
354 : {
355 0 : return NS_ERROR_NOT_AVAILABLE;
356 : }
357 :
358 : NS_IMETHODIMP
359 0 : nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
360 : {
361 0 : return NS_ERROR_NOT_AVAILABLE;
362 : }
363 :
364 : NS_IMETHODIMP
365 0 : nsWyciwygChannel::GetContentLength(PRInt32 *aContentLength)
366 : {
367 0 : *aContentLength = mContentLength;
368 0 : return NS_OK;
369 : }
370 :
371 : NS_IMETHODIMP
372 0 : nsWyciwygChannel::SetContentLength(PRInt32 aContentLength)
373 : {
374 0 : mContentLength = aContentLength;
375 :
376 0 : return NS_OK;
377 : }
378 :
379 : NS_IMETHODIMP
380 0 : nsWyciwygChannel::Open(nsIInputStream ** aReturn)
381 : {
382 0 : return NS_ERROR_NOT_IMPLEMENTED;
383 : }
384 :
385 : NS_IMETHODIMP
386 0 : nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
387 : {
388 0 : LOG(("nsWyciwygChannel::AsyncOpen [this=%x]\n", this));
389 :
390 0 : NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
391 0 : NS_ENSURE_ARG_POINTER(listener);
392 :
393 0 : nsCAutoString spec;
394 0 : mURI->GetSpec(spec);
395 :
396 : // open a cache entry for this channel...
397 0 : nsresult rv = OpenCacheEntry(spec, nsICache::ACCESS_READ);
398 0 : if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) {
399 : // Overwrite rv on purpose; if event dispatch fails we'll bail, and
400 : // otherwise we'll wait until the event fires before calling back.
401 : rv = NS_DispatchToCurrentThread(
402 0 : NS_NewRunnableMethod(this, &nsWyciwygChannel::NotifyListener));
403 : }
404 :
405 0 : if (NS_FAILED(rv)) {
406 0 : LOG(("nsWyciwygChannel::OpenCacheEntry failed [rv=%x]\n", rv));
407 0 : return rv;
408 : }
409 :
410 0 : mIsPending = true;
411 0 : mListener = listener;
412 0 : mListenerContext = ctx;
413 :
414 0 : if (mLoadGroup)
415 0 : mLoadGroup->AddRequest(this, nsnull);
416 :
417 0 : return NS_OK;
418 : }
419 :
420 : //////////////////////////////////////////////////////////////////////////////
421 : // nsIWyciwygChannel
422 : //////////////////////////////////////////////////////////////////////////////
423 :
424 : NS_IMETHODIMP
425 0 : nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
426 : {
427 : // URIs not thread-safe, so get spec now in case we need it
428 0 : nsCAutoString spec;
429 0 : nsresult rv = mURI->GetAsciiSpec(spec);
430 0 : if (NS_FAILED(rv))
431 0 : return rv;
432 :
433 0 : return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData, spec),
434 0 : NS_DISPATCH_NORMAL);
435 : }
436 :
437 : nsresult
438 0 : nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData, const nsACString& spec)
439 : {
440 0 : NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
441 :
442 : nsresult rv;
443 :
444 0 : if (!mCacheEntry) {
445 0 : rv = OpenCacheEntry(spec, nsICache::ACCESS_WRITE);
446 0 : if (NS_FAILED(rv)) return rv;
447 : }
448 :
449 0 : if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
450 0 : rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
451 0 : if (NS_FAILED(rv)) return rv;
452 : }
453 :
454 0 : if (mSecurityInfo) {
455 0 : mCacheEntry->SetSecurityInfo(mSecurityInfo);
456 : }
457 :
458 0 : if (mNeedToWriteCharset) {
459 0 : WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
460 0 : mNeedToWriteCharset = false;
461 : }
462 :
463 : PRUint32 out;
464 0 : if (!mCacheOutputStream) {
465 : // Get the outputstream from the cache entry.
466 0 : rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream));
467 0 : if (NS_FAILED(rv)) return rv;
468 :
469 : // Write out a Byte Order Mark, so that we'll know if the data is
470 : // BE or LE when we go to read it.
471 0 : PRUnichar bom = 0xFEFF;
472 0 : rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out);
473 0 : if (NS_FAILED(rv)) return rv;
474 : }
475 :
476 0 : return mCacheOutputStream->Write((char *)PromiseFlatString(aData).get(),
477 0 : aData.Length() * sizeof(PRUnichar), &out);
478 : }
479 :
480 :
481 : NS_IMETHODIMP
482 0 : nsWyciwygChannel::CloseCacheEntry(nsresult reason)
483 : {
484 0 : return mCacheIOTarget->Dispatch(new nsWyciwygCloseEvent(this, reason),
485 0 : NS_DISPATCH_NORMAL);
486 : }
487 :
488 : nsresult
489 0 : nsWyciwygChannel::CloseCacheEntryInternal(nsresult reason)
490 : {
491 0 : NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
492 :
493 0 : if (mCacheEntry) {
494 0 : LOG(("nsWyciwygChannel::CloseCacheEntryInternal [this=%x ]", this));
495 0 : mCacheOutputStream = 0;
496 0 : mCacheInputStream = 0;
497 :
498 0 : if (NS_FAILED(reason))
499 0 : mCacheEntry->Doom();
500 :
501 0 : mCacheEntry = 0;
502 : }
503 0 : return NS_OK;
504 : }
505 :
506 : NS_IMETHODIMP
507 0 : nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo)
508 : {
509 0 : mSecurityInfo = aSecurityInfo;
510 :
511 0 : return NS_OK;
512 : }
513 :
514 : NS_IMETHODIMP
515 0 : nsWyciwygChannel::SetCharsetAndSource(PRInt32 aSource,
516 : const nsACString& aCharset)
517 : {
518 0 : NS_ENSURE_ARG(!aCharset.IsEmpty());
519 :
520 0 : mCharsetAndSourceSet = true;
521 0 : mCharset = aCharset;
522 0 : mCharsetSource = aSource;
523 :
524 0 : return mCacheIOTarget->Dispatch(new nsWyciwygSetCharsetandSourceEvent(this),
525 0 : NS_DISPATCH_NORMAL);
526 : }
527 :
528 : void
529 0 : nsWyciwygChannel::SetCharsetAndSourceInternal()
530 : {
531 0 : NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
532 :
533 0 : if (mCacheEntry) {
534 0 : WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
535 : } else {
536 0 : mNeedToWriteCharset = true;
537 : }
538 0 : }
539 :
540 : NS_IMETHODIMP
541 0 : nsWyciwygChannel::GetCharsetAndSource(PRInt32* aSource, nsACString& aCharset)
542 : {
543 0 : if (mCharsetAndSourceSet) {
544 0 : *aSource = mCharsetSource;
545 0 : aCharset = mCharset;
546 0 : return NS_OK;
547 : }
548 :
549 0 : if (!mCacheEntry) {
550 0 : return NS_ERROR_NOT_AVAILABLE;
551 : }
552 :
553 0 : nsXPIDLCString data;
554 0 : mCacheEntry->GetMetaDataElement("charset", getter_Copies(data));
555 :
556 0 : if (data.IsEmpty()) {
557 0 : return NS_ERROR_NOT_AVAILABLE;
558 : }
559 :
560 0 : nsXPIDLCString sourceStr;
561 0 : mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr));
562 :
563 : PRInt32 source;
564 : // XXXbz ToInteger takes an PRInt32* but outputs an nsresult in it... :(
565 : PRInt32 err;
566 0 : source = sourceStr.ToInteger(&err);
567 0 : if (NS_FAILED(err) || source == 0) {
568 0 : return NS_ERROR_NOT_AVAILABLE;
569 : }
570 :
571 0 : *aSource = source;
572 0 : aCharset = data;
573 0 : return NS_OK;
574 : }
575 :
576 : //////////////////////////////////////////////////////////////////////////////
577 : // nsICachelistener
578 : //////////////////////////////////////////////////////////////////////////////
579 : NS_IMETHODIMP
580 0 : nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor * aCacheEntry, nsCacheAccessMode aMode, nsresult aStatus)
581 : {
582 0 : LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%x entry=%x "
583 : "access=%x status=%x]\n", this, aCacheEntry, aMode, aStatus));
584 :
585 : // if the channel's already fired onStopRequest,
586 : // then we should ignore this event.
587 0 : if (!mIsPending)
588 0 : return NS_OK;
589 :
590 : // otherwise, we have to handle this event.
591 0 : if (NS_SUCCEEDED(aStatus))
592 0 : mCacheEntry = aCacheEntry;
593 0 : else if (NS_SUCCEEDED(mStatus))
594 0 : mStatus = aStatus;
595 :
596 : nsresult rv;
597 0 : if (NS_FAILED(mStatus)) {
598 0 : LOG(("channel was canceled [this=%x status=%x]\n", this, mStatus));
599 0 : rv = mStatus;
600 : }
601 : else { // advance to the next state...
602 0 : rv = ReadFromCache();
603 : }
604 :
605 : // a failure from Connect means that we have to abort the channel.
606 0 : if (NS_FAILED(rv)) {
607 0 : CloseCacheEntry(rv);
608 :
609 0 : NotifyListener();
610 : }
611 :
612 0 : return NS_OK;
613 : }
614 :
615 : //-----------------------------------------------------------------------------
616 : // nsWyciwygChannel::nsIStreamListener
617 : //-----------------------------------------------------------------------------
618 :
619 : NS_IMETHODIMP
620 0 : nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
621 : nsIInputStream *input,
622 : PRUint32 offset, PRUint32 count)
623 : {
624 0 : LOG(("nsWyciwygChannel::OnDataAvailable [this=%x request=%x offset=%u count=%u]\n",
625 : this, request, offset, count));
626 :
627 : nsresult rv;
628 :
629 0 : rv = mListener->OnDataAvailable(this, mListenerContext, input, offset, count);
630 :
631 : // XXX handle 64-bit stuff for real
632 0 : if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
633 0 : mProgressSink->OnProgress(this, nsnull, PRUint64(offset + count),
634 0 : PRUint64(mContentLength));
635 :
636 0 : return rv; // let the pump cancel on failure
637 : }
638 :
639 : //////////////////////////////////////////////////////////////////////////////
640 : // nsIRequestObserver
641 : //////////////////////////////////////////////////////////////////////////////
642 :
643 : NS_IMETHODIMP
644 0 : nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
645 : {
646 0 : LOG(("nsWyciwygChannel::OnStartRequest [this=%x request=%x\n",
647 : this, request));
648 :
649 0 : return mListener->OnStartRequest(this, mListenerContext);
650 : }
651 :
652 :
653 : NS_IMETHODIMP
654 0 : nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status)
655 : {
656 0 : LOG(("nsWyciwygChannel::OnStopRequest [this=%x request=%x status=%d\n",
657 : this, request, status));
658 :
659 0 : if (NS_SUCCEEDED(mStatus))
660 0 : mStatus = status;
661 :
662 0 : mListener->OnStopRequest(this, mListenerContext, mStatus);
663 0 : mListener = 0;
664 0 : mListenerContext = 0;
665 :
666 0 : if (mLoadGroup)
667 0 : mLoadGroup->RemoveRequest(this, nsnull, mStatus);
668 :
669 0 : CloseCacheEntry(mStatus);
670 0 : mPump = 0;
671 0 : mIsPending = false;
672 :
673 : // Drop notification callbacks to prevent cycles.
674 0 : mCallbacks = 0;
675 0 : mProgressSink = 0;
676 :
677 0 : return NS_OK;
678 : }
679 :
680 : //////////////////////////////////////////////////////////////////////////////
681 : // Helper functions
682 : //////////////////////////////////////////////////////////////////////////////
683 :
684 : nsresult
685 0 : nsWyciwygChannel::OpenCacheEntry(const nsACString & aCacheKey,
686 : nsCacheAccessMode aAccessMode)
687 : {
688 0 : nsresult rv = NS_ERROR_FAILURE;
689 : // Get cache service
690 : nsCOMPtr<nsICacheService> cacheService =
691 0 : do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
692 0 : NS_ENSURE_SUCCESS(rv, rv);
693 :
694 : // honor security settings
695 : nsCacheStoragePolicy storagePolicy;
696 0 : if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
697 0 : storagePolicy = nsICache::STORE_IN_MEMORY;
698 : else
699 0 : storagePolicy = nsICache::STORE_ANYWHERE;
700 :
701 0 : nsCOMPtr<nsICacheSession> cacheSession;
702 : // Open a stream based cache session.
703 0 : rv = cacheService->CreateSession("wyciwyg", storagePolicy, true,
704 0 : getter_AddRefs(cacheSession));
705 0 : if (!cacheSession)
706 0 : return NS_ERROR_FAILURE;
707 :
708 0 : if (aAccessMode == nsICache::ACCESS_WRITE)
709 0 : rv = cacheSession->OpenCacheEntry(aCacheKey, aAccessMode, false,
710 0 : getter_AddRefs(mCacheEntry));
711 : else
712 0 : rv = cacheSession->AsyncOpenCacheEntry(aCacheKey, aAccessMode, this);
713 :
714 0 : return rv;
715 : }
716 :
717 : nsresult
718 0 : nsWyciwygChannel::ReadFromCache()
719 : {
720 0 : LOG(("nsWyciwygChannel::ReadFromCache [this=%x] ", this));
721 :
722 0 : NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
723 : nsresult rv;
724 :
725 : // Get the stored security info
726 0 : mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
727 :
728 0 : nsCAutoString tmpStr;
729 0 : rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
730 0 : getter_Copies(tmpStr));
731 0 : if (NS_SUCCEEDED(rv) && tmpStr == NS_LITERAL_CSTRING("1"))
732 0 : mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
733 :
734 : // Get a transport to the cached data...
735 0 : rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream));
736 0 : if (NS_FAILED(rv))
737 0 : return rv;
738 0 : NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED);
739 :
740 0 : rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream);
741 0 : if (NS_FAILED(rv)) return rv;
742 :
743 : // Pump the cache data downstream
744 0 : return mPump->AsyncRead(this, nsnull);
745 : }
746 :
747 : void
748 0 : nsWyciwygChannel::WriteCharsetAndSourceToCache(PRInt32 aSource,
749 : const nsCString& aCharset)
750 : {
751 0 : NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
752 0 : NS_PRECONDITION(mCacheEntry, "Better have cache entry!");
753 :
754 0 : mCacheEntry->SetMetaDataElement("charset", aCharset.get());
755 :
756 0 : nsCAutoString source;
757 0 : source.AppendInt(aSource);
758 0 : mCacheEntry->SetMetaDataElement("charset-source", source.get());
759 0 : }
760 :
761 : void
762 0 : nsWyciwygChannel::NotifyListener()
763 : {
764 0 : if (mListener) {
765 0 : mListener->OnStartRequest(this, mListenerContext);
766 0 : mListener->OnStopRequest(this, mListenerContext, mStatus);
767 0 : mListener = 0;
768 0 : mListenerContext = 0;
769 : }
770 :
771 0 : mIsPending = false;
772 :
773 : // Remove ourselves from the load group.
774 0 : if (mLoadGroup) {
775 0 : mLoadGroup->RemoveRequest(this, nsnull, mStatus);
776 : }
777 0 : }
778 :
779 : bool
780 0 : nsWyciwygChannel::IsOnCacheIOThread()
781 : {
782 : bool correctThread;
783 0 : mCacheIOTarget->IsOnCurrentThread(&correctThread);
784 0 : return correctThread;
785 : }
786 :
787 : // vim: ts=2 sw=2
|