netwerk/cache/nsCacheEntryDescriptor.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: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "nsICache.h"
michael@0 8 #include "nsCache.h"
michael@0 9 #include "nsCacheService.h"
michael@0 10 #include "nsCacheEntryDescriptor.h"
michael@0 11 #include "nsCacheEntry.h"
michael@0 12 #include "nsReadableUtils.h"
michael@0 13 #include "nsIOutputStream.h"
michael@0 14 #include "nsCRT.h"
michael@0 15 #include "nsThreadUtils.h"
michael@0 16 #include <algorithm>
michael@0 17
michael@0 18 #define kMinDecompressReadBufLen 1024
michael@0 19 #define kMinCompressWriteBufLen 1024
michael@0 20
michael@0 21
michael@0 22 /******************************************************************************
michael@0 23 * nsAsyncDoomEvent
michael@0 24 *****************************************************************************/
michael@0 25
michael@0 26 class nsAsyncDoomEvent : public nsRunnable {
michael@0 27 public:
michael@0 28 nsAsyncDoomEvent(nsCacheEntryDescriptor *descriptor,
michael@0 29 nsICacheListener *listener)
michael@0 30 {
michael@0 31 mDescriptor = descriptor;
michael@0 32 mListener = listener;
michael@0 33 mThread = do_GetCurrentThread();
michael@0 34 // We addref the listener here and release it in nsNotifyDoomListener
michael@0 35 // on the callers thread. If posting of nsNotifyDoomListener event fails
michael@0 36 // we leak the listener which is better than releasing it on a wrong
michael@0 37 // thread.
michael@0 38 NS_IF_ADDREF(mListener);
michael@0 39 }
michael@0 40
michael@0 41 NS_IMETHOD Run()
michael@0 42 {
michael@0 43 nsresult status = NS_OK;
michael@0 44
michael@0 45 {
michael@0 46 nsCacheServiceAutoLock lock(LOCK_TELEM(NSASYNCDOOMEVENT_RUN));
michael@0 47
michael@0 48 if (mDescriptor->mCacheEntry) {
michael@0 49 status = nsCacheService::gService->DoomEntry_Internal(
michael@0 50 mDescriptor->mCacheEntry, true);
michael@0 51 } else if (!mDescriptor->mDoomedOnClose) {
michael@0 52 status = NS_ERROR_NOT_AVAILABLE;
michael@0 53 }
michael@0 54 }
michael@0 55
michael@0 56 if (mListener) {
michael@0 57 mThread->Dispatch(new nsNotifyDoomListener(mListener, status),
michael@0 58 NS_DISPATCH_NORMAL);
michael@0 59 // posted event will release the reference on the correct thread
michael@0 60 mListener = nullptr;
michael@0 61 }
michael@0 62
michael@0 63 return NS_OK;
michael@0 64 }
michael@0 65
michael@0 66 private:
michael@0 67 nsRefPtr<nsCacheEntryDescriptor> mDescriptor;
michael@0 68 nsICacheListener *mListener;
michael@0 69 nsCOMPtr<nsIThread> mThread;
michael@0 70 };
michael@0 71
michael@0 72
michael@0 73 NS_IMPL_ISUPPORTS(nsCacheEntryDescriptor,
michael@0 74 nsICacheEntryDescriptor,
michael@0 75 nsICacheEntryInfo)
michael@0 76
michael@0 77 nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry,
michael@0 78 nsCacheAccessMode accessGranted)
michael@0 79 : mCacheEntry(entry),
michael@0 80 mAccessGranted(accessGranted),
michael@0 81 mOutputWrapper(nullptr),
michael@0 82 mLock("nsCacheEntryDescriptor.mLock"),
michael@0 83 mAsyncDoomPending(false),
michael@0 84 mDoomedOnClose(false),
michael@0 85 mClosingDescriptor(false)
michael@0 86 {
michael@0 87 PR_INIT_CLIST(this);
michael@0 88 NS_ADDREF(nsCacheService::GlobalInstance()); // ensure it lives for the lifetime of the descriptor
michael@0 89 }
michael@0 90
michael@0 91
michael@0 92 nsCacheEntryDescriptor::~nsCacheEntryDescriptor()
michael@0 93 {
michael@0 94 // No need to close if the cache entry has already been severed. This
michael@0 95 // helps avoid a shutdown assertion (bug 285519) that is caused when
michael@0 96 // consumers end up holding onto these objects past xpcom-shutdown. It's
michael@0 97 // okay for them to do that because the cache service calls our Close
michael@0 98 // method during xpcom-shutdown, so we don't need to complain about it.
michael@0 99 if (mCacheEntry)
michael@0 100 Close();
michael@0 101
michael@0 102 NS_ASSERTION(mInputWrappers.Count() == 0,
michael@0 103 "We have still some input wrapper!");
michael@0 104 NS_ASSERTION(!mOutputWrapper, "We have still an output wrapper!");
michael@0 105
michael@0 106 nsCacheService * service = nsCacheService::GlobalInstance();
michael@0 107 NS_RELEASE(service);
michael@0 108 }
michael@0 109
michael@0 110
michael@0 111 NS_IMETHODIMP
michael@0 112 nsCacheEntryDescriptor::GetClientID(char ** result)
michael@0 113 {
michael@0 114 NS_ENSURE_ARG_POINTER(result);
michael@0 115
michael@0 116 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETCLIENTID));
michael@0 117 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 118
michael@0 119 return ClientIDFromCacheKey(*(mCacheEntry->Key()), result);
michael@0 120 }
michael@0 121
michael@0 122
michael@0 123 NS_IMETHODIMP
michael@0 124 nsCacheEntryDescriptor::GetDeviceID(char ** aDeviceID)
michael@0 125 {
michael@0 126 NS_ENSURE_ARG_POINTER(aDeviceID);
michael@0 127 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETDEVICEID));
michael@0 128 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 129
michael@0 130 const char* deviceID = mCacheEntry->GetDeviceID();
michael@0 131 if (!deviceID) {
michael@0 132 *aDeviceID = nullptr;
michael@0 133 return NS_OK;
michael@0 134 }
michael@0 135
michael@0 136 *aDeviceID = NS_strdup(deviceID);
michael@0 137 return *aDeviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 138 }
michael@0 139
michael@0 140
michael@0 141 NS_IMETHODIMP
michael@0 142 nsCacheEntryDescriptor::GetKey(nsACString &result)
michael@0 143 {
michael@0 144 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETKEY));
michael@0 145 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 146
michael@0 147 return ClientKeyFromCacheKey(*(mCacheEntry->Key()), result);
michael@0 148 }
michael@0 149
michael@0 150
michael@0 151 NS_IMETHODIMP
michael@0 152 nsCacheEntryDescriptor::GetFetchCount(int32_t *result)
michael@0 153 {
michael@0 154 NS_ENSURE_ARG_POINTER(result);
michael@0 155 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETFETCHCOUNT));
michael@0 156 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 157
michael@0 158 *result = mCacheEntry->FetchCount();
michael@0 159 return NS_OK;
michael@0 160 }
michael@0 161
michael@0 162
michael@0 163 NS_IMETHODIMP
michael@0 164 nsCacheEntryDescriptor::GetLastFetched(uint32_t *result)
michael@0 165 {
michael@0 166 NS_ENSURE_ARG_POINTER(result);
michael@0 167 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETLASTFETCHED));
michael@0 168 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 169
michael@0 170 *result = mCacheEntry->LastFetched();
michael@0 171 return NS_OK;
michael@0 172 }
michael@0 173
michael@0 174
michael@0 175 NS_IMETHODIMP
michael@0 176 nsCacheEntryDescriptor::GetLastModified(uint32_t *result)
michael@0 177 {
michael@0 178 NS_ENSURE_ARG_POINTER(result);
michael@0 179 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETLASTMODIFIED));
michael@0 180 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 181
michael@0 182 *result = mCacheEntry->LastModified();
michael@0 183 return NS_OK;
michael@0 184 }
michael@0 185
michael@0 186
michael@0 187 NS_IMETHODIMP
michael@0 188 nsCacheEntryDescriptor::GetExpirationTime(uint32_t *result)
michael@0 189 {
michael@0 190 NS_ENSURE_ARG_POINTER(result);
michael@0 191 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETEXPIRATIONTIME));
michael@0 192 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 193
michael@0 194 *result = mCacheEntry->ExpirationTime();
michael@0 195 return NS_OK;
michael@0 196 }
michael@0 197
michael@0 198
michael@0 199 NS_IMETHODIMP
michael@0 200 nsCacheEntryDescriptor::SetExpirationTime(uint32_t expirationTime)
michael@0 201 {
michael@0 202 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETEXPIRATIONTIME));
michael@0 203 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 204
michael@0 205 mCacheEntry->SetExpirationTime(expirationTime);
michael@0 206 mCacheEntry->MarkEntryDirty();
michael@0 207 return NS_OK;
michael@0 208 }
michael@0 209
michael@0 210
michael@0 211 NS_IMETHODIMP nsCacheEntryDescriptor::IsStreamBased(bool *result)
michael@0 212 {
michael@0 213 NS_ENSURE_ARG_POINTER(result);
michael@0 214 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_ISSTREAMBASED));
michael@0 215 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 216
michael@0 217 *result = mCacheEntry->IsStreamData();
michael@0 218 return NS_OK;
michael@0 219 }
michael@0 220
michael@0 221 NS_IMETHODIMP nsCacheEntryDescriptor::GetPredictedDataSize(int64_t *result)
michael@0 222 {
michael@0 223 NS_ENSURE_ARG_POINTER(result);
michael@0 224 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETPREDICTEDDATASIZE));
michael@0 225 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 226
michael@0 227 *result = mCacheEntry->PredictedDataSize();
michael@0 228 return NS_OK;
michael@0 229 }
michael@0 230
michael@0 231 NS_IMETHODIMP nsCacheEntryDescriptor::SetPredictedDataSize(int64_t
michael@0 232 predictedSize)
michael@0 233 {
michael@0 234 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETPREDICTEDDATASIZE));
michael@0 235 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 236
michael@0 237 mCacheEntry->SetPredictedDataSize(predictedSize);
michael@0 238 return NS_OK;
michael@0 239 }
michael@0 240
michael@0 241 NS_IMETHODIMP nsCacheEntryDescriptor::GetDataSize(uint32_t *result)
michael@0 242 {
michael@0 243 NS_ENSURE_ARG_POINTER(result);
michael@0 244 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETDATASIZE));
michael@0 245 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 246
michael@0 247 const char* val = mCacheEntry->GetMetaDataElement("uncompressed-len");
michael@0 248 if (!val) {
michael@0 249 *result = mCacheEntry->DataSize();
michael@0 250 } else {
michael@0 251 *result = atol(val);
michael@0 252 }
michael@0 253
michael@0 254 return NS_OK;
michael@0 255 }
michael@0 256
michael@0 257
michael@0 258 NS_IMETHODIMP nsCacheEntryDescriptor::GetStorageDataSize(uint32_t *result)
michael@0 259 {
michael@0 260 NS_ENSURE_ARG_POINTER(result);
michael@0 261 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSTORAGEDATASIZE));
michael@0 262 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 263
michael@0 264 *result = mCacheEntry->DataSize();
michael@0 265
michael@0 266 return NS_OK;
michael@0 267 }
michael@0 268
michael@0 269
michael@0 270 nsresult
michael@0 271 nsCacheEntryDescriptor::RequestDataSizeChange(int32_t deltaSize)
michael@0 272 {
michael@0 273 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_REQUESTDATASIZECHANGE));
michael@0 274 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 275
michael@0 276 nsresult rv;
michael@0 277 rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize);
michael@0 278 if (NS_SUCCEEDED(rv)) {
michael@0 279 // XXX review for signed/unsigned math errors
michael@0 280 uint32_t newDataSize = mCacheEntry->DataSize() + deltaSize;
michael@0 281 mCacheEntry->SetDataSize(newDataSize);
michael@0 282 mCacheEntry->TouchData();
michael@0 283 }
michael@0 284 return rv;
michael@0 285 }
michael@0 286
michael@0 287
michael@0 288 NS_IMETHODIMP
michael@0 289 nsCacheEntryDescriptor::SetDataSize(uint32_t dataSize)
michael@0 290 {
michael@0 291 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETDATASIZE));
michael@0 292 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 293
michael@0 294 // XXX review for signed/unsigned math errors
michael@0 295 int32_t deltaSize = dataSize - mCacheEntry->DataSize();
michael@0 296
michael@0 297 nsresult rv;
michael@0 298 rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize);
michael@0 299 // this had better be NS_OK, this call instance is advisory for memory cache objects
michael@0 300 if (NS_SUCCEEDED(rv)) {
michael@0 301 // XXX review for signed/unsigned math errors
michael@0 302 uint32_t newDataSize = mCacheEntry->DataSize() + deltaSize;
michael@0 303 mCacheEntry->SetDataSize(newDataSize);
michael@0 304 mCacheEntry->TouchData();
michael@0 305 } else {
michael@0 306 NS_WARNING("failed SetDataSize() on memory cache object!");
michael@0 307 }
michael@0 308
michael@0 309 return rv;
michael@0 310 }
michael@0 311
michael@0 312
michael@0 313 NS_IMETHODIMP
michael@0 314 nsCacheEntryDescriptor::OpenInputStream(uint32_t offset, nsIInputStream ** result)
michael@0 315 {
michael@0 316 NS_ENSURE_ARG_POINTER(result);
michael@0 317
michael@0 318 nsInputStreamWrapper* cacheInput = nullptr;
michael@0 319 {
michael@0 320 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_OPENINPUTSTREAM));
michael@0 321 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 322 if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
michael@0 323
michael@0 324 // Don't open any new stream when closing descriptor or clearing entries
michael@0 325 if (mClosingDescriptor || nsCacheService::GetClearingEntries())
michael@0 326 return NS_ERROR_NOT_AVAILABLE;
michael@0 327
michael@0 328 // ensure valid permissions
michael@0 329 if (!(mAccessGranted & nsICache::ACCESS_READ))
michael@0 330 return NS_ERROR_CACHE_READ_ACCESS_DENIED;
michael@0 331
michael@0 332 const char *val;
michael@0 333 val = mCacheEntry->GetMetaDataElement("uncompressed-len");
michael@0 334 if (val) {
michael@0 335 cacheInput = new nsDecompressInputStreamWrapper(this, offset);
michael@0 336 } else {
michael@0 337 cacheInput = new nsInputStreamWrapper(this, offset);
michael@0 338 }
michael@0 339 if (!cacheInput) return NS_ERROR_OUT_OF_MEMORY;
michael@0 340
michael@0 341 mInputWrappers.AppendElement(cacheInput);
michael@0 342 }
michael@0 343
michael@0 344 NS_ADDREF(*result = cacheInput);
michael@0 345 return NS_OK;
michael@0 346 }
michael@0 347
michael@0 348 NS_IMETHODIMP
michael@0 349 nsCacheEntryDescriptor::OpenOutputStream(uint32_t offset, nsIOutputStream ** result)
michael@0 350 {
michael@0 351 NS_ENSURE_ARG_POINTER(result);
michael@0 352
michael@0 353 nsOutputStreamWrapper* cacheOutput = nullptr;
michael@0 354 {
michael@0 355 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_OPENOUTPUTSTREAM));
michael@0 356 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 357 if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
michael@0 358
michael@0 359 // Don't open any new stream when closing descriptor or clearing entries
michael@0 360 if (mClosingDescriptor || nsCacheService::GetClearingEntries())
michael@0 361 return NS_ERROR_NOT_AVAILABLE;
michael@0 362
michael@0 363 // ensure valid permissions
michael@0 364 if (!(mAccessGranted & nsICache::ACCESS_WRITE))
michael@0 365 return NS_ERROR_CACHE_WRITE_ACCESS_DENIED;
michael@0 366
michael@0 367 int32_t compressionLevel = nsCacheService::CacheCompressionLevel();
michael@0 368 const char *val;
michael@0 369 val = mCacheEntry->GetMetaDataElement("uncompressed-len");
michael@0 370 if ((compressionLevel > 0) && val) {
michael@0 371 cacheOutput = new nsCompressOutputStreamWrapper(this, offset);
michael@0 372 } else {
michael@0 373 // clear compression flag when compression disabled - see bug 715198
michael@0 374 if (val) {
michael@0 375 mCacheEntry->SetMetaDataElement("uncompressed-len", nullptr);
michael@0 376 }
michael@0 377 cacheOutput = new nsOutputStreamWrapper(this, offset);
michael@0 378 }
michael@0 379 if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY;
michael@0 380
michael@0 381 mOutputWrapper = cacheOutput;
michael@0 382 }
michael@0 383
michael@0 384 NS_ADDREF(*result = cacheOutput);
michael@0 385 return NS_OK;
michael@0 386 }
michael@0 387
michael@0 388
michael@0 389 NS_IMETHODIMP
michael@0 390 nsCacheEntryDescriptor::GetCacheElement(nsISupports ** result)
michael@0 391 {
michael@0 392 NS_ENSURE_ARG_POINTER(result);
michael@0 393 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETCACHEELEMENT));
michael@0 394 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 395 if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM;
michael@0 396
michael@0 397 NS_IF_ADDREF(*result = mCacheEntry->Data());
michael@0 398 return NS_OK;
michael@0 399 }
michael@0 400
michael@0 401
michael@0 402 NS_IMETHODIMP
michael@0 403 nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement)
michael@0 404 {
michael@0 405 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETCACHEELEMENT));
michael@0 406 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 407 if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM;
michael@0 408
michael@0 409 return nsCacheService::SetCacheElement(mCacheEntry, cacheElement);
michael@0 410 }
michael@0 411
michael@0 412
michael@0 413 NS_IMETHODIMP
michael@0 414 nsCacheEntryDescriptor::GetAccessGranted(nsCacheAccessMode *result)
michael@0 415 {
michael@0 416 NS_ENSURE_ARG_POINTER(result);
michael@0 417 *result = mAccessGranted;
michael@0 418 return NS_OK;
michael@0 419 }
michael@0 420
michael@0 421
michael@0 422 NS_IMETHODIMP
michael@0 423 nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy *result)
michael@0 424 {
michael@0 425 NS_ENSURE_ARG_POINTER(result);
michael@0 426 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSTORAGEPOLICY));
michael@0 427 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 428
michael@0 429 *result = mCacheEntry->StoragePolicy();
michael@0 430 return NS_OK;
michael@0 431 }
michael@0 432
michael@0 433
michael@0 434 NS_IMETHODIMP
michael@0 435 nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy)
michael@0 436 {
michael@0 437 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETSTORAGEPOLICY));
michael@0 438 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 439 // XXX validate policy against session?
michael@0 440
michael@0 441 bool storageEnabled = false;
michael@0 442 storageEnabled = nsCacheService::IsStorageEnabledForPolicy_Locked(policy);
michael@0 443 if (!storageEnabled) return NS_ERROR_FAILURE;
michael@0 444
michael@0 445 // Don't change the storage policy of entries we can't write
michael@0 446 if (!(mAccessGranted & nsICache::ACCESS_WRITE))
michael@0 447 return NS_ERROR_NOT_AVAILABLE;
michael@0 448
michael@0 449 // Don't allow a cache entry to move from memory-only to anything else
michael@0 450 if (mCacheEntry->StoragePolicy() == nsICache::STORE_IN_MEMORY &&
michael@0 451 policy != nsICache::STORE_IN_MEMORY)
michael@0 452 return NS_ERROR_NOT_AVAILABLE;
michael@0 453
michael@0 454 mCacheEntry->SetStoragePolicy(policy);
michael@0 455 mCacheEntry->MarkEntryDirty();
michael@0 456 return NS_OK;
michael@0 457 }
michael@0 458
michael@0 459
michael@0 460 NS_IMETHODIMP
michael@0 461 nsCacheEntryDescriptor::GetFile(nsIFile ** result)
michael@0 462 {
michael@0 463 NS_ENSURE_ARG_POINTER(result);
michael@0 464 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETFILE));
michael@0 465 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 466
michael@0 467 return nsCacheService::GetFileForEntry(mCacheEntry, result);
michael@0 468 }
michael@0 469
michael@0 470
michael@0 471 NS_IMETHODIMP
michael@0 472 nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result)
michael@0 473 {
michael@0 474 NS_ENSURE_ARG_POINTER(result);
michael@0 475 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSECURITYINFO));
michael@0 476 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 477
michael@0 478 *result = mCacheEntry->SecurityInfo();
michael@0 479 NS_IF_ADDREF(*result);
michael@0 480 return NS_OK;
michael@0 481 }
michael@0 482
michael@0 483
michael@0 484 NS_IMETHODIMP
michael@0 485 nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo)
michael@0 486 {
michael@0 487 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETSECURITYINFO));
michael@0 488 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 489
michael@0 490 mCacheEntry->SetSecurityInfo(securityInfo);
michael@0 491 mCacheEntry->MarkEntryDirty();
michael@0 492 return NS_OK;
michael@0 493 }
michael@0 494
michael@0 495
michael@0 496 NS_IMETHODIMP
michael@0 497 nsCacheEntryDescriptor::Doom()
michael@0 498 {
michael@0 499 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_DOOM));
michael@0 500 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 501
michael@0 502 return nsCacheService::DoomEntry(mCacheEntry);
michael@0 503 }
michael@0 504
michael@0 505
michael@0 506 NS_IMETHODIMP
michael@0 507 nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status)
michael@0 508 {
michael@0 509 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_DOOMANDFAILPENDINGREQUESTS));
michael@0 510 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 511
michael@0 512 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 513 }
michael@0 514
michael@0 515
michael@0 516 NS_IMETHODIMP
michael@0 517 nsCacheEntryDescriptor::AsyncDoom(nsICacheListener *listener)
michael@0 518 {
michael@0 519 bool asyncDoomPending;
michael@0 520 {
michael@0 521 mozilla::MutexAutoLock lock(mLock);
michael@0 522 asyncDoomPending = mAsyncDoomPending;
michael@0 523 mAsyncDoomPending = true;
michael@0 524 }
michael@0 525
michael@0 526 if (asyncDoomPending) {
michael@0 527 // AsyncDoom was already called. Notify listener if it is non-null,
michael@0 528 // otherwise just return success.
michael@0 529 if (listener) {
michael@0 530 nsresult rv = NS_DispatchToCurrentThread(
michael@0 531 new nsNotifyDoomListener(listener, NS_ERROR_NOT_AVAILABLE));
michael@0 532 if (NS_SUCCEEDED(rv))
michael@0 533 NS_IF_ADDREF(listener);
michael@0 534 return rv;
michael@0 535 }
michael@0 536 return NS_OK;
michael@0 537 }
michael@0 538
michael@0 539 nsRefPtr<nsIRunnable> event = new nsAsyncDoomEvent(this, listener);
michael@0 540 return nsCacheService::DispatchToCacheIOThread(event);
michael@0 541 }
michael@0 542
michael@0 543
michael@0 544 NS_IMETHODIMP
michael@0 545 nsCacheEntryDescriptor::MarkValid()
michael@0 546 {
michael@0 547 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_MARKVALID));
michael@0 548 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 549
michael@0 550 nsresult rv = nsCacheService::ValidateEntry(mCacheEntry);
michael@0 551 return rv;
michael@0 552 }
michael@0 553
michael@0 554
michael@0 555 NS_IMETHODIMP
michael@0 556 nsCacheEntryDescriptor::Close()
michael@0 557 {
michael@0 558 nsRefPtr<nsOutputStreamWrapper> outputWrapper;
michael@0 559 nsTArray<nsRefPtr<nsInputStreamWrapper> > inputWrappers;
michael@0 560
michael@0 561 {
michael@0 562 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE));
michael@0 563 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 564
michael@0 565 // Make sure no other stream can be opened
michael@0 566 mClosingDescriptor = true;
michael@0 567 outputWrapper = mOutputWrapper;
michael@0 568 for (int32_t i = 0 ; i < mInputWrappers.Count() ; i++)
michael@0 569 inputWrappers.AppendElement(static_cast<nsInputStreamWrapper *>(
michael@0 570 mInputWrappers[i]));
michael@0 571 }
michael@0 572
michael@0 573 // Call Close() on the streams outside the lock since it might need to call
michael@0 574 // methods that grab the cache service lock, e.g. compressed output stream
michael@0 575 // when it finalizes the entry
michael@0 576 if (outputWrapper) {
michael@0 577 if (NS_FAILED(outputWrapper->Close())) {
michael@0 578 NS_WARNING("Dooming entry because Close() failed!!!");
michael@0 579 Doom();
michael@0 580 }
michael@0 581 outputWrapper = nullptr;
michael@0 582 }
michael@0 583
michael@0 584 for (uint32_t i = 0 ; i < inputWrappers.Length() ; i++)
michael@0 585 inputWrappers[i]->Close();
michael@0 586
michael@0 587 inputWrappers.Clear();
michael@0 588
michael@0 589 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE));
michael@0 590 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 591
michael@0 592 // XXX perhaps closing descriptors should clear/sever transports
michael@0 593
michael@0 594 // tell nsCacheService we're going away
michael@0 595 nsCacheService::CloseDescriptor(this);
michael@0 596 NS_ASSERTION(mCacheEntry == nullptr, "mCacheEntry not null");
michael@0 597
michael@0 598 return NS_OK;
michael@0 599 }
michael@0 600
michael@0 601
michael@0 602 NS_IMETHODIMP
michael@0 603 nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char **result)
michael@0 604 {
michael@0 605 NS_ENSURE_ARG_POINTER(key);
michael@0 606 *result = nullptr;
michael@0 607
michael@0 608 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETMETADATAELEMENT));
michael@0 609 NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
michael@0 610
michael@0 611 const char *value;
michael@0 612
michael@0 613 value = mCacheEntry->GetMetaDataElement(key);
michael@0 614 if (!value) return NS_ERROR_NOT_AVAILABLE;
michael@0 615
michael@0 616 *result = NS_strdup(value);
michael@0 617 if (!*result) return NS_ERROR_OUT_OF_MEMORY;
michael@0 618
michael@0 619 return NS_OK;
michael@0 620 }
michael@0 621
michael@0 622
michael@0 623 NS_IMETHODIMP
michael@0 624 nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value)
michael@0 625 {
michael@0 626 NS_ENSURE_ARG_POINTER(key);
michael@0 627
michael@0 628 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETMETADATAELEMENT));
michael@0 629 NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
michael@0 630
michael@0 631 // XXX allow null value, for clearing key?
michael@0 632
michael@0 633 nsresult rv = mCacheEntry->SetMetaDataElement(key, value);
michael@0 634 if (NS_SUCCEEDED(rv))
michael@0 635 mCacheEntry->TouchMetaData();
michael@0 636 return rv;
michael@0 637 }
michael@0 638
michael@0 639
michael@0 640 NS_IMETHODIMP
michael@0 641 nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor)
michael@0 642 {
michael@0 643 nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_VISITMETADATA));
michael@0 644 // XXX check callers, we're calling out of module
michael@0 645 NS_ENSURE_ARG_POINTER(visitor);
michael@0 646 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 647
michael@0 648 return mCacheEntry->VisitMetaDataElements(visitor);
michael@0 649 }
michael@0 650
michael@0 651
michael@0 652 /******************************************************************************
michael@0 653 * nsCacheInputStream - a wrapper for nsIInputStream keeps the cache entry
michael@0 654 * open while referenced.
michael@0 655 ******************************************************************************/
michael@0 656
michael@0 657 NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsInputStreamWrapper)
michael@0 658 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 659 nsCacheEntryDescriptor::nsInputStreamWrapper::Release()
michael@0 660 {
michael@0 661 // Holding a reference to descriptor ensures that cache service won't go
michael@0 662 // away. Do not grab cache service lock if there is no descriptor.
michael@0 663 nsRefPtr<nsCacheEntryDescriptor> desc;
michael@0 664
michael@0 665 {
michael@0 666 mozilla::MutexAutoLock lock(mLock);
michael@0 667 desc = mDescriptor;
michael@0 668 }
michael@0 669
michael@0 670 if (desc)
michael@0 671 nsCacheService::Lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_RELEASE));
michael@0 672
michael@0 673 nsrefcnt count;
michael@0 674 NS_PRECONDITION(0 != mRefCnt, "dup release");
michael@0 675 count = --mRefCnt;
michael@0 676 NS_LOG_RELEASE(this, count, "nsCacheEntryDescriptor::nsInputStreamWrapper");
michael@0 677
michael@0 678 if (0 == count) {
michael@0 679 // don't use desc here since mDescriptor might be already nulled out
michael@0 680 if (mDescriptor) {
michael@0 681 NS_ASSERTION(mDescriptor->mInputWrappers.IndexOf(this) != -1,
michael@0 682 "Wrapper not found in array!");
michael@0 683 mDescriptor->mInputWrappers.RemoveElement(this);
michael@0 684 }
michael@0 685
michael@0 686 if (desc)
michael@0 687 nsCacheService::Unlock();
michael@0 688
michael@0 689 mRefCnt = 1;
michael@0 690 delete (this);
michael@0 691 return 0;
michael@0 692 }
michael@0 693
michael@0 694 if (desc)
michael@0 695 nsCacheService::Unlock();
michael@0 696
michael@0 697 return count;
michael@0 698 }
michael@0 699
michael@0 700 NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsInputStreamWrapper)
michael@0 701 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
michael@0 702 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 703 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 704
michael@0 705 nsresult nsCacheEntryDescriptor::
michael@0 706 nsInputStreamWrapper::LazyInit()
michael@0 707 {
michael@0 708 // Check if we have the descriptor. If not we can't even grab the cache
michael@0 709 // lock since it is not ensured that the cache service still exists.
michael@0 710 if (!mDescriptor)
michael@0 711 return NS_ERROR_NOT_AVAILABLE;
michael@0 712
michael@0 713 nsCacheServiceAutoLock lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_LAZYINIT));
michael@0 714
michael@0 715 nsCacheAccessMode mode;
michael@0 716 nsresult rv = mDescriptor->GetAccessGranted(&mode);
michael@0 717 if (NS_FAILED(rv)) return rv;
michael@0 718
michael@0 719 NS_ENSURE_TRUE(mode & nsICache::ACCESS_READ, NS_ERROR_UNEXPECTED);
michael@0 720
michael@0 721 nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
michael@0 722 if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 723
michael@0 724 rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode,
michael@0 725 mStartOffset,
michael@0 726 getter_AddRefs(mInput));
michael@0 727
michael@0 728 CACHE_LOG_DEBUG(("nsInputStreamWrapper::LazyInit "
michael@0 729 "[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
michael@0 730 mDescriptor, this, mInput.get(), int(rv)));
michael@0 731
michael@0 732 if (NS_FAILED(rv)) return rv;
michael@0 733
michael@0 734 mInitialized = true;
michael@0 735 return NS_OK;
michael@0 736 }
michael@0 737
michael@0 738 nsresult nsCacheEntryDescriptor::
michael@0 739 nsInputStreamWrapper::EnsureInit()
michael@0 740 {
michael@0 741 if (mInitialized) {
michael@0 742 NS_ASSERTION(mDescriptor, "Bad state");
michael@0 743 return NS_OK;
michael@0 744 }
michael@0 745
michael@0 746 return LazyInit();
michael@0 747 }
michael@0 748
michael@0 749 void nsCacheEntryDescriptor::
michael@0 750 nsInputStreamWrapper::CloseInternal()
michael@0 751 {
michael@0 752 mLock.AssertCurrentThreadOwns();
michael@0 753 if (!mDescriptor) {
michael@0 754 NS_ASSERTION(!mInitialized, "Bad state");
michael@0 755 NS_ASSERTION(!mInput, "Bad state");
michael@0 756 return;
michael@0 757 }
michael@0 758
michael@0 759 nsCacheServiceAutoLock lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_CLOSEINTERNAL));
michael@0 760
michael@0 761 if (mDescriptor) {
michael@0 762 mDescriptor->mInputWrappers.RemoveElement(this);
michael@0 763 nsCacheService::ReleaseObject_Locked(mDescriptor);
michael@0 764 mDescriptor = nullptr;
michael@0 765 }
michael@0 766 mInitialized = false;
michael@0 767 mInput = nullptr;
michael@0 768 }
michael@0 769
michael@0 770 nsresult nsCacheEntryDescriptor::
michael@0 771 nsInputStreamWrapper::Close()
michael@0 772 {
michael@0 773 mozilla::MutexAutoLock lock(mLock);
michael@0 774
michael@0 775 return Close_Locked();
michael@0 776 }
michael@0 777
michael@0 778 nsresult nsCacheEntryDescriptor::
michael@0 779 nsInputStreamWrapper::Close_Locked()
michael@0 780 {
michael@0 781 nsresult rv = EnsureInit();
michael@0 782 if (NS_SUCCEEDED(rv)) {
michael@0 783 rv = mInput->Close();
michael@0 784 } else {
michael@0 785 NS_ASSERTION(!mInput,
michael@0 786 "Shouldn't have mInput when EnsureInit() failed");
michael@0 787 }
michael@0 788
michael@0 789 // Call CloseInternal() even when EnsureInit() failed, e.g. in case we are
michael@0 790 // closing streams with nsCacheService::CloseAllStream()
michael@0 791 CloseInternal();
michael@0 792 return rv;
michael@0 793 }
michael@0 794
michael@0 795 nsresult nsCacheEntryDescriptor::
michael@0 796 nsInputStreamWrapper::Available(uint64_t *avail)
michael@0 797 {
michael@0 798 mozilla::MutexAutoLock lock(mLock);
michael@0 799
michael@0 800 nsresult rv = EnsureInit();
michael@0 801 if (NS_FAILED(rv)) return rv;
michael@0 802
michael@0 803 return mInput->Available(avail);
michael@0 804 }
michael@0 805
michael@0 806 nsresult nsCacheEntryDescriptor::
michael@0 807 nsInputStreamWrapper::Read(char *buf, uint32_t count, uint32_t *countRead)
michael@0 808 {
michael@0 809 mozilla::MutexAutoLock lock(mLock);
michael@0 810
michael@0 811 return Read_Locked(buf, count, countRead);
michael@0 812 }
michael@0 813
michael@0 814 nsresult nsCacheEntryDescriptor::
michael@0 815 nsInputStreamWrapper::Read_Locked(char *buf, uint32_t count, uint32_t *countRead)
michael@0 816 {
michael@0 817 nsresult rv = EnsureInit();
michael@0 818 if (NS_SUCCEEDED(rv))
michael@0 819 rv = mInput->Read(buf, count, countRead);
michael@0 820
michael@0 821 CACHE_LOG_DEBUG(("nsInputStreamWrapper::Read "
michael@0 822 "[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
michael@0 823 mDescriptor, this, mInput.get(), rv));
michael@0 824
michael@0 825 return rv;
michael@0 826 }
michael@0 827
michael@0 828 nsresult nsCacheEntryDescriptor::
michael@0 829 nsInputStreamWrapper::ReadSegments(nsWriteSegmentFun writer, void *closure,
michael@0 830 uint32_t count, uint32_t *countRead)
michael@0 831 {
michael@0 832 // cache stream not buffered
michael@0 833 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 834 }
michael@0 835
michael@0 836 nsresult nsCacheEntryDescriptor::
michael@0 837 nsInputStreamWrapper::IsNonBlocking(bool *result)
michael@0 838 {
michael@0 839 // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
michael@0 840 *result = false;
michael@0 841 return NS_OK;
michael@0 842 }
michael@0 843
michael@0 844
michael@0 845 /******************************************************************************
michael@0 846 * nsDecompressInputStreamWrapper - an input stream wrapper that decompresses
michael@0 847 ******************************************************************************/
michael@0 848
michael@0 849 NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsDecompressInputStreamWrapper)
michael@0 850 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 851 nsCacheEntryDescriptor::nsDecompressInputStreamWrapper::Release()
michael@0 852 {
michael@0 853 // Holding a reference to descriptor ensures that cache service won't go
michael@0 854 // away. Do not grab cache service lock if there is no descriptor.
michael@0 855 nsRefPtr<nsCacheEntryDescriptor> desc;
michael@0 856
michael@0 857 {
michael@0 858 mozilla::MutexAutoLock lock(mLock);
michael@0 859 desc = mDescriptor;
michael@0 860 }
michael@0 861
michael@0 862 if (desc)
michael@0 863 nsCacheService::Lock(LOCK_TELEM(
michael@0 864 NSDECOMPRESSINPUTSTREAMWRAPPER_RELEASE));
michael@0 865
michael@0 866 nsrefcnt count;
michael@0 867 NS_PRECONDITION(0 != mRefCnt, "dup release");
michael@0 868 count = --mRefCnt;
michael@0 869 NS_LOG_RELEASE(this, count,
michael@0 870 "nsCacheEntryDescriptor::nsDecompressInputStreamWrapper");
michael@0 871
michael@0 872 if (0 == count) {
michael@0 873 // don't use desc here since mDescriptor might be already nulled out
michael@0 874 if (mDescriptor) {
michael@0 875 NS_ASSERTION(mDescriptor->mInputWrappers.IndexOf(this) != -1,
michael@0 876 "Wrapper not found in array!");
michael@0 877 mDescriptor->mInputWrappers.RemoveElement(this);
michael@0 878 }
michael@0 879
michael@0 880 if (desc)
michael@0 881 nsCacheService::Unlock();
michael@0 882
michael@0 883 mRefCnt = 1;
michael@0 884 delete (this);
michael@0 885 return 0;
michael@0 886 }
michael@0 887
michael@0 888 if (desc)
michael@0 889 nsCacheService::Unlock();
michael@0 890
michael@0 891 return count;
michael@0 892 }
michael@0 893
michael@0 894 NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsDecompressInputStreamWrapper)
michael@0 895 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
michael@0 896 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 897 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 898
michael@0 899 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 900 nsDecompressInputStreamWrapper::Read(char * buf,
michael@0 901 uint32_t count,
michael@0 902 uint32_t *countRead)
michael@0 903 {
michael@0 904 mozilla::MutexAutoLock lock(mLock);
michael@0 905
michael@0 906 int zerr = Z_OK;
michael@0 907 nsresult rv = NS_OK;
michael@0 908
michael@0 909 if (!mStreamInitialized) {
michael@0 910 rv = InitZstream();
michael@0 911 if (NS_FAILED(rv)) {
michael@0 912 return rv;
michael@0 913 }
michael@0 914 }
michael@0 915
michael@0 916 mZstream.next_out = (Bytef*)buf;
michael@0 917 mZstream.avail_out = count;
michael@0 918
michael@0 919 if (mReadBufferLen < count) {
michael@0 920 // Allocate a buffer for reading from the input stream. This will
michael@0 921 // determine the max number of compressed bytes read from the
michael@0 922 // input stream at one time. Making the buffer size proportional
michael@0 923 // to the request size is not necessary, but helps minimize the
michael@0 924 // number of read requests to the input stream.
michael@0 925 uint32_t newBufLen = std::max(count, (uint32_t)kMinDecompressReadBufLen);
michael@0 926 unsigned char* newBuf;
michael@0 927 newBuf = (unsigned char*)nsMemory::Realloc(mReadBuffer,
michael@0 928 newBufLen);
michael@0 929 if (newBuf) {
michael@0 930 mReadBuffer = newBuf;
michael@0 931 mReadBufferLen = newBufLen;
michael@0 932 }
michael@0 933 if (!mReadBuffer) {
michael@0 934 mReadBufferLen = 0;
michael@0 935 return NS_ERROR_OUT_OF_MEMORY;
michael@0 936 }
michael@0 937 }
michael@0 938
michael@0 939 // read and inflate data until the output buffer is full, or
michael@0 940 // there is no more data to read
michael@0 941 while (NS_SUCCEEDED(rv) &&
michael@0 942 zerr == Z_OK &&
michael@0 943 mZstream.avail_out > 0 &&
michael@0 944 count > 0) {
michael@0 945 if (mZstream.avail_in == 0) {
michael@0 946 rv = nsInputStreamWrapper::Read_Locked((char*)mReadBuffer,
michael@0 947 mReadBufferLen,
michael@0 948 &mZstream.avail_in);
michael@0 949 if (NS_FAILED(rv) || !mZstream.avail_in) {
michael@0 950 break;
michael@0 951 }
michael@0 952 mZstream.next_in = mReadBuffer;
michael@0 953 }
michael@0 954 zerr = inflate(&mZstream, Z_NO_FLUSH);
michael@0 955 if (zerr == Z_STREAM_END) {
michael@0 956 // The compressed data may have been stored in multiple
michael@0 957 // chunks/streams. To allow for this case, re-initialize
michael@0 958 // the inflate stream and continue decompressing from
michael@0 959 // the next byte.
michael@0 960 Bytef * saveNextIn = mZstream.next_in;
michael@0 961 unsigned int saveAvailIn = mZstream.avail_in;
michael@0 962 Bytef * saveNextOut = mZstream.next_out;
michael@0 963 unsigned int saveAvailOut = mZstream.avail_out;
michael@0 964 inflateReset(&mZstream);
michael@0 965 mZstream.next_in = saveNextIn;
michael@0 966 mZstream.avail_in = saveAvailIn;
michael@0 967 mZstream.next_out = saveNextOut;
michael@0 968 mZstream.avail_out = saveAvailOut;
michael@0 969 zerr = Z_OK;
michael@0 970 } else if (zerr != Z_OK) {
michael@0 971 rv = NS_ERROR_INVALID_CONTENT_ENCODING;
michael@0 972 }
michael@0 973 }
michael@0 974 if (NS_SUCCEEDED(rv)) {
michael@0 975 *countRead = count - mZstream.avail_out;
michael@0 976 }
michael@0 977 return rv;
michael@0 978 }
michael@0 979
michael@0 980 nsresult nsCacheEntryDescriptor::
michael@0 981 nsDecompressInputStreamWrapper::Close()
michael@0 982 {
michael@0 983 mozilla::MutexAutoLock lock(mLock);
michael@0 984
michael@0 985 if (!mDescriptor)
michael@0 986 return NS_ERROR_NOT_AVAILABLE;
michael@0 987
michael@0 988 EndZstream();
michael@0 989 if (mReadBuffer) {
michael@0 990 nsMemory::Free(mReadBuffer);
michael@0 991 mReadBuffer = 0;
michael@0 992 mReadBufferLen = 0;
michael@0 993 }
michael@0 994 return nsInputStreamWrapper::Close_Locked();
michael@0 995 }
michael@0 996
michael@0 997 nsresult nsCacheEntryDescriptor::
michael@0 998 nsDecompressInputStreamWrapper::InitZstream()
michael@0 999 {
michael@0 1000 if (!mDescriptor)
michael@0 1001 return NS_ERROR_NOT_AVAILABLE;
michael@0 1002
michael@0 1003 if (mStreamEnded)
michael@0 1004 return NS_ERROR_FAILURE;
michael@0 1005
michael@0 1006 // Initialize zlib inflate stream
michael@0 1007 mZstream.zalloc = Z_NULL;
michael@0 1008 mZstream.zfree = Z_NULL;
michael@0 1009 mZstream.opaque = Z_NULL;
michael@0 1010 mZstream.next_out = Z_NULL;
michael@0 1011 mZstream.avail_out = 0;
michael@0 1012 mZstream.next_in = Z_NULL;
michael@0 1013 mZstream.avail_in = 0;
michael@0 1014 if (inflateInit(&mZstream) != Z_OK) {
michael@0 1015 return NS_ERROR_FAILURE;
michael@0 1016 }
michael@0 1017 mStreamInitialized = true;
michael@0 1018 return NS_OK;
michael@0 1019 }
michael@0 1020
michael@0 1021 nsresult nsCacheEntryDescriptor::
michael@0 1022 nsDecompressInputStreamWrapper::EndZstream()
michael@0 1023 {
michael@0 1024 if (mStreamInitialized && !mStreamEnded) {
michael@0 1025 inflateEnd(&mZstream);
michael@0 1026 mStreamInitialized = false;
michael@0 1027 mStreamEnded = true;
michael@0 1028 }
michael@0 1029 return NS_OK;
michael@0 1030 }
michael@0 1031
michael@0 1032
michael@0 1033 /******************************************************************************
michael@0 1034 * nsOutputStreamWrapper - a wrapper for nsIOutputstream to track the amount of
michael@0 1035 * data written to a cache entry.
michael@0 1036 * - also keeps the cache entry open while referenced.
michael@0 1037 ******************************************************************************/
michael@0 1038
michael@0 1039 NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsOutputStreamWrapper)
michael@0 1040 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 1041 nsCacheEntryDescriptor::nsOutputStreamWrapper::Release()
michael@0 1042 {
michael@0 1043 // Holding a reference to descriptor ensures that cache service won't go
michael@0 1044 // away. Do not grab cache service lock if there is no descriptor.
michael@0 1045 nsRefPtr<nsCacheEntryDescriptor> desc;
michael@0 1046
michael@0 1047 {
michael@0 1048 mozilla::MutexAutoLock lock(mLock);
michael@0 1049 desc = mDescriptor;
michael@0 1050 }
michael@0 1051
michael@0 1052 if (desc)
michael@0 1053 nsCacheService::Lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_RELEASE));
michael@0 1054
michael@0 1055 nsrefcnt count;
michael@0 1056 NS_PRECONDITION(0 != mRefCnt, "dup release");
michael@0 1057 count = --mRefCnt;
michael@0 1058 NS_LOG_RELEASE(this, count,
michael@0 1059 "nsCacheEntryDescriptor::nsOutputStreamWrapper");
michael@0 1060
michael@0 1061 if (0 == count) {
michael@0 1062 // don't use desc here since mDescriptor might be already nulled out
michael@0 1063 if (mDescriptor)
michael@0 1064 mDescriptor->mOutputWrapper = nullptr;
michael@0 1065
michael@0 1066 if (desc)
michael@0 1067 nsCacheService::Unlock();
michael@0 1068
michael@0 1069 mRefCnt = 1;
michael@0 1070 delete (this);
michael@0 1071 return 0;
michael@0 1072 }
michael@0 1073
michael@0 1074 if (desc)
michael@0 1075 nsCacheService::Unlock();
michael@0 1076
michael@0 1077 return count;
michael@0 1078 }
michael@0 1079
michael@0 1080 NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsOutputStreamWrapper)
michael@0 1081 NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
michael@0 1082 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 1083 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 1084
michael@0 1085 nsresult nsCacheEntryDescriptor::
michael@0 1086 nsOutputStreamWrapper::LazyInit()
michael@0 1087 {
michael@0 1088 // Check if we have the descriptor. If not we can't even grab the cache
michael@0 1089 // lock since it is not ensured that the cache service still exists.
michael@0 1090 if (!mDescriptor)
michael@0 1091 return NS_ERROR_NOT_AVAILABLE;
michael@0 1092
michael@0 1093 nsCacheServiceAutoLock lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_LAZYINIT));
michael@0 1094
michael@0 1095 nsCacheAccessMode mode;
michael@0 1096 nsresult rv = mDescriptor->GetAccessGranted(&mode);
michael@0 1097 if (NS_FAILED(rv)) return rv;
michael@0 1098
michael@0 1099 NS_ENSURE_TRUE(mode & nsICache::ACCESS_WRITE, NS_ERROR_UNEXPECTED);
michael@0 1100
michael@0 1101 nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
michael@0 1102 if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 1103
michael@0 1104 NS_ASSERTION(mOutput == nullptr, "mOutput set in LazyInit");
michael@0 1105
michael@0 1106 nsCOMPtr<nsIOutputStream> stream;
michael@0 1107 rv = nsCacheService::OpenOutputStreamForEntry(cacheEntry, mode, mStartOffset,
michael@0 1108 getter_AddRefs(stream));
michael@0 1109 if (NS_FAILED(rv))
michael@0 1110 return rv;
michael@0 1111
michael@0 1112 nsCacheDevice* device = cacheEntry->CacheDevice();
michael@0 1113 if (device) {
michael@0 1114 // the entry has been truncated to mStartOffset bytes, inform device
michael@0 1115 int32_t size = cacheEntry->DataSize();
michael@0 1116 rv = device->OnDataSizeChange(cacheEntry, mStartOffset - size);
michael@0 1117 if (NS_SUCCEEDED(rv))
michael@0 1118 cacheEntry->SetDataSize(mStartOffset);
michael@0 1119 } else {
michael@0 1120 rv = NS_ERROR_NOT_AVAILABLE;
michael@0 1121 }
michael@0 1122
michael@0 1123 // If anything above failed, clean up internal state and get out of here
michael@0 1124 // (see bug #654926)...
michael@0 1125 if (NS_FAILED(rv)) {
michael@0 1126 nsCacheService::ReleaseObject_Locked(stream.forget().take());
michael@0 1127 mDescriptor->mOutputWrapper = nullptr;
michael@0 1128 nsCacheService::ReleaseObject_Locked(mDescriptor);
michael@0 1129 mDescriptor = nullptr;
michael@0 1130 mInitialized = false;
michael@0 1131 return rv;
michael@0 1132 }
michael@0 1133
michael@0 1134 mOutput = stream;
michael@0 1135 mInitialized = true;
michael@0 1136 return NS_OK;
michael@0 1137 }
michael@0 1138
michael@0 1139 nsresult nsCacheEntryDescriptor::
michael@0 1140 nsOutputStreamWrapper::EnsureInit()
michael@0 1141 {
michael@0 1142 if (mInitialized) {
michael@0 1143 NS_ASSERTION(mDescriptor, "Bad state");
michael@0 1144 return NS_OK;
michael@0 1145 }
michael@0 1146
michael@0 1147 return LazyInit();
michael@0 1148 }
michael@0 1149
michael@0 1150 nsresult nsCacheEntryDescriptor::
michael@0 1151 nsOutputStreamWrapper::OnWrite(uint32_t count)
michael@0 1152 {
michael@0 1153 if (count > INT32_MAX) return NS_ERROR_UNEXPECTED;
michael@0 1154 return mDescriptor->RequestDataSizeChange((int32_t)count);
michael@0 1155 }
michael@0 1156
michael@0 1157 void nsCacheEntryDescriptor::
michael@0 1158 nsOutputStreamWrapper::CloseInternal()
michael@0 1159 {
michael@0 1160 mLock.AssertCurrentThreadOwns();
michael@0 1161 if (!mDescriptor) {
michael@0 1162 NS_ASSERTION(!mInitialized, "Bad state");
michael@0 1163 NS_ASSERTION(!mOutput, "Bad state");
michael@0 1164 return;
michael@0 1165 }
michael@0 1166
michael@0 1167 nsCacheServiceAutoLock lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_CLOSEINTERNAL));
michael@0 1168
michael@0 1169 if (mDescriptor) {
michael@0 1170 mDescriptor->mOutputWrapper = nullptr;
michael@0 1171 nsCacheService::ReleaseObject_Locked(mDescriptor);
michael@0 1172 mDescriptor = nullptr;
michael@0 1173 }
michael@0 1174 mInitialized = false;
michael@0 1175 mOutput = nullptr;
michael@0 1176 }
michael@0 1177
michael@0 1178
michael@0 1179 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1180 nsOutputStreamWrapper::Close()
michael@0 1181 {
michael@0 1182 mozilla::MutexAutoLock lock(mLock);
michael@0 1183
michael@0 1184 return Close_Locked();
michael@0 1185 }
michael@0 1186
michael@0 1187 nsresult nsCacheEntryDescriptor::
michael@0 1188 nsOutputStreamWrapper::Close_Locked()
michael@0 1189 {
michael@0 1190 nsresult rv = EnsureInit();
michael@0 1191 if (NS_SUCCEEDED(rv)) {
michael@0 1192 rv = mOutput->Close();
michael@0 1193 } else {
michael@0 1194 NS_ASSERTION(!mOutput,
michael@0 1195 "Shouldn't have mOutput when EnsureInit() failed");
michael@0 1196 }
michael@0 1197
michael@0 1198 // Call CloseInternal() even when EnsureInit() failed, e.g. in case we are
michael@0 1199 // closing streams with nsCacheService::CloseAllStream()
michael@0 1200 CloseInternal();
michael@0 1201 return rv;
michael@0 1202 }
michael@0 1203
michael@0 1204 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1205 nsOutputStreamWrapper::Flush()
michael@0 1206 {
michael@0 1207 mozilla::MutexAutoLock lock(mLock);
michael@0 1208
michael@0 1209 nsresult rv = EnsureInit();
michael@0 1210 if (NS_FAILED(rv)) return rv;
michael@0 1211
michael@0 1212 return mOutput->Flush();
michael@0 1213 }
michael@0 1214
michael@0 1215 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1216 nsOutputStreamWrapper::Write(const char * buf,
michael@0 1217 uint32_t count,
michael@0 1218 uint32_t * result)
michael@0 1219 {
michael@0 1220 mozilla::MutexAutoLock lock(mLock);
michael@0 1221 return Write_Locked(buf, count, result);
michael@0 1222 }
michael@0 1223
michael@0 1224 nsresult nsCacheEntryDescriptor::
michael@0 1225 nsOutputStreamWrapper::Write_Locked(const char * buf,
michael@0 1226 uint32_t count,
michael@0 1227 uint32_t * result)
michael@0 1228 {
michael@0 1229 nsresult rv = EnsureInit();
michael@0 1230 if (NS_FAILED(rv)) return rv;
michael@0 1231
michael@0 1232 rv = OnWrite(count);
michael@0 1233 if (NS_FAILED(rv)) return rv;
michael@0 1234
michael@0 1235 return mOutput->Write(buf, count, result);
michael@0 1236 }
michael@0 1237
michael@0 1238 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1239 nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr,
michael@0 1240 uint32_t count,
michael@0 1241 uint32_t * result)
michael@0 1242 {
michael@0 1243 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1244 }
michael@0 1245
michael@0 1246 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1247 nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader,
michael@0 1248 void * closure,
michael@0 1249 uint32_t count,
michael@0 1250 uint32_t * result)
michael@0 1251 {
michael@0 1252 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1253 }
michael@0 1254
michael@0 1255 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1256 nsOutputStreamWrapper::IsNonBlocking(bool *result)
michael@0 1257 {
michael@0 1258 // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
michael@0 1259 *result = false;
michael@0 1260 return NS_OK;
michael@0 1261 }
michael@0 1262
michael@0 1263
michael@0 1264 /******************************************************************************
michael@0 1265 * nsCompressOutputStreamWrapper - an output stream wrapper that compresses
michael@0 1266 * data before it is written
michael@0 1267 ******************************************************************************/
michael@0 1268
michael@0 1269 NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsCompressOutputStreamWrapper)
michael@0 1270 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 1271 nsCacheEntryDescriptor::nsCompressOutputStreamWrapper::Release()
michael@0 1272 {
michael@0 1273 // Holding a reference to descriptor ensures that cache service won't go
michael@0 1274 // away. Do not grab cache service lock if there is no descriptor.
michael@0 1275 nsRefPtr<nsCacheEntryDescriptor> desc;
michael@0 1276
michael@0 1277 {
michael@0 1278 mozilla::MutexAutoLock lock(mLock);
michael@0 1279 desc = mDescriptor;
michael@0 1280 }
michael@0 1281
michael@0 1282 if (desc)
michael@0 1283 nsCacheService::Lock(LOCK_TELEM(NSCOMPRESSOUTPUTSTREAMWRAPPER_RELEASE));
michael@0 1284
michael@0 1285 nsrefcnt count;
michael@0 1286 NS_PRECONDITION(0 != mRefCnt, "dup release");
michael@0 1287 count = --mRefCnt;
michael@0 1288 NS_LOG_RELEASE(this, count,
michael@0 1289 "nsCacheEntryDescriptor::nsCompressOutputStreamWrapper");
michael@0 1290
michael@0 1291 if (0 == count) {
michael@0 1292 // don't use desc here since mDescriptor might be already nulled out
michael@0 1293 if (mDescriptor)
michael@0 1294 mDescriptor->mOutputWrapper = nullptr;
michael@0 1295
michael@0 1296 if (desc)
michael@0 1297 nsCacheService::Unlock();
michael@0 1298
michael@0 1299 mRefCnt = 1;
michael@0 1300 delete (this);
michael@0 1301 return 0;
michael@0 1302 }
michael@0 1303
michael@0 1304 if (desc)
michael@0 1305 nsCacheService::Unlock();
michael@0 1306
michael@0 1307 return count;
michael@0 1308 }
michael@0 1309
michael@0 1310 NS_INTERFACE_MAP_BEGIN(nsCacheEntryDescriptor::nsCompressOutputStreamWrapper)
michael@0 1311 NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
michael@0 1312 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 1313 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 1314
michael@0 1315 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1316 nsCompressOutputStreamWrapper::Write(const char * buf,
michael@0 1317 uint32_t count,
michael@0 1318 uint32_t * result)
michael@0 1319 {
michael@0 1320 mozilla::MutexAutoLock lock(mLock);
michael@0 1321
michael@0 1322 int zerr = Z_OK;
michael@0 1323 nsresult rv = NS_OK;
michael@0 1324
michael@0 1325 if (!mStreamInitialized) {
michael@0 1326 rv = InitZstream();
michael@0 1327 if (NS_FAILED(rv)) {
michael@0 1328 return rv;
michael@0 1329 }
michael@0 1330 }
michael@0 1331
michael@0 1332 if (!mWriteBuffer) {
michael@0 1333 // Once allocated, this buffer is referenced by the zlib stream and
michael@0 1334 // cannot be grown. We use 2x(initial write request) to approximate
michael@0 1335 // a stream buffer size proportional to request buffers.
michael@0 1336 mWriteBufferLen = std::max(count*2, (uint32_t)kMinCompressWriteBufLen);
michael@0 1337 mWriteBuffer = (unsigned char*)nsMemory::Alloc(mWriteBufferLen);
michael@0 1338 if (!mWriteBuffer) {
michael@0 1339 mWriteBufferLen = 0;
michael@0 1340 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1341 }
michael@0 1342 mZstream.next_out = mWriteBuffer;
michael@0 1343 mZstream.avail_out = mWriteBufferLen;
michael@0 1344 }
michael@0 1345
michael@0 1346 // Compress (deflate) the requested buffer. Keep going
michael@0 1347 // until the entire buffer has been deflated.
michael@0 1348 mZstream.avail_in = count;
michael@0 1349 mZstream.next_in = (Bytef*)buf;
michael@0 1350 while (mZstream.avail_in > 0) {
michael@0 1351 zerr = deflate(&mZstream, Z_NO_FLUSH);
michael@0 1352 if (zerr == Z_STREAM_ERROR) {
michael@0 1353 deflateEnd(&mZstream);
michael@0 1354 mStreamEnded = true;
michael@0 1355 mStreamInitialized = false;
michael@0 1356 return NS_ERROR_FAILURE;
michael@0 1357 }
michael@0 1358 // Note: Z_BUF_ERROR is non-fatal and sometimes expected here.
michael@0 1359
michael@0 1360 // If the compression stream output buffer is filled, write
michael@0 1361 // it out to the underlying stream wrapper.
michael@0 1362 if (mZstream.avail_out == 0) {
michael@0 1363 rv = WriteBuffer();
michael@0 1364 if (NS_FAILED(rv)) {
michael@0 1365 deflateEnd(&mZstream);
michael@0 1366 mStreamEnded = true;
michael@0 1367 mStreamInitialized = false;
michael@0 1368 return rv;
michael@0 1369 }
michael@0 1370 }
michael@0 1371 }
michael@0 1372 *result = count;
michael@0 1373 mUncompressedCount += *result;
michael@0 1374 return NS_OK;
michael@0 1375 }
michael@0 1376
michael@0 1377 NS_IMETHODIMP nsCacheEntryDescriptor::
michael@0 1378 nsCompressOutputStreamWrapper::Close()
michael@0 1379 {
michael@0 1380 mozilla::MutexAutoLock lock(mLock);
michael@0 1381
michael@0 1382 if (!mDescriptor)
michael@0 1383 return NS_ERROR_NOT_AVAILABLE;
michael@0 1384
michael@0 1385 nsresult retval = NS_OK;
michael@0 1386 nsresult rv;
michael@0 1387 int zerr = 0;
michael@0 1388
michael@0 1389 if (mStreamInitialized) {
michael@0 1390 // complete compression of any data remaining in the zlib stream
michael@0 1391 do {
michael@0 1392 zerr = deflate(&mZstream, Z_FINISH);
michael@0 1393 rv = WriteBuffer();
michael@0 1394 if (NS_FAILED(rv))
michael@0 1395 retval = rv;
michael@0 1396 } while (zerr == Z_OK && rv == NS_OK);
michael@0 1397 deflateEnd(&mZstream);
michael@0 1398 mStreamInitialized = false;
michael@0 1399 }
michael@0 1400 // Do not allow to initialize stream after calling Close().
michael@0 1401 mStreamEnded = true;
michael@0 1402
michael@0 1403 if (mDescriptor->CacheEntry()) {
michael@0 1404 nsAutoCString uncompressedLenStr;
michael@0 1405 rv = mDescriptor->GetMetaDataElement("uncompressed-len",
michael@0 1406 getter_Copies(uncompressedLenStr));
michael@0 1407 if (NS_SUCCEEDED(rv)) {
michael@0 1408 int32_t oldCount = uncompressedLenStr.ToInteger(&rv);
michael@0 1409 if (NS_SUCCEEDED(rv)) {
michael@0 1410 mUncompressedCount += oldCount;
michael@0 1411 }
michael@0 1412 }
michael@0 1413 uncompressedLenStr.Adopt(0);
michael@0 1414 uncompressedLenStr.AppendInt(mUncompressedCount);
michael@0 1415 rv = mDescriptor->SetMetaDataElement("uncompressed-len",
michael@0 1416 uncompressedLenStr.get());
michael@0 1417 if (NS_FAILED(rv))
michael@0 1418 retval = rv;
michael@0 1419 }
michael@0 1420
michael@0 1421 if (mWriteBuffer) {
michael@0 1422 nsMemory::Free(mWriteBuffer);
michael@0 1423 mWriteBuffer = 0;
michael@0 1424 mWriteBufferLen = 0;
michael@0 1425 }
michael@0 1426
michael@0 1427 rv = nsOutputStreamWrapper::Close_Locked();
michael@0 1428 if (NS_FAILED(rv))
michael@0 1429 retval = rv;
michael@0 1430
michael@0 1431 return retval;
michael@0 1432 }
michael@0 1433
michael@0 1434 nsresult nsCacheEntryDescriptor::
michael@0 1435 nsCompressOutputStreamWrapper::InitZstream()
michael@0 1436 {
michael@0 1437 if (!mDescriptor)
michael@0 1438 return NS_ERROR_NOT_AVAILABLE;
michael@0 1439
michael@0 1440 if (mStreamEnded)
michael@0 1441 return NS_ERROR_FAILURE;
michael@0 1442
michael@0 1443 // Determine compression level: Aggressive compression
michael@0 1444 // may impact performance on mobile devices, while a
michael@0 1445 // lower compression level still provides substantial
michael@0 1446 // space savings for many text streams.
michael@0 1447 int32_t compressionLevel = nsCacheService::CacheCompressionLevel();
michael@0 1448
michael@0 1449 // Initialize zlib deflate stream
michael@0 1450 mZstream.zalloc = Z_NULL;
michael@0 1451 mZstream.zfree = Z_NULL;
michael@0 1452 mZstream.opaque = Z_NULL;
michael@0 1453 if (deflateInit2(&mZstream, compressionLevel, Z_DEFLATED,
michael@0 1454 MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
michael@0 1455 return NS_ERROR_FAILURE;
michael@0 1456 }
michael@0 1457 mZstream.next_in = Z_NULL;
michael@0 1458 mZstream.avail_in = 0;
michael@0 1459
michael@0 1460 mStreamInitialized = true;
michael@0 1461
michael@0 1462 return NS_OK;
michael@0 1463 }
michael@0 1464
michael@0 1465 nsresult nsCacheEntryDescriptor::
michael@0 1466 nsCompressOutputStreamWrapper::WriteBuffer()
michael@0 1467 {
michael@0 1468 uint32_t bytesToWrite = mWriteBufferLen - mZstream.avail_out;
michael@0 1469 uint32_t result = 0;
michael@0 1470 nsresult rv = nsCacheEntryDescriptor::nsOutputStreamWrapper::Write_Locked(
michael@0 1471 (const char *)mWriteBuffer, bytesToWrite, &result);
michael@0 1472 mZstream.next_out = mWriteBuffer;
michael@0 1473 mZstream.avail_out = mWriteBufferLen;
michael@0 1474 return rv;
michael@0 1475 }
michael@0 1476

mercurial