Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
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 : #include "nsWyciwyg.h"
8 : #include "nsWyciwygChannel.h"
9 : #include "nsILoadGroup.h"
10 : #include "nsNetUtil.h"
11 : #include "nsNetCID.h"
12 : #include "LoadContextInfo.h"
13 : #include "nsICacheService.h" // only to initialize
14 : #include "nsICacheStorageService.h"
15 : #include "nsICacheStorage.h"
16 : #include "nsICacheEntry.h"
17 : #include "nsCharsetSource.h"
18 : #include "nsProxyRelease.h"
19 : #include "nsThreadUtils.h"
20 : #include "nsIInputStream.h"
21 : #include "nsIInputStreamPump.h"
22 : #include "nsIOutputStream.h"
23 : #include "nsIProgressEventSink.h"
24 : #include "nsIURI.h"
25 : #include "mozilla/DebugOnly.h"
26 : #include "mozilla/Unused.h"
27 : #include "mozilla/BasePrincipal.h"
28 : #include "nsProxyRelease.h"
29 : #include "nsContentSecurityManager.h"
30 : #include "nsContentUtils.h"
31 :
32 : typedef mozilla::net::LoadContextInfo LoadContextInfo;
33 :
34 : // nsWyciwygChannel methods
35 0 : nsWyciwygChannel::nsWyciwygChannel()
36 : : mMode(NONE),
37 : mStatus(NS_OK),
38 : mIsPending(false),
39 : mNeedToWriteCharset(false),
40 : mCharsetSource(kCharsetUninitialized),
41 : mContentLength(-1),
42 : mLoadFlags(LOAD_NORMAL),
43 0 : mNeedToSetSecurityInfo(false)
44 : {
45 0 : }
46 :
47 0 : nsWyciwygChannel::~nsWyciwygChannel()
48 : {
49 0 : if (mLoadInfo) {
50 : NS_ReleaseOnMainThread(
51 0 : "nsWyciwygChannel::mLoadInfo", mLoadInfo.forget(), false);
52 : }
53 0 : }
54 :
55 0 : NS_IMPL_ISUPPORTS(nsWyciwygChannel,
56 : nsIChannel,
57 : nsIRequest,
58 : nsIStreamListener,
59 : nsIRequestObserver,
60 : nsICacheEntryOpenCallback,
61 : nsIWyciwygChannel,
62 : nsIPrivateBrowsingChannel)
63 :
64 : nsresult
65 0 : nsWyciwygChannel::Init(nsIURI* uri)
66 : {
67 0 : NS_ENSURE_ARG_POINTER(uri);
68 :
69 0 : mURI = uri;
70 0 : mOriginalURI = uri;
71 :
72 0 : return NS_OK;
73 : }
74 :
75 : ///////////////////////////////////////////////////////////////////////////////
76 : // nsIRequest methods:
77 : ///////////////////////////////////////////////////////////////////////////////
78 :
79 : NS_IMETHODIMP
80 0 : nsWyciwygChannel::GetName(nsACString &aName)
81 : {
82 0 : return mURI->GetSpec(aName);
83 : }
84 :
85 : NS_IMETHODIMP
86 0 : nsWyciwygChannel::IsPending(bool *aIsPending)
87 : {
88 0 : *aIsPending = mIsPending;
89 0 : return NS_OK;
90 : }
91 :
92 : NS_IMETHODIMP
93 0 : nsWyciwygChannel::GetStatus(nsresult *aStatus)
94 : {
95 0 : if (NS_SUCCEEDED(mStatus) && mPump)
96 0 : mPump->GetStatus(aStatus);
97 : else
98 0 : *aStatus = mStatus;
99 0 : return NS_OK;
100 : }
101 :
102 : NS_IMETHODIMP
103 0 : nsWyciwygChannel::Cancel(nsresult status)
104 : {
105 0 : mStatus = status;
106 0 : if (mPump)
107 0 : mPump->Cancel(status);
108 : // else we're waiting for OnCacheEntryAvailable
109 0 : return NS_OK;
110 : }
111 :
112 : NS_IMETHODIMP
113 0 : nsWyciwygChannel::Suspend()
114 : {
115 0 : if (mPump)
116 0 : mPump->Suspend();
117 : // XXX else, we'll ignore this ... and that's probably bad!
118 0 : return NS_OK;
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : nsWyciwygChannel::Resume()
123 : {
124 0 : if (mPump)
125 0 : mPump->Resume();
126 : // XXX else, we'll ignore this ... and that's probably bad!
127 0 : return NS_OK;
128 : }
129 :
130 : NS_IMETHODIMP
131 0 : nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
132 : {
133 0 : *aLoadGroup = mLoadGroup;
134 0 : NS_IF_ADDREF(*aLoadGroup);
135 0 : return NS_OK;
136 : }
137 :
138 : NS_IMETHODIMP
139 0 : nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
140 : {
141 0 : if (!CanSetLoadGroup(aLoadGroup)) {
142 0 : return NS_ERROR_FAILURE;
143 : }
144 :
145 0 : mLoadGroup = aLoadGroup;
146 0 : NS_QueryNotificationCallbacks(mCallbacks,
147 : mLoadGroup,
148 : NS_GET_IID(nsIProgressEventSink),
149 0 : getter_AddRefs(mProgressSink));
150 0 : UpdatePrivateBrowsing();
151 0 : NS_GetOriginAttributes(this, mOriginAttributes);
152 :
153 0 : return NS_OK;
154 : }
155 :
156 : NS_IMETHODIMP
157 0 : nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
158 : {
159 0 : mLoadFlags = aLoadFlags;
160 0 : return NS_OK;
161 : }
162 :
163 : NS_IMETHODIMP
164 0 : nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags)
165 : {
166 0 : *aLoadFlags = mLoadFlags;
167 0 : return NS_OK;
168 : }
169 :
170 : NS_IMETHODIMP
171 0 : nsWyciwygChannel::GetIsDocument(bool *aIsDocument)
172 : {
173 0 : return NS_GetIsDocumentChannel(this, aIsDocument);
174 : }
175 :
176 : ////////////////////////////////////////////////////////////////////////////////
177 : // nsIChannel methods:
178 : ///////////////////////////////////////////////////////////////////////////////
179 :
180 : NS_IMETHODIMP
181 0 : nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI)
182 : {
183 0 : *aURI = mOriginalURI;
184 0 : NS_ADDREF(*aURI);
185 0 : return NS_OK;
186 : }
187 :
188 : NS_IMETHODIMP
189 0 : nsWyciwygChannel::SetOriginalURI(nsIURI* aURI)
190 : {
191 0 : NS_ENSURE_ARG_POINTER(aURI);
192 0 : mOriginalURI = aURI;
193 0 : return NS_OK;
194 : }
195 :
196 : NS_IMETHODIMP
197 0 : nsWyciwygChannel::GetURI(nsIURI* *aURI)
198 : {
199 0 : *aURI = mURI;
200 0 : NS_IF_ADDREF(*aURI);
201 0 : return NS_OK;
202 : }
203 :
204 : NS_IMETHODIMP
205 0 : nsWyciwygChannel::GetOwner(nsISupports **aOwner)
206 : {
207 0 : NS_IF_ADDREF(*aOwner = mOwner);
208 0 : return NS_OK;
209 : }
210 :
211 : NS_IMETHODIMP
212 0 : nsWyciwygChannel::SetOwner(nsISupports* aOwner)
213 : {
214 0 : mOwner = aOwner;
215 0 : return NS_OK;
216 : }
217 :
218 : NS_IMETHODIMP
219 0 : nsWyciwygChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
220 : {
221 0 : NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
222 0 : return NS_OK;
223 : }
224 :
225 : NS_IMETHODIMP
226 0 : nsWyciwygChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
227 : {
228 0 : mLoadInfo = aLoadInfo;
229 0 : return NS_OK;
230 : }
231 :
232 : NS_IMETHODIMP
233 0 : nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
234 : {
235 0 : *aCallbacks = mCallbacks.get();
236 0 : NS_IF_ADDREF(*aCallbacks);
237 0 : return NS_OK;
238 : }
239 :
240 : NS_IMETHODIMP
241 0 : nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
242 : {
243 0 : if (!CanSetCallbacks(aNotificationCallbacks)) {
244 0 : return NS_ERROR_FAILURE;
245 : }
246 :
247 0 : mCallbacks = aNotificationCallbacks;
248 0 : NS_QueryNotificationCallbacks(mCallbacks,
249 : mLoadGroup,
250 : NS_GET_IID(nsIProgressEventSink),
251 0 : getter_AddRefs(mProgressSink));
252 :
253 0 : UpdatePrivateBrowsing();
254 0 : NS_GetOriginAttributes(this, mOriginAttributes);
255 :
256 0 : return NS_OK;
257 : }
258 :
259 : NS_IMETHODIMP
260 0 : nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
261 : {
262 0 : NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
263 :
264 0 : return NS_OK;
265 : }
266 :
267 : NS_IMETHODIMP
268 0 : nsWyciwygChannel::GetContentType(nsACString &aContentType)
269 : {
270 0 : aContentType.AssignLiteral(WYCIWYG_TYPE);
271 0 : return NS_OK;
272 : }
273 :
274 : NS_IMETHODIMP
275 0 : nsWyciwygChannel::SetContentType(const nsACString &aContentType)
276 : {
277 0 : return NS_ERROR_NOT_IMPLEMENTED;
278 : }
279 :
280 : NS_IMETHODIMP
281 0 : nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset)
282 : {
283 0 : aContentCharset.AssignLiteral("UTF-16LE");
284 0 : return NS_OK;
285 : }
286 :
287 : NS_IMETHODIMP
288 0 : nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
289 : {
290 0 : return NS_ERROR_NOT_IMPLEMENTED;
291 : }
292 :
293 : NS_IMETHODIMP
294 0 : nsWyciwygChannel::GetContentDisposition(uint32_t *aContentDisposition)
295 : {
296 0 : return NS_ERROR_NOT_AVAILABLE;
297 : }
298 :
299 : NS_IMETHODIMP
300 0 : nsWyciwygChannel::SetContentDisposition(uint32_t aContentDisposition)
301 : {
302 0 : return NS_ERROR_NOT_AVAILABLE;
303 : }
304 :
305 : NS_IMETHODIMP
306 0 : nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
307 : {
308 0 : return NS_ERROR_NOT_AVAILABLE;
309 : }
310 :
311 : NS_IMETHODIMP
312 0 : nsWyciwygChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
313 : {
314 0 : return NS_ERROR_NOT_AVAILABLE;
315 : }
316 :
317 : NS_IMETHODIMP
318 0 : nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
319 : {
320 0 : return NS_ERROR_NOT_AVAILABLE;
321 : }
322 :
323 : NS_IMETHODIMP
324 0 : nsWyciwygChannel::GetContentLength(int64_t *aContentLength)
325 : {
326 0 : *aContentLength = mContentLength;
327 0 : return NS_OK;
328 : }
329 :
330 : NS_IMETHODIMP
331 0 : nsWyciwygChannel::SetContentLength(int64_t aContentLength)
332 : {
333 0 : mContentLength = aContentLength;
334 :
335 0 : return NS_OK;
336 : }
337 :
338 : NS_IMETHODIMP
339 0 : nsWyciwygChannel::Open(nsIInputStream ** aReturn)
340 : {
341 0 : return NS_ERROR_NOT_IMPLEMENTED;
342 : }
343 :
344 : NS_IMETHODIMP
345 0 : nsWyciwygChannel::Open2(nsIInputStream** aStream)
346 : {
347 0 : nsCOMPtr<nsIStreamListener> listener;
348 0 : nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
349 0 : NS_ENSURE_SUCCESS(rv, rv);
350 0 : return Open(aStream);
351 : }
352 :
353 : NS_IMETHODIMP
354 0 : nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
355 : {
356 0 : MOZ_ASSERT(!mLoadInfo ||
357 : mLoadInfo->GetSecurityMode() == 0 ||
358 : mLoadInfo->GetInitialSecurityCheckDone() ||
359 : (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
360 : nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
361 : "security flags in loadInfo but asyncOpen2() not called");
362 :
363 0 : LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this));
364 0 : MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open");
365 :
366 0 : NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
367 0 : NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS);
368 0 : NS_ENSURE_ARG_POINTER(listener);
369 :
370 0 : mMode = READING;
371 :
372 : // open a cache entry for this channel...
373 : // mIsPending set to true since OnCacheEntryAvailable may be called
374 : // synchronously and fails when mIsPending found false.
375 0 : mIsPending = true;
376 0 : nsresult rv = OpenCacheEntryForReading(mURI);
377 0 : if (NS_FAILED(rv)) {
378 0 : LOG(("nsWyciwygChannel::OpenCacheEntryForReading failed [rv=%" PRIx32 "]\n",
379 : static_cast<uint32_t>(rv)));
380 0 : mIsPending = false;
381 0 : mCallbacks = nullptr;
382 0 : return rv;
383 : }
384 :
385 : // There is no code path that would invoke the listener sooner than
386 : // we get to this line in case OnCacheEntryAvailable is invoked
387 : // synchronously.
388 0 : mListener = listener;
389 0 : mListenerContext = ctx;
390 :
391 0 : if (mLoadGroup)
392 0 : mLoadGroup->AddRequest(this, nullptr);
393 :
394 0 : return NS_OK;
395 : }
396 :
397 : NS_IMETHODIMP
398 0 : nsWyciwygChannel::AsyncOpen2(nsIStreamListener *aListener)
399 : {
400 0 : nsCOMPtr<nsIStreamListener> listener = aListener;
401 0 : nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
402 0 : if (NS_FAILED(rv)) {
403 0 : mIsPending = false;
404 0 : mCallbacks = nullptr;
405 0 : return rv;
406 : }
407 0 : return AsyncOpen(listener, nullptr);
408 : }
409 :
410 : //////////////////////////////////////////////////////////////////////////////
411 : // nsIWyciwygChannel
412 : //////////////////////////////////////////////////////////////////////////////
413 :
414 : NS_IMETHODIMP
415 0 : nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
416 : {
417 0 : LOG(("nsWyciwygChannel::WriteToCacheEntry [this=%p]", this));
418 :
419 : nsresult rv;
420 :
421 0 : if (mMode == READING) {
422 0 : LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading"));
423 0 : MOZ_ASSERT(false);
424 : return NS_ERROR_UNEXPECTED;
425 : }
426 :
427 0 : mMode = WRITING;
428 :
429 0 : if (!mCacheEntry) {
430 0 : nsresult rv = OpenCacheEntryForWriting(mURI);
431 0 : if (NS_FAILED(rv) || !mCacheEntry) {
432 0 : LOG((" could not synchronously open cache entry for write!"));
433 0 : return NS_ERROR_FAILURE;
434 : }
435 : }
436 :
437 0 : if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
438 0 : rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
439 0 : if (NS_FAILED(rv)) return rv;
440 : }
441 :
442 0 : if (mNeedToSetSecurityInfo) {
443 0 : mCacheEntry->SetSecurityInfo(mSecurityInfo);
444 0 : mNeedToSetSecurityInfo = false;
445 : }
446 :
447 0 : if (mNeedToWriteCharset) {
448 0 : WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
449 0 : mNeedToWriteCharset = false;
450 : }
451 :
452 : uint32_t out;
453 0 : if (!mCacheOutputStream) {
454 : // Get the outputstream from the cache entry.
455 0 : rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream));
456 0 : if (NS_FAILED(rv)) return rv;
457 :
458 : // Write out a Byte Order Mark, so that we'll know if the data is
459 : // BE or LE when we go to read it.
460 0 : char16_t bom = 0xFEFF;
461 0 : rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out);
462 0 : if (NS_FAILED(rv)) return rv;
463 : }
464 :
465 0 : return mCacheOutputStream->Write((const char *)PromiseFlatString(aData).get(),
466 0 : aData.Length() * sizeof(char16_t), &out);
467 : }
468 :
469 :
470 : NS_IMETHODIMP
471 0 : nsWyciwygChannel::CloseCacheEntry(nsresult reason)
472 : {
473 0 : if (mCacheEntry) {
474 0 : LOG(("nsWyciwygChannel::CloseCacheEntry [this=%p ]", this));
475 0 : mCacheOutputStream = nullptr;
476 0 : mCacheInputStream = nullptr;
477 :
478 0 : if (NS_FAILED(reason)) {
479 0 : mCacheEntry->AsyncDoom(nullptr);
480 : }
481 :
482 0 : mCacheEntry = nullptr;
483 : }
484 0 : return NS_OK;
485 : }
486 :
487 : NS_IMETHODIMP
488 0 : nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo)
489 : {
490 0 : if (mMode == READING) {
491 0 : MOZ_ASSERT(false);
492 : return NS_ERROR_UNEXPECTED;
493 : }
494 :
495 0 : mSecurityInfo = aSecurityInfo;
496 :
497 0 : if (mCacheEntry) {
498 0 : return mCacheEntry->SetSecurityInfo(mSecurityInfo);
499 : }
500 :
501 0 : mNeedToSetSecurityInfo = true;
502 :
503 0 : return NS_OK;
504 : }
505 :
506 : NS_IMETHODIMP
507 0 : nsWyciwygChannel::SetCharsetAndSource(int32_t aSource,
508 : const nsACString& aCharset)
509 : {
510 0 : NS_ENSURE_ARG(!aCharset.IsEmpty());
511 :
512 0 : if (mCacheEntry) {
513 0 : WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
514 : } else {
515 0 : MOZ_ASSERT(mMode != WRITING, "We must have an entry!");
516 0 : if (mMode == READING) {
517 0 : return NS_ERROR_NOT_AVAILABLE;
518 : }
519 0 : mNeedToWriteCharset = true;
520 0 : mCharsetSource = aSource;
521 0 : mCharset = aCharset;
522 : }
523 :
524 0 : return NS_OK;
525 : }
526 :
527 : NS_IMETHODIMP
528 0 : nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset)
529 : {
530 0 : MOZ_ASSERT(mMode == READING);
531 :
532 0 : if (!mCacheEntry) {
533 0 : return NS_ERROR_NOT_AVAILABLE;
534 : }
535 :
536 0 : nsXPIDLCString data;
537 0 : mCacheEntry->GetMetaDataElement("charset", getter_Copies(data));
538 :
539 0 : if (data.IsEmpty()) {
540 0 : return NS_ERROR_NOT_AVAILABLE;
541 : }
542 :
543 0 : nsXPIDLCString sourceStr;
544 0 : mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr));
545 :
546 : int32_t source;
547 : nsresult err;
548 0 : source = sourceStr.ToInteger(&err);
549 0 : if (NS_FAILED(err) || source == 0) {
550 0 : return NS_ERROR_NOT_AVAILABLE;
551 : }
552 :
553 0 : *aSource = source;
554 0 : aCharset = data;
555 0 : return NS_OK;
556 : }
557 :
558 : //////////////////////////////////////////////////////////////////////////////
559 : // nsICacheEntryOpenCallback
560 : //////////////////////////////////////////////////////////////////////////////
561 :
562 : NS_IMETHODIMP
563 0 : nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache,
564 : uint32_t* aResult)
565 : {
566 0 : *aResult = ENTRY_WANTED;
567 0 : return NS_OK;
568 : }
569 :
570 : NS_IMETHODIMP
571 0 : nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry,
572 : bool aNew,
573 : nsIApplicationCache* aAppCache,
574 : nsresult aStatus)
575 : {
576 0 : LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p "
577 : "new=%d status=%" PRIx32 "]\n", this, aCacheEntry, aNew, static_cast<uint32_t>(aStatus)));
578 :
579 0 : MOZ_RELEASE_ASSERT(!aNew, "New entry must not be returned when flag "
580 : "OPEN_READONLY is used!");
581 :
582 : // if the channel's already fired onStopRequest,
583 : // then we should ignore this event.
584 0 : if (!mIsPending)
585 0 : return NS_OK;
586 :
587 0 : if (NS_SUCCEEDED(mStatus)) {
588 0 : if (NS_SUCCEEDED(aStatus)) {
589 0 : MOZ_ASSERT(aCacheEntry);
590 0 : mCacheEntry = aCacheEntry;
591 0 : nsresult rv = ReadFromCache();
592 0 : if (NS_FAILED(rv)) {
593 0 : mStatus = rv;
594 : }
595 : } else {
596 0 : mStatus = aStatus;
597 : }
598 : }
599 :
600 0 : if (NS_FAILED(mStatus)) {
601 0 : LOG(("channel was canceled [this=%p status=%" PRIx32 "]\n", this, static_cast<uint32_t>(mStatus)));
602 : // Since OnCacheEntryAvailable can be called directly from AsyncOpen
603 : // we must dispatch.
604 0 : NS_DispatchToCurrentThread(
605 0 : mozilla::NewRunnableMethod("nsWyciwygChannel::NotifyListener",
606 : this,
607 0 : &nsWyciwygChannel::NotifyListener));
608 : }
609 :
610 0 : return NS_OK;
611 : }
612 :
613 : //-----------------------------------------------------------------------------
614 : // nsWyciwygChannel::nsIStreamListener
615 : //-----------------------------------------------------------------------------
616 :
617 : NS_IMETHODIMP
618 0 : nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
619 : nsIInputStream *input,
620 : uint64_t offset, uint32_t count)
621 : {
622 0 : LOG(("nsWyciwygChannel::OnDataAvailable [this=%p request=%p offset=%" PRIu64 " count=%u]\n",
623 : this, request, offset, count));
624 :
625 : nsresult rv;
626 :
627 0 : nsCOMPtr<nsIStreamListener> listener = mListener;
628 0 : nsCOMPtr<nsISupports> listenerContext = mListenerContext;
629 :
630 0 : if (listener) {
631 0 : rv = listener->OnDataAvailable(this, listenerContext, input, offset, count);
632 : } else {
633 0 : MOZ_ASSERT(false, "We must have a listener!");
634 : rv = NS_ERROR_UNEXPECTED;
635 : }
636 :
637 : // XXX handle 64-bit stuff for real
638 0 : if (mProgressSink && NS_SUCCEEDED(rv)) {
639 0 : mProgressSink->OnProgress(this, nullptr, offset + count, mContentLength);
640 : }
641 :
642 0 : return rv; // let the pump cancel on failure
643 : }
644 :
645 : //////////////////////////////////////////////////////////////////////////////
646 : // nsIRequestObserver
647 : //////////////////////////////////////////////////////////////////////////////
648 :
649 : NS_IMETHODIMP
650 0 : nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
651 : {
652 0 : LOG(("nsWyciwygChannel::OnStartRequest [this=%p request=%p]\n",
653 : this, request));
654 :
655 0 : nsCOMPtr<nsIStreamListener> listener = mListener;
656 0 : nsCOMPtr<nsISupports> listenerContext = mListenerContext;
657 :
658 0 : if (listener) {
659 0 : return listener->OnStartRequest(this, listenerContext);
660 : }
661 :
662 0 : MOZ_ASSERT(false, "We must have a listener!");
663 : return NS_ERROR_UNEXPECTED;
664 : }
665 :
666 :
667 : NS_IMETHODIMP
668 0 : nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status)
669 : {
670 0 : LOG(("nsWyciwygChannel::OnStopRequest [this=%p request=%p status=%" PRIu32 "]\n",
671 : this, request, static_cast<uint32_t>(status)));
672 :
673 0 : if (NS_SUCCEEDED(mStatus))
674 0 : mStatus = status;
675 :
676 0 : mIsPending = false;
677 :
678 0 : nsCOMPtr<nsIStreamListener> listener;
679 0 : nsCOMPtr<nsISupports> listenerContext;
680 0 : listener.swap(mListener);
681 0 : listenerContext.swap(mListenerContext);
682 :
683 0 : if (listener) {
684 0 : listener->OnStopRequest(this, listenerContext, mStatus);
685 : } else {
686 0 : MOZ_ASSERT(false, "We must have a listener!");
687 : }
688 :
689 0 : if (mLoadGroup)
690 0 : mLoadGroup->RemoveRequest(this, nullptr, mStatus);
691 :
692 0 : CloseCacheEntry(mStatus);
693 0 : mPump = nullptr;
694 :
695 : // Drop notification callbacks to prevent cycles.
696 0 : mCallbacks = nullptr;
697 0 : mProgressSink = nullptr;
698 :
699 0 : return NS_OK;
700 : }
701 :
702 : //////////////////////////////////////////////////////////////////////////////
703 : // Helper functions
704 : //////////////////////////////////////////////////////////////////////////////
705 :
706 : nsresult
707 0 : nsWyciwygChannel::GetCacheStorage(nsICacheStorage **_retval)
708 : {
709 : nsresult rv;
710 :
711 : nsCOMPtr<nsICacheStorageService> cacheService =
712 0 : do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
713 0 : NS_ENSURE_SUCCESS(rv, rv);
714 :
715 0 : bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
716 0 : mOriginAttributes.SyncAttributesWithPrivateBrowsing(mPrivateBrowsing);
717 0 : RefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(anonymous, mOriginAttributes);
718 :
719 0 : if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
720 0 : return cacheService->MemoryCacheStorage(loadInfo, _retval);
721 : }
722 :
723 0 : return cacheService->DiskCacheStorage(loadInfo, false, _retval);
724 : }
725 :
726 : nsresult
727 0 : nsWyciwygChannel::OpenCacheEntryForReading(nsIURI *aURI)
728 : {
729 : nsresult rv;
730 :
731 0 : nsCOMPtr<nsICacheStorage> cacheStorage;
732 0 : rv = GetCacheStorage(getter_AddRefs(cacheStorage));
733 0 : NS_ENSURE_SUCCESS(rv, rv);
734 :
735 0 : return cacheStorage->AsyncOpenURI(aURI, EmptyCString(),
736 : nsICacheStorage::OPEN_READONLY |
737 : nsICacheStorage::CHECK_MULTITHREADED,
738 0 : this);
739 : }
740 :
741 : nsresult
742 0 : nsWyciwygChannel::OpenCacheEntryForWriting(nsIURI *aURI)
743 : {
744 : nsresult rv;
745 :
746 0 : nsCOMPtr<nsICacheStorage> cacheStorage;
747 0 : rv = GetCacheStorage(getter_AddRefs(cacheStorage));
748 0 : NS_ENSURE_SUCCESS(rv, rv);
749 :
750 0 : return cacheStorage->OpenTruncate(aURI, EmptyCString(),
751 0 : getter_AddRefs(mCacheEntry));
752 : }
753 :
754 : nsresult
755 0 : nsWyciwygChannel::ReadFromCache()
756 : {
757 0 : LOG(("nsWyciwygChannel::ReadFromCache [this=%p] ", this));
758 :
759 0 : NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
760 : nsresult rv;
761 :
762 : // Get the stored security info
763 0 : mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
764 :
765 0 : nsAutoCString tmpStr;
766 0 : rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
767 0 : getter_Copies(tmpStr));
768 0 : if (NS_SUCCEEDED(rv) && tmpStr.EqualsLiteral("1"))
769 0 : mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
770 :
771 : // Get a transport to the cached data...
772 0 : rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream));
773 0 : if (NS_FAILED(rv))
774 0 : return rv;
775 0 : NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED);
776 :
777 0 : rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream);
778 0 : if (NS_FAILED(rv)) return rv;
779 :
780 : // Pump the cache data downstream
781 0 : return mPump->AsyncRead(this, nullptr);
782 : }
783 :
784 : void
785 0 : nsWyciwygChannel::WriteCharsetAndSourceToCache(int32_t aSource,
786 : const nsCString& aCharset)
787 : {
788 0 : NS_PRECONDITION(mCacheEntry, "Better have cache entry!");
789 :
790 0 : mCacheEntry->SetMetaDataElement("charset", aCharset.get());
791 :
792 0 : nsAutoCString source;
793 0 : source.AppendInt(aSource);
794 0 : mCacheEntry->SetMetaDataElement("charset-source", source.get());
795 0 : }
796 :
797 : void
798 0 : nsWyciwygChannel::NotifyListener()
799 : {
800 0 : nsCOMPtr<nsIStreamListener> listener;
801 0 : nsCOMPtr<nsISupports> listenerContext;
802 :
803 0 : listener.swap(mListener);
804 0 : listenerContext.swap(mListenerContext);
805 :
806 0 : if (listener) {
807 0 : listener->OnStartRequest(this, listenerContext);
808 0 : mIsPending = false;
809 0 : listener->OnStopRequest(this, listenerContext, mStatus);
810 : } else {
811 0 : MOZ_ASSERT(false, "We must have the listener!");
812 : mIsPending = false;
813 : }
814 :
815 0 : CloseCacheEntry(mStatus);
816 :
817 : // Remove ourselves from the load group.
818 0 : if (mLoadGroup) {
819 0 : mLoadGroup->RemoveRequest(this, nullptr, mStatus);
820 : }
821 0 : }
822 :
823 : // vim: ts=2 sw=2
|