1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,840 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsWyciwyg.h" 1.11 +#include "nsWyciwygChannel.h" 1.12 +#include "nsILoadGroup.h" 1.13 +#include "nsNetUtil.h" 1.14 +#include "LoadContextInfo.h" 1.15 +#include "nsICacheService.h" // only to initialize 1.16 +#include "nsICacheStorageService.h" 1.17 +#include "nsICacheStorage.h" 1.18 +#include "nsICacheEntry.h" 1.19 +#include "CacheObserver.h" 1.20 +#include "nsCharsetSource.h" 1.21 +#include "nsProxyRelease.h" 1.22 +#include "nsThreadUtils.h" 1.23 +#include "nsIEventTarget.h" 1.24 +#include "nsIInputStream.h" 1.25 +#include "nsIInputStreamPump.h" 1.26 +#include "nsIOutputStream.h" 1.27 +#include "nsIProgressEventSink.h" 1.28 +#include "nsIURI.h" 1.29 +#include "mozilla/DebugOnly.h" 1.30 +#include "mozilla/unused.h" 1.31 + 1.32 +typedef mozilla::net::LoadContextInfo LoadContextInfo; 1.33 + 1.34 +// Must release mChannel on the main thread 1.35 +class nsWyciwygAsyncEvent : public nsRunnable { 1.36 +public: 1.37 + nsWyciwygAsyncEvent(nsWyciwygChannel *aChannel) : mChannel(aChannel) {} 1.38 + 1.39 + ~nsWyciwygAsyncEvent() 1.40 + { 1.41 + nsCOMPtr<nsIThread> thread = do_GetMainThread(); 1.42 + NS_WARN_IF_FALSE(thread, "Couldn't get the main thread!"); 1.43 + if (thread) { 1.44 + nsIWyciwygChannel *chan = static_cast<nsIWyciwygChannel *>(mChannel); 1.45 + mozilla::unused << mChannel.forget(); 1.46 + NS_ProxyRelease(thread, chan); 1.47 + } 1.48 + } 1.49 +protected: 1.50 + nsRefPtr<nsWyciwygChannel> mChannel; 1.51 +}; 1.52 + 1.53 +class nsWyciwygSetCharsetandSourceEvent : public nsWyciwygAsyncEvent { 1.54 +public: 1.55 + nsWyciwygSetCharsetandSourceEvent(nsWyciwygChannel *aChannel) 1.56 + : nsWyciwygAsyncEvent(aChannel) {} 1.57 + 1.58 + NS_IMETHOD Run() 1.59 + { 1.60 + mChannel->SetCharsetAndSourceInternal(); 1.61 + return NS_OK; 1.62 + } 1.63 +}; 1.64 + 1.65 +class nsWyciwygWriteEvent : public nsWyciwygAsyncEvent { 1.66 +public: 1.67 + nsWyciwygWriteEvent(nsWyciwygChannel *aChannel, const nsAString &aData) 1.68 + : nsWyciwygAsyncEvent(aChannel), mData(aData) {} 1.69 + 1.70 + NS_IMETHOD Run() 1.71 + { 1.72 + mChannel->WriteToCacheEntryInternal(mData); 1.73 + return NS_OK; 1.74 + } 1.75 +private: 1.76 + nsString mData; 1.77 +}; 1.78 + 1.79 +class nsWyciwygCloseEvent : public nsWyciwygAsyncEvent { 1.80 +public: 1.81 + nsWyciwygCloseEvent(nsWyciwygChannel *aChannel, nsresult aReason) 1.82 + : nsWyciwygAsyncEvent(aChannel), mReason(aReason) {} 1.83 + 1.84 + NS_IMETHOD Run() 1.85 + { 1.86 + mChannel->CloseCacheEntryInternal(mReason); 1.87 + return NS_OK; 1.88 + } 1.89 +private: 1.90 + nsresult mReason; 1.91 +}; 1.92 + 1.93 + 1.94 +// nsWyciwygChannel methods 1.95 +nsWyciwygChannel::nsWyciwygChannel() 1.96 + : mMode(NONE), 1.97 + mStatus(NS_OK), 1.98 + mIsPending(false), 1.99 + mCharsetAndSourceSet(false), 1.100 + mNeedToWriteCharset(false), 1.101 + mCharsetSource(kCharsetUninitialized), 1.102 + mContentLength(-1), 1.103 + mLoadFlags(LOAD_NORMAL), 1.104 + mAppId(NECKO_NO_APP_ID), 1.105 + mInBrowser(false) 1.106 +{ 1.107 +} 1.108 + 1.109 +nsWyciwygChannel::~nsWyciwygChannel() 1.110 +{ 1.111 +} 1.112 + 1.113 +NS_IMPL_ISUPPORTS(nsWyciwygChannel, 1.114 + nsIChannel, 1.115 + nsIRequest, 1.116 + nsIStreamListener, 1.117 + nsIRequestObserver, 1.118 + nsICacheEntryOpenCallback, 1.119 + nsIWyciwygChannel, 1.120 + nsIPrivateBrowsingChannel) 1.121 + 1.122 +nsresult 1.123 +nsWyciwygChannel::Init(nsIURI* uri) 1.124 +{ 1.125 + NS_ENSURE_ARG_POINTER(uri); 1.126 + 1.127 + nsresult rv; 1.128 + 1.129 + if (!mozilla::net::CacheObserver::UseNewCache()) { 1.130 + // Since nsWyciwygChannel can use the new cache API off the main thread 1.131 + // and that API normally does this initiation, we need to take care 1.132 + // of initiating the old cache service here manually. Will be removed 1.133 + // with bug 913828. 1.134 + MOZ_ASSERT(NS_IsMainThread()); 1.135 + nsCOMPtr<nsICacheService> service = 1.136 + do_GetService(NS_CACHESERVICE_CONTRACTID, &rv); 1.137 + } 1.138 + 1.139 + mURI = uri; 1.140 + mOriginalURI = uri; 1.141 + 1.142 + nsCOMPtr<nsICacheStorageService> serv = 1.143 + do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv); 1.144 + NS_ENSURE_SUCCESS(rv, rv); 1.145 + 1.146 + rv = serv->GetIoTarget(getter_AddRefs(mCacheIOTarget)); 1.147 + NS_ENSURE_SUCCESS(rv, rv); 1.148 + 1.149 + return NS_OK; 1.150 +} 1.151 + 1.152 +/////////////////////////////////////////////////////////////////////////////// 1.153 +// nsIRequest methods: 1.154 +/////////////////////////////////////////////////////////////////////////////// 1.155 + 1.156 +NS_IMETHODIMP 1.157 +nsWyciwygChannel::GetName(nsACString &aName) 1.158 +{ 1.159 + return mURI->GetSpec(aName); 1.160 +} 1.161 + 1.162 +NS_IMETHODIMP 1.163 +nsWyciwygChannel::IsPending(bool *aIsPending) 1.164 +{ 1.165 + *aIsPending = mIsPending; 1.166 + return NS_OK; 1.167 +} 1.168 + 1.169 +NS_IMETHODIMP 1.170 +nsWyciwygChannel::GetStatus(nsresult *aStatus) 1.171 +{ 1.172 + if (NS_SUCCEEDED(mStatus) && mPump) 1.173 + mPump->GetStatus(aStatus); 1.174 + else 1.175 + *aStatus = mStatus; 1.176 + return NS_OK; 1.177 +} 1.178 + 1.179 +NS_IMETHODIMP 1.180 +nsWyciwygChannel::Cancel(nsresult status) 1.181 +{ 1.182 + mStatus = status; 1.183 + if (mPump) 1.184 + mPump->Cancel(status); 1.185 + // else we're waiting for OnCacheEntryAvailable 1.186 + return NS_OK; 1.187 +} 1.188 + 1.189 +NS_IMETHODIMP 1.190 +nsWyciwygChannel::Suspend() 1.191 +{ 1.192 + if (mPump) 1.193 + mPump->Suspend(); 1.194 + // XXX else, we'll ignore this ... and that's probably bad! 1.195 + return NS_OK; 1.196 +} 1.197 + 1.198 +NS_IMETHODIMP 1.199 +nsWyciwygChannel::Resume() 1.200 +{ 1.201 + if (mPump) 1.202 + mPump->Resume(); 1.203 + // XXX else, we'll ignore this ... and that's probably bad! 1.204 + return NS_OK; 1.205 +} 1.206 + 1.207 +NS_IMETHODIMP 1.208 +nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) 1.209 +{ 1.210 + *aLoadGroup = mLoadGroup; 1.211 + NS_IF_ADDREF(*aLoadGroup); 1.212 + return NS_OK; 1.213 +} 1.214 + 1.215 +NS_IMETHODIMP 1.216 +nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) 1.217 +{ 1.218 + if (!CanSetLoadGroup(aLoadGroup)) { 1.219 + return NS_ERROR_FAILURE; 1.220 + } 1.221 + 1.222 + mLoadGroup = aLoadGroup; 1.223 + NS_QueryNotificationCallbacks(mCallbacks, 1.224 + mLoadGroup, 1.225 + NS_GET_IID(nsIProgressEventSink), 1.226 + getter_AddRefs(mProgressSink)); 1.227 + mPrivateBrowsing = NS_UsePrivateBrowsing(this); 1.228 + NS_GetAppInfo(this, &mAppId, &mInBrowser); 1.229 + return NS_OK; 1.230 +} 1.231 + 1.232 +NS_IMETHODIMP 1.233 +nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags) 1.234 +{ 1.235 + mLoadFlags = aLoadFlags; 1.236 + return NS_OK; 1.237 +} 1.238 + 1.239 +NS_IMETHODIMP 1.240 +nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags) 1.241 +{ 1.242 + *aLoadFlags = mLoadFlags; 1.243 + return NS_OK; 1.244 +} 1.245 + 1.246 +//////////////////////////////////////////////////////////////////////////////// 1.247 +// nsIChannel methods: 1.248 +/////////////////////////////////////////////////////////////////////////////// 1.249 + 1.250 +NS_IMETHODIMP 1.251 +nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI) 1.252 +{ 1.253 + *aURI = mOriginalURI; 1.254 + NS_ADDREF(*aURI); 1.255 + return NS_OK; 1.256 +} 1.257 + 1.258 +NS_IMETHODIMP 1.259 +nsWyciwygChannel::SetOriginalURI(nsIURI* aURI) 1.260 +{ 1.261 + NS_ENSURE_ARG_POINTER(aURI); 1.262 + mOriginalURI = aURI; 1.263 + return NS_OK; 1.264 +} 1.265 + 1.266 +NS_IMETHODIMP 1.267 +nsWyciwygChannel::GetURI(nsIURI* *aURI) 1.268 +{ 1.269 + *aURI = mURI; 1.270 + NS_IF_ADDREF(*aURI); 1.271 + return NS_OK; 1.272 +} 1.273 + 1.274 +NS_IMETHODIMP 1.275 +nsWyciwygChannel::GetOwner(nsISupports **aOwner) 1.276 +{ 1.277 + NS_PRECONDITION(mOwner, "Must have a principal!"); 1.278 + NS_ENSURE_STATE(mOwner); 1.279 + 1.280 + NS_ADDREF(*aOwner = mOwner); 1.281 + return NS_OK; 1.282 +} 1.283 + 1.284 +NS_IMETHODIMP 1.285 +nsWyciwygChannel::SetOwner(nsISupports* aOwner) 1.286 +{ 1.287 + mOwner = aOwner; 1.288 + return NS_OK; 1.289 +} 1.290 + 1.291 +NS_IMETHODIMP 1.292 +nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks) 1.293 +{ 1.294 + *aCallbacks = mCallbacks.get(); 1.295 + NS_IF_ADDREF(*aCallbacks); 1.296 + return NS_OK; 1.297 +} 1.298 + 1.299 +NS_IMETHODIMP 1.300 +nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) 1.301 +{ 1.302 + if (!CanSetCallbacks(aNotificationCallbacks)) { 1.303 + return NS_ERROR_FAILURE; 1.304 + } 1.305 + 1.306 + mCallbacks = aNotificationCallbacks; 1.307 + NS_QueryNotificationCallbacks(mCallbacks, 1.308 + mLoadGroup, 1.309 + NS_GET_IID(nsIProgressEventSink), 1.310 + getter_AddRefs(mProgressSink)); 1.311 + 1.312 + mPrivateBrowsing = NS_UsePrivateBrowsing(this); 1.313 + NS_GetAppInfo(this, &mAppId, &mInBrowser); 1.314 + 1.315 + return NS_OK; 1.316 +} 1.317 + 1.318 +NS_IMETHODIMP 1.319 +nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) 1.320 +{ 1.321 + NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo); 1.322 + 1.323 + return NS_OK; 1.324 +} 1.325 + 1.326 +NS_IMETHODIMP 1.327 +nsWyciwygChannel::GetContentType(nsACString &aContentType) 1.328 +{ 1.329 + aContentType.AssignLiteral(WYCIWYG_TYPE); 1.330 + return NS_OK; 1.331 +} 1.332 + 1.333 +NS_IMETHODIMP 1.334 +nsWyciwygChannel::SetContentType(const nsACString &aContentType) 1.335 +{ 1.336 + return NS_ERROR_NOT_IMPLEMENTED; 1.337 +} 1.338 + 1.339 +NS_IMETHODIMP 1.340 +nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset) 1.341 +{ 1.342 + aContentCharset.Assign("UTF-16"); 1.343 + return NS_OK; 1.344 +} 1.345 + 1.346 +NS_IMETHODIMP 1.347 +nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset) 1.348 +{ 1.349 + return NS_ERROR_NOT_IMPLEMENTED; 1.350 +} 1.351 + 1.352 +NS_IMETHODIMP 1.353 +nsWyciwygChannel::GetContentDisposition(uint32_t *aContentDisposition) 1.354 +{ 1.355 + return NS_ERROR_NOT_AVAILABLE; 1.356 +} 1.357 + 1.358 +NS_IMETHODIMP 1.359 +nsWyciwygChannel::SetContentDisposition(uint32_t aContentDisposition) 1.360 +{ 1.361 + return NS_ERROR_NOT_AVAILABLE; 1.362 +} 1.363 + 1.364 +NS_IMETHODIMP 1.365 +nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename) 1.366 +{ 1.367 + return NS_ERROR_NOT_AVAILABLE; 1.368 +} 1.369 + 1.370 +NS_IMETHODIMP 1.371 +nsWyciwygChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename) 1.372 +{ 1.373 + return NS_ERROR_NOT_AVAILABLE; 1.374 +} 1.375 + 1.376 +NS_IMETHODIMP 1.377 +nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader) 1.378 +{ 1.379 + return NS_ERROR_NOT_AVAILABLE; 1.380 +} 1.381 + 1.382 +NS_IMETHODIMP 1.383 +nsWyciwygChannel::GetContentLength(int64_t *aContentLength) 1.384 +{ 1.385 + *aContentLength = mContentLength; 1.386 + return NS_OK; 1.387 +} 1.388 + 1.389 +NS_IMETHODIMP 1.390 +nsWyciwygChannel::SetContentLength(int64_t aContentLength) 1.391 +{ 1.392 + mContentLength = aContentLength; 1.393 + 1.394 + return NS_OK; 1.395 +} 1.396 + 1.397 +NS_IMETHODIMP 1.398 +nsWyciwygChannel::Open(nsIInputStream ** aReturn) 1.399 +{ 1.400 + return NS_ERROR_NOT_IMPLEMENTED; 1.401 +} 1.402 + 1.403 +NS_IMETHODIMP 1.404 +nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) 1.405 +{ 1.406 + LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this)); 1.407 + MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open"); 1.408 + 1.409 + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); 1.410 + NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS); 1.411 + NS_ENSURE_ARG_POINTER(listener); 1.412 + 1.413 + mMode = READING; 1.414 + 1.415 + // open a cache entry for this channel... 1.416 + // mIsPending set to true since OnCacheEntryAvailable may be called 1.417 + // synchronously and fails when mIsPending found false. 1.418 + mIsPending = true; 1.419 + nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_READONLY | 1.420 + nsICacheStorage::CHECK_MULTITHREADED); 1.421 + if (NS_FAILED(rv)) { 1.422 + LOG(("nsWyciwygChannel::OpenCacheEntry failed [rv=%x]\n", rv)); 1.423 + mIsPending = false; 1.424 + return rv; 1.425 + } 1.426 + 1.427 + // There is no code path that would invoke the listener sooner than 1.428 + // we get to this line in case OnCacheEntryAvailable is invoked 1.429 + // synchronously. 1.430 + mListener = listener; 1.431 + mListenerContext = ctx; 1.432 + 1.433 + if (mLoadGroup) 1.434 + mLoadGroup->AddRequest(this, nullptr); 1.435 + 1.436 + return NS_OK; 1.437 +} 1.438 + 1.439 +////////////////////////////////////////////////////////////////////////////// 1.440 +// nsIWyciwygChannel 1.441 +////////////////////////////////////////////////////////////////////////////// 1.442 + 1.443 +nsresult 1.444 +nsWyciwygChannel::EnsureWriteCacheEntry() 1.445 +{ 1.446 + MOZ_ASSERT(mMode == WRITING, "nsWyciwygChannel not open for writing"); 1.447 + 1.448 + if (!mCacheEntry) { 1.449 + // OPEN_TRUNCATE will give us the entry instantly 1.450 + nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_TRUNCATE); 1.451 + if (NS_FAILED(rv) || !mCacheEntry) { 1.452 + LOG((" could not synchronously open cache entry for write!")); 1.453 + return NS_ERROR_FAILURE; 1.454 + } 1.455 + } 1.456 + 1.457 + return NS_OK; 1.458 +} 1.459 + 1.460 +NS_IMETHODIMP 1.461 +nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData) 1.462 +{ 1.463 + if (mMode == READING) { 1.464 + LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading")); 1.465 + MOZ_ASSERT(false); 1.466 + return NS_ERROR_UNEXPECTED; 1.467 + } 1.468 + 1.469 + mMode = WRITING; 1.470 + 1.471 + if (mozilla::net::CacheObserver::UseNewCache()) { 1.472 + nsresult rv = EnsureWriteCacheEntry(); 1.473 + if (NS_FAILED(rv)) return rv; 1.474 + } 1.475 + 1.476 + return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData), 1.477 + NS_DISPATCH_NORMAL); 1.478 +} 1.479 + 1.480 +nsresult 1.481 +nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData) 1.482 +{ 1.483 + LOG(("nsWyciwygChannel::WriteToCacheEntryInternal [this=%p]", this)); 1.484 + NS_ASSERTION(IsOnCacheIOThread(), "wrong thread"); 1.485 + 1.486 + nsresult rv; 1.487 + 1.488 + // With the new cache entry this will just pass as a no-op since we 1.489 + // are opening the entry in WriteToCacheEntry. 1.490 + rv = EnsureWriteCacheEntry(); 1.491 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.492 + return rv; 1.493 + } 1.494 + 1.495 + if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) { 1.496 + rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1"); 1.497 + if (NS_FAILED(rv)) return rv; 1.498 + } 1.499 + 1.500 + if (mSecurityInfo) { 1.501 + mCacheEntry->SetSecurityInfo(mSecurityInfo); 1.502 + } 1.503 + 1.504 + if (mNeedToWriteCharset) { 1.505 + WriteCharsetAndSourceToCache(mCharsetSource, mCharset); 1.506 + mNeedToWriteCharset = false; 1.507 + } 1.508 + 1.509 + uint32_t out; 1.510 + if (!mCacheOutputStream) { 1.511 + // Get the outputstream from the cache entry. 1.512 + rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream)); 1.513 + if (NS_FAILED(rv)) return rv; 1.514 + 1.515 + // Write out a Byte Order Mark, so that we'll know if the data is 1.516 + // BE or LE when we go to read it. 1.517 + char16_t bom = 0xFEFF; 1.518 + rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out); 1.519 + if (NS_FAILED(rv)) return rv; 1.520 + } 1.521 + 1.522 + return mCacheOutputStream->Write((const char *)PromiseFlatString(aData).get(), 1.523 + aData.Length() * sizeof(char16_t), &out); 1.524 +} 1.525 + 1.526 + 1.527 +NS_IMETHODIMP 1.528 +nsWyciwygChannel::CloseCacheEntry(nsresult reason) 1.529 +{ 1.530 + return mCacheIOTarget->Dispatch(new nsWyciwygCloseEvent(this, reason), 1.531 + NS_DISPATCH_NORMAL); 1.532 +} 1.533 + 1.534 +nsresult 1.535 +nsWyciwygChannel::CloseCacheEntryInternal(nsresult reason) 1.536 +{ 1.537 + NS_ASSERTION(IsOnCacheIOThread(), "wrong thread"); 1.538 + 1.539 + if (mCacheEntry) { 1.540 + LOG(("nsWyciwygChannel::CloseCacheEntryInternal [this=%p ]", this)); 1.541 + mCacheOutputStream = 0; 1.542 + mCacheInputStream = 0; 1.543 + 1.544 + if (NS_FAILED(reason)) 1.545 + mCacheEntry->AsyncDoom(nullptr); // here we were calling Doom() ... 1.546 + 1.547 + mCacheEntry = 0; 1.548 + } 1.549 + return NS_OK; 1.550 +} 1.551 + 1.552 +NS_IMETHODIMP 1.553 +nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo) 1.554 +{ 1.555 + mSecurityInfo = aSecurityInfo; 1.556 + 1.557 + return NS_OK; 1.558 +} 1.559 + 1.560 +NS_IMETHODIMP 1.561 +nsWyciwygChannel::SetCharsetAndSource(int32_t aSource, 1.562 + const nsACString& aCharset) 1.563 +{ 1.564 + NS_ENSURE_ARG(!aCharset.IsEmpty()); 1.565 + 1.566 + mCharsetAndSourceSet = true; 1.567 + mCharset = aCharset; 1.568 + mCharsetSource = aSource; 1.569 + 1.570 + return mCacheIOTarget->Dispatch(new nsWyciwygSetCharsetandSourceEvent(this), 1.571 + NS_DISPATCH_NORMAL); 1.572 +} 1.573 + 1.574 +void 1.575 +nsWyciwygChannel::SetCharsetAndSourceInternal() 1.576 +{ 1.577 + NS_ASSERTION(IsOnCacheIOThread(), "wrong thread"); 1.578 + 1.579 + if (mCacheEntry) { 1.580 + WriteCharsetAndSourceToCache(mCharsetSource, mCharset); 1.581 + } else { 1.582 + mNeedToWriteCharset = true; 1.583 + } 1.584 +} 1.585 + 1.586 +NS_IMETHODIMP 1.587 +nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset) 1.588 +{ 1.589 + if (mCharsetAndSourceSet) { 1.590 + *aSource = mCharsetSource; 1.591 + aCharset = mCharset; 1.592 + return NS_OK; 1.593 + } 1.594 + 1.595 + if (!mCacheEntry) { 1.596 + return NS_ERROR_NOT_AVAILABLE; 1.597 + } 1.598 + 1.599 + nsXPIDLCString data; 1.600 + mCacheEntry->GetMetaDataElement("charset", getter_Copies(data)); 1.601 + 1.602 + if (data.IsEmpty()) { 1.603 + return NS_ERROR_NOT_AVAILABLE; 1.604 + } 1.605 + 1.606 + nsXPIDLCString sourceStr; 1.607 + mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr)); 1.608 + 1.609 + int32_t source; 1.610 + nsresult err; 1.611 + source = sourceStr.ToInteger(&err); 1.612 + if (NS_FAILED(err) || source == 0) { 1.613 + return NS_ERROR_NOT_AVAILABLE; 1.614 + } 1.615 + 1.616 + *aSource = source; 1.617 + aCharset = data; 1.618 + return NS_OK; 1.619 +} 1.620 + 1.621 +////////////////////////////////////////////////////////////////////////////// 1.622 +// nsICacheEntryOpenCallback 1.623 +////////////////////////////////////////////////////////////////////////////// 1.624 + 1.625 +NS_IMETHODIMP 1.626 +nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache, 1.627 + uint32_t* aResult) 1.628 +{ 1.629 + *aResult = ENTRY_WANTED; 1.630 + return NS_OK; 1.631 +} 1.632 + 1.633 +NS_IMETHODIMP 1.634 +nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry, 1.635 + bool aNew, 1.636 + nsIApplicationCache* aAppCache, 1.637 + nsresult aStatus) 1.638 +{ 1.639 + LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p " 1.640 + "new=%d status=%x]\n", this, aCacheEntry, aNew, aStatus)); 1.641 + 1.642 + // if the channel's already fired onStopRequest, 1.643 + // then we should ignore this event. 1.644 + if (!mIsPending && !aNew) 1.645 + return NS_OK; 1.646 + 1.647 + // otherwise, we have to handle this event. 1.648 + if (NS_SUCCEEDED(aStatus)) 1.649 + mCacheEntry = aCacheEntry; 1.650 + else if (NS_SUCCEEDED(mStatus)) 1.651 + mStatus = aStatus; 1.652 + 1.653 + nsresult rv = NS_OK; 1.654 + if (NS_FAILED(mStatus)) { 1.655 + LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus)); 1.656 + rv = mStatus; 1.657 + } 1.658 + else if (!aNew) { // advance to the next state... 1.659 + rv = ReadFromCache(); 1.660 + } 1.661 + 1.662 + // a failure from Connect means that we have to abort the channel. 1.663 + if (NS_FAILED(rv)) { 1.664 + CloseCacheEntry(rv); 1.665 + 1.666 + if (!aNew) { 1.667 + // Since OnCacheEntryAvailable can be called directly from AsyncOpen 1.668 + // we must dispatch. 1.669 + NS_DispatchToCurrentThread(NS_NewRunnableMethod( 1.670 + this, &nsWyciwygChannel::NotifyListener)); 1.671 + } 1.672 + } 1.673 + 1.674 + return NS_OK; 1.675 +} 1.676 + 1.677 +//----------------------------------------------------------------------------- 1.678 +// nsWyciwygChannel::nsIStreamListener 1.679 +//----------------------------------------------------------------------------- 1.680 + 1.681 +NS_IMETHODIMP 1.682 +nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx, 1.683 + nsIInputStream *input, 1.684 + uint64_t offset, uint32_t count) 1.685 +{ 1.686 + LOG(("nsWyciwygChannel::OnDataAvailable [this=%p request=%x offset=%llu count=%u]\n", 1.687 + this, request, offset, count)); 1.688 + 1.689 + nsresult rv; 1.690 + 1.691 + rv = mListener->OnDataAvailable(this, mListenerContext, input, offset, count); 1.692 + 1.693 + // XXX handle 64-bit stuff for real 1.694 + if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND)) 1.695 + mProgressSink->OnProgress(this, nullptr, offset + count, 1.696 + uint64_t(mContentLength)); 1.697 + 1.698 + return rv; // let the pump cancel on failure 1.699 +} 1.700 + 1.701 +////////////////////////////////////////////////////////////////////////////// 1.702 +// nsIRequestObserver 1.703 +////////////////////////////////////////////////////////////////////////////// 1.704 + 1.705 +NS_IMETHODIMP 1.706 +nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx) 1.707 +{ 1.708 + LOG(("nsWyciwygChannel::OnStartRequest [this=%p request=%x\n", 1.709 + this, request)); 1.710 + 1.711 + return mListener->OnStartRequest(this, mListenerContext); 1.712 +} 1.713 + 1.714 + 1.715 +NS_IMETHODIMP 1.716 +nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status) 1.717 +{ 1.718 + LOG(("nsWyciwygChannel::OnStopRequest [this=%p request=%x status=%d\n", 1.719 + this, request, status)); 1.720 + 1.721 + if (NS_SUCCEEDED(mStatus)) 1.722 + mStatus = status; 1.723 + 1.724 + mListener->OnStopRequest(this, mListenerContext, mStatus); 1.725 + mListener = 0; 1.726 + mListenerContext = 0; 1.727 + 1.728 + if (mLoadGroup) 1.729 + mLoadGroup->RemoveRequest(this, nullptr, mStatus); 1.730 + 1.731 + CloseCacheEntry(mStatus); 1.732 + mPump = 0; 1.733 + mIsPending = false; 1.734 + 1.735 + // Drop notification callbacks to prevent cycles. 1.736 + mCallbacks = 0; 1.737 + mProgressSink = 0; 1.738 + 1.739 + return NS_OK; 1.740 +} 1.741 + 1.742 +////////////////////////////////////////////////////////////////////////////// 1.743 +// Helper functions 1.744 +////////////////////////////////////////////////////////////////////////////// 1.745 + 1.746 +nsresult 1.747 +nsWyciwygChannel::OpenCacheEntry(nsIURI *aURI, 1.748 + uint32_t aOpenFlags) 1.749 +{ 1.750 + nsresult rv; 1.751 + 1.752 + nsCOMPtr<nsICacheStorageService> cacheService = 1.753 + do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv); 1.754 + NS_ENSURE_SUCCESS(rv, rv); 1.755 + 1.756 + bool anonymous = mLoadFlags & LOAD_ANONYMOUS; 1.757 + nsRefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo( 1.758 + mPrivateBrowsing, mAppId, mInBrowser, anonymous); 1.759 + 1.760 + nsCOMPtr<nsICacheStorage> cacheStorage; 1.761 + if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) 1.762 + rv = cacheService->MemoryCacheStorage(loadInfo, getter_AddRefs(cacheStorage)); 1.763 + else 1.764 + rv = cacheService->DiskCacheStorage(loadInfo, false, getter_AddRefs(cacheStorage)); 1.765 + NS_ENSURE_SUCCESS(rv, rv); 1.766 + 1.767 + rv = cacheStorage->AsyncOpenURI(aURI, EmptyCString(), aOpenFlags, this); 1.768 + NS_ENSURE_SUCCESS(rv, rv); 1.769 + 1.770 + return NS_OK; 1.771 +} 1.772 + 1.773 +nsresult 1.774 +nsWyciwygChannel::ReadFromCache() 1.775 +{ 1.776 + LOG(("nsWyciwygChannel::ReadFromCache [this=%p] ", this)); 1.777 + 1.778 + NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE); 1.779 + nsresult rv; 1.780 + 1.781 + // Get the stored security info 1.782 + mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); 1.783 + 1.784 + nsAutoCString tmpStr; 1.785 + rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching", 1.786 + getter_Copies(tmpStr)); 1.787 + if (NS_SUCCEEDED(rv) && tmpStr == NS_LITERAL_CSTRING("1")) 1.788 + mLoadFlags |= INHIBIT_PERSISTENT_CACHING; 1.789 + 1.790 + // Get a transport to the cached data... 1.791 + rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream)); 1.792 + if (NS_FAILED(rv)) 1.793 + return rv; 1.794 + NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED); 1.795 + 1.796 + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream); 1.797 + if (NS_FAILED(rv)) return rv; 1.798 + 1.799 + // Pump the cache data downstream 1.800 + return mPump->AsyncRead(this, nullptr); 1.801 +} 1.802 + 1.803 +void 1.804 +nsWyciwygChannel::WriteCharsetAndSourceToCache(int32_t aSource, 1.805 + const nsCString& aCharset) 1.806 +{ 1.807 + NS_ASSERTION(IsOnCacheIOThread(), "wrong thread"); 1.808 + NS_PRECONDITION(mCacheEntry, "Better have cache entry!"); 1.809 + 1.810 + mCacheEntry->SetMetaDataElement("charset", aCharset.get()); 1.811 + 1.812 + nsAutoCString source; 1.813 + source.AppendInt(aSource); 1.814 + mCacheEntry->SetMetaDataElement("charset-source", source.get()); 1.815 +} 1.816 + 1.817 +void 1.818 +nsWyciwygChannel::NotifyListener() 1.819 +{ 1.820 + if (mListener) { 1.821 + mListener->OnStartRequest(this, mListenerContext); 1.822 + mListener->OnStopRequest(this, mListenerContext, mStatus); 1.823 + mListener = 0; 1.824 + mListenerContext = 0; 1.825 + } 1.826 + 1.827 + mIsPending = false; 1.828 + 1.829 + // Remove ourselves from the load group. 1.830 + if (mLoadGroup) { 1.831 + mLoadGroup->RemoveRequest(this, nullptr, mStatus); 1.832 + } 1.833 +} 1.834 + 1.835 +bool 1.836 +nsWyciwygChannel::IsOnCacheIOThread() 1.837 +{ 1.838 + bool correctThread; 1.839 + mCacheIOTarget->IsOnCurrentThread(&correctThread); 1.840 + return correctThread; 1.841 +} 1.842 + 1.843 +// vim: ts=2 sw=2