netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial