1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is nsCacheEntryDescriptor.cpp, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2001
22 * the Initial Developer. All Rights Reserved.
25 * Gordon Sheridan, 22-February-2001
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
43 #include "nsCacheService.h"
44 #include "nsCacheEntryDescriptor.h"
45 #include "nsCacheEntry.h"
46 #include "nsReadableUtils.h"
47 #include "nsIOutputStream.h"
50 NS_IMPL_THREADSAFE_ISUPPORTS2(nsCacheEntryDescriptor
,
51 nsICacheEntryDescriptor
,
54 nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry
* entry
,
55 nsCacheAccessMode accessGranted
)
57 mAccessGranted(accessGranted
)
60 NS_ADDREF(nsCacheService::GlobalInstance()); // ensure it lives for the lifetime of the descriptor
64 nsCacheEntryDescriptor::~nsCacheEntryDescriptor()
66 // No need to close if the cache entry has already been severed. This
67 // helps avoid a shutdown assertion (bug 285519) that is caused when
68 // consumers end up holding onto these objects past xpcom-shutdown. It's
69 // okay for them to do that because the cache service calls our Close
70 // method during xpcom-shutdown, so we don't need to complain about it.
74 nsCacheService
* service
= nsCacheService::GlobalInstance();
80 nsCacheEntryDescriptor::GetClientID(char ** result
)
82 NS_ENSURE_ARG_POINTER(result
);
84 nsCacheServiceAutoLock lock
;
85 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
87 return ClientIDFromCacheKey(*(mCacheEntry
->Key()), result
);
92 nsCacheEntryDescriptor::GetDeviceID(char ** result
)
94 NS_ENSURE_ARG_POINTER(result
);
95 nsCacheServiceAutoLock lock
;
96 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
98 *result
= NS_strdup(mCacheEntry
->GetDeviceID());
99 return *result
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
104 nsCacheEntryDescriptor::GetKey(nsACString
&result
)
106 nsCacheServiceAutoLock lock
;
107 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
109 return ClientKeyFromCacheKey(*(mCacheEntry
->Key()), result
);
114 nsCacheEntryDescriptor::GetFetchCount(PRInt32
*result
)
116 NS_ENSURE_ARG_POINTER(result
);
117 nsCacheServiceAutoLock lock
;
118 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
120 *result
= mCacheEntry
->FetchCount();
126 nsCacheEntryDescriptor::GetLastFetched(PRUint32
*result
)
128 NS_ENSURE_ARG_POINTER(result
);
129 nsCacheServiceAutoLock lock
;
130 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
132 *result
= mCacheEntry
->LastFetched();
138 nsCacheEntryDescriptor::GetLastModified(PRUint32
*result
)
140 NS_ENSURE_ARG_POINTER(result
);
141 nsCacheServiceAutoLock lock
;
142 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
144 *result
= mCacheEntry
->LastModified();
150 nsCacheEntryDescriptor::GetExpirationTime(PRUint32
*result
)
152 NS_ENSURE_ARG_POINTER(result
);
153 nsCacheServiceAutoLock lock
;
154 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
156 *result
= mCacheEntry
->ExpirationTime();
162 nsCacheEntryDescriptor::SetExpirationTime(PRUint32 expirationTime
)
164 nsCacheServiceAutoLock lock
;
165 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
167 mCacheEntry
->SetExpirationTime(expirationTime
);
168 mCacheEntry
->MarkEntryDirty();
173 NS_IMETHODIMP
nsCacheEntryDescriptor::IsStreamBased(PRBool
*result
)
175 NS_ENSURE_ARG_POINTER(result
);
176 nsCacheServiceAutoLock lock
;
177 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
179 *result
= mCacheEntry
->IsStreamData();
184 NS_IMETHODIMP
nsCacheEntryDescriptor::GetDataSize(PRUint32
*result
)
186 NS_ENSURE_ARG_POINTER(result
);
187 nsCacheServiceAutoLock lock
;
188 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
190 *result
= mCacheEntry
->DataSize();
196 nsCacheEntryDescriptor::RequestDataSizeChange(PRInt32 deltaSize
)
198 nsCacheServiceAutoLock lock
;
199 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
202 rv
= nsCacheService::OnDataSizeChange(mCacheEntry
, deltaSize
);
203 if (NS_SUCCEEDED(rv
)) {
204 // XXX review for signed/unsigned math errors
205 PRUint32 newDataSize
= mCacheEntry
->DataSize() + deltaSize
;
206 mCacheEntry
->SetDataSize(newDataSize
);
207 mCacheEntry
->TouchData();
214 nsCacheEntryDescriptor::SetDataSize(PRUint32 dataSize
)
216 nsCacheServiceAutoLock lock
;
217 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
219 // XXX review for signed/unsigned math errors
220 PRInt32 deltaSize
= dataSize
- mCacheEntry
->DataSize();
223 rv
= nsCacheService::OnDataSizeChange(mCacheEntry
, deltaSize
);
224 // this had better be NS_OK, this call instance is advisory for memory cache objects
225 if (NS_SUCCEEDED(rv
)) {
226 // XXX review for signed/unsigned math errors
227 PRUint32 newDataSize
= mCacheEntry
->DataSize() + deltaSize
;
228 mCacheEntry
->SetDataSize(newDataSize
);
229 mCacheEntry
->TouchData();
231 NS_WARNING("failed SetDataSize() on memory cache object!");
239 nsCacheEntryDescriptor::OpenInputStream(PRUint32 offset
, nsIInputStream
** result
)
241 NS_ENSURE_ARG_POINTER(result
);
244 nsCacheServiceAutoLock lock
;
245 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
246 if (!mCacheEntry
->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM
;
248 // ensure valid permissions
249 if (!(mAccessGranted
& nsICache::ACCESS_READ
))
250 return NS_ERROR_CACHE_READ_ACCESS_DENIED
;
253 nsInputStreamWrapper
* cacheInput
=
254 new nsInputStreamWrapper(this, offset
);
255 if (!cacheInput
) return NS_ERROR_OUT_OF_MEMORY
;
257 NS_ADDREF(*result
= cacheInput
);
262 nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset
, nsIOutputStream
** result
)
264 NS_ENSURE_ARG_POINTER(result
);
267 nsCacheServiceAutoLock lock
;
268 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
269 if (!mCacheEntry
->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM
;
271 // ensure valid permissions
272 if (!(mAccessGranted
& nsICache::ACCESS_WRITE
))
273 return NS_ERROR_CACHE_WRITE_ACCESS_DENIED
;
276 nsOutputStreamWrapper
* cacheOutput
=
277 new nsOutputStreamWrapper(this, offset
);
278 if (!cacheOutput
) return NS_ERROR_OUT_OF_MEMORY
;
280 NS_ADDREF(*result
= cacheOutput
);
286 nsCacheEntryDescriptor::GetCacheElement(nsISupports
** result
)
288 NS_ENSURE_ARG_POINTER(result
);
289 nsCacheServiceAutoLock lock
;
290 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
291 if (mCacheEntry
->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM
;
293 NS_IF_ADDREF(*result
= mCacheEntry
->Data());
299 nsCacheEntryDescriptor::SetCacheElement(nsISupports
* cacheElement
)
301 nsCacheServiceAutoLock lock
;
302 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
303 if (mCacheEntry
->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM
;
305 return nsCacheService::SetCacheElement(mCacheEntry
, cacheElement
);
310 nsCacheEntryDescriptor::GetAccessGranted(nsCacheAccessMode
*result
)
312 NS_ENSURE_ARG_POINTER(result
);
313 *result
= mAccessGranted
;
319 nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy
*result
)
321 NS_ENSURE_ARG_POINTER(result
);
322 nsCacheServiceAutoLock lock
;
323 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
325 *result
= mCacheEntry
->StoragePolicy();
331 nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy
)
333 nsCacheServiceAutoLock lock
;
334 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
335 // XXX validate policy against session?
337 PRBool storageEnabled
= PR_FALSE
;
338 storageEnabled
= nsCacheService::IsStorageEnabledForPolicy_Locked(policy
);
339 if (!storageEnabled
) return NS_ERROR_FAILURE
;
341 // Don't change the storage policy of entries we can't write
342 if (!(mAccessGranted
& nsICache::ACCESS_WRITE
))
343 return NS_ERROR_NOT_AVAILABLE
;
345 // Don't allow a cache entry to move from memory-only to anything else
346 if (mCacheEntry
->StoragePolicy() == nsICache::STORE_IN_MEMORY
&&
347 policy
!= nsICache::STORE_IN_MEMORY
)
348 return NS_ERROR_NOT_AVAILABLE
;
350 mCacheEntry
->SetStoragePolicy(policy
);
351 mCacheEntry
->MarkEntryDirty();
357 nsCacheEntryDescriptor::GetFile(nsIFile
** result
)
359 NS_ENSURE_ARG_POINTER(result
);
360 nsCacheServiceAutoLock lock
;
361 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
363 return nsCacheService::GetFileForEntry(mCacheEntry
, result
);
368 nsCacheEntryDescriptor::GetSecurityInfo(nsISupports
** result
)
370 NS_ENSURE_ARG_POINTER(result
);
371 nsCacheServiceAutoLock lock
;
372 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
374 *result
= mCacheEntry
->SecurityInfo();
375 NS_IF_ADDREF(*result
);
381 nsCacheEntryDescriptor::SetSecurityInfo(nsISupports
* securityInfo
)
383 nsCacheServiceAutoLock lock
;
384 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
386 mCacheEntry
->SetSecurityInfo(securityInfo
);
387 mCacheEntry
->MarkEntryDirty();
393 nsCacheEntryDescriptor::Doom()
395 nsCacheServiceAutoLock lock
;
396 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
398 return nsCacheService::DoomEntry(mCacheEntry
);
403 nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status
)
405 nsCacheServiceAutoLock lock
;
406 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
408 return NS_ERROR_NOT_IMPLEMENTED
;
413 nsCacheEntryDescriptor::MarkValid()
415 nsCacheServiceAutoLock lock
;
416 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
418 nsresult rv
= nsCacheService::ValidateEntry(mCacheEntry
);
424 nsCacheEntryDescriptor::Close()
426 nsCacheServiceAutoLock lock
;
427 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
429 // XXX perhaps closing descriptors should clear/sever transports
431 // tell nsCacheService we're going away
432 nsCacheService::CloseDescriptor(this);
433 NS_ASSERTION(mCacheEntry
== nsnull
, "mCacheEntry not null");
440 nsCacheEntryDescriptor::GetMetaDataElement(const char *key
, char **result
)
442 NS_ENSURE_ARG_POINTER(key
);
445 nsCacheServiceAutoLock lock
;
446 NS_ENSURE_TRUE(mCacheEntry
, NS_ERROR_NOT_AVAILABLE
);
450 value
= mCacheEntry
->GetMetaDataElement(key
);
451 if (!value
) return NS_ERROR_NOT_AVAILABLE
;
453 *result
= NS_strdup(value
);
454 if (!*result
) return NS_ERROR_OUT_OF_MEMORY
;
461 nsCacheEntryDescriptor::SetMetaDataElement(const char *key
, const char *value
)
463 NS_ENSURE_ARG_POINTER(key
);
465 nsCacheServiceAutoLock lock
;
466 NS_ENSURE_TRUE(mCacheEntry
, NS_ERROR_NOT_AVAILABLE
);
468 // XXX allow null value, for clearing key?
470 nsresult rv
= mCacheEntry
->SetMetaDataElement(key
, value
);
471 if (NS_SUCCEEDED(rv
))
472 mCacheEntry
->TouchMetaData();
478 nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor
* visitor
)
480 nsCacheServiceAutoLock lock
; // XXX check callers, we're calling out of module
481 NS_ENSURE_ARG_POINTER(visitor
);
482 if (!mCacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
484 return mCacheEntry
->VisitMetaDataElements(visitor
);
488 /******************************************************************************
489 * nsCacheInputStream - a wrapper for nsIInputstream keeps the cache entry
490 * open while referenced.
491 ******************************************************************************/
493 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsInputStreamWrapper
,
496 nsresult
nsCacheEntryDescriptor::
497 nsInputStreamWrapper::LazyInit()
499 nsCacheServiceAutoLock lock
;
501 nsCacheAccessMode mode
;
502 nsresult rv
= mDescriptor
->GetAccessGranted(&mode
);
503 if (NS_FAILED(rv
)) return rv
;
505 NS_ENSURE_TRUE(mode
& nsICache::ACCESS_READ
, NS_ERROR_UNEXPECTED
);
507 nsCacheEntry
* cacheEntry
= mDescriptor
->CacheEntry();
508 if (!cacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
510 nsCOMPtr
<nsIInputStream
> input
;
511 rv
= nsCacheService::OpenInputStreamForEntry(cacheEntry
, mode
,
513 getter_AddRefs(mInput
));
514 if (NS_FAILED(rv
)) return rv
;
516 mInitialized
= PR_TRUE
;
520 nsresult
nsCacheEntryDescriptor::
521 nsInputStreamWrapper::Close()
523 nsresult rv
= EnsureInit();
524 if (NS_FAILED(rv
)) return rv
;
526 return mInput
->Close();
529 nsresult
nsCacheEntryDescriptor::
530 nsInputStreamWrapper::Available(PRUint32
*avail
)
532 nsresult rv
= EnsureInit();
533 if (NS_FAILED(rv
)) return rv
;
535 return mInput
->Available(avail
);
538 nsresult
nsCacheEntryDescriptor::
539 nsInputStreamWrapper::Read(char *buf
, PRUint32 count
, PRUint32
*countRead
)
541 nsresult rv
= EnsureInit();
542 if (NS_FAILED(rv
)) return rv
;
544 return mInput
->Read(buf
, count
, countRead
);
547 nsresult
nsCacheEntryDescriptor::
548 nsInputStreamWrapper::ReadSegments(nsWriteSegmentFun writer
, void *closure
,
549 PRUint32 count
, PRUint32
*countRead
)
551 // cache stream not buffered
552 return NS_ERROR_NOT_IMPLEMENTED
;
555 nsresult
nsCacheEntryDescriptor::
556 nsInputStreamWrapper::IsNonBlocking(PRBool
*result
)
558 // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
564 /******************************************************************************
565 * nsCacheOutputStream - a wrapper for nsIOutputstream to track the amount of
566 * data written to a cache entry.
567 * - also keeps the cache entry open while referenced.
568 ******************************************************************************/
570 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsOutputStreamWrapper
,
573 nsresult
nsCacheEntryDescriptor::
574 nsOutputStreamWrapper::LazyInit()
576 nsCacheServiceAutoLock lock
;
578 nsCacheAccessMode mode
;
579 nsresult rv
= mDescriptor
->GetAccessGranted(&mode
);
580 if (NS_FAILED(rv
)) return rv
;
582 NS_ENSURE_TRUE(mode
& nsICache::ACCESS_WRITE
, NS_ERROR_UNEXPECTED
);
584 nsCacheEntry
* cacheEntry
= mDescriptor
->CacheEntry();
585 if (!cacheEntry
) return NS_ERROR_NOT_AVAILABLE
;
587 rv
= nsCacheService::OpenOutputStreamForEntry(cacheEntry
, mode
, mStartOffset
,
588 getter_AddRefs(mOutput
));
589 if (NS_FAILED(rv
)) return rv
;
591 nsCacheDevice
* device
= cacheEntry
->CacheDevice();
592 if (!device
) return NS_ERROR_NOT_AVAILABLE
;
594 // the entry has been truncated to mStartOffset bytes, inform the device.
595 PRInt32 size
= cacheEntry
->DataSize();
596 rv
= device
->OnDataSizeChange(cacheEntry
, mStartOffset
- size
);
597 if (NS_FAILED(rv
)) return rv
;
599 cacheEntry
->SetDataSize(mStartOffset
);
601 mInitialized
= PR_TRUE
;
605 nsresult
nsCacheEntryDescriptor::
606 nsOutputStreamWrapper::OnWrite(PRUint32 count
)
608 if (count
> PR_INT32_MAX
) return NS_ERROR_UNEXPECTED
;
609 return mDescriptor
->RequestDataSizeChange((PRInt32
)count
);
612 NS_IMETHODIMP
nsCacheEntryDescriptor::
613 nsOutputStreamWrapper::Close()
615 nsresult rv
= EnsureInit();
616 if (NS_FAILED(rv
)) return rv
;
618 return mOutput
->Close();
621 NS_IMETHODIMP
nsCacheEntryDescriptor::
622 nsOutputStreamWrapper::Flush()
624 nsresult rv
= EnsureInit();
625 if (NS_FAILED(rv
)) return rv
;
627 return mOutput
->Flush();
630 NS_IMETHODIMP
nsCacheEntryDescriptor::
631 nsOutputStreamWrapper::Write(const char * buf
,
635 nsresult rv
= EnsureInit();
636 if (NS_FAILED(rv
)) return rv
;
639 if (NS_FAILED(rv
)) return rv
;
641 return mOutput
->Write(buf
, count
, result
);
644 NS_IMETHODIMP
nsCacheEntryDescriptor::
645 nsOutputStreamWrapper::WriteFrom(nsIInputStream
* inStr
,
649 NS_NOTREACHED("cache stream not buffered");
650 return NS_ERROR_NOT_IMPLEMENTED
;
653 NS_IMETHODIMP
nsCacheEntryDescriptor::
654 nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader
,
659 NS_NOTREACHED("cache stream not buffered");
660 return NS_ERROR_NOT_IMPLEMENTED
;
663 NS_IMETHODIMP
nsCacheEntryDescriptor::
664 nsOutputStreamWrapper::IsNonBlocking(PRBool
*result
)
666 // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK