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