Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / netwerk / cache / src / nsCacheEntryDescriptor.cpp
blobf0daa3f52ce0b4ea889ee0daffe2300006a15004
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
14 * License.
16 * The Original Code is nsCacheEntryDescriptor.cpp, released
17 * February 22, 2001.
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.
24 * Contributor(s):
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 ***** */
41 #include "nsICache.h"
42 #include "nsCache.h"
43 #include "nsCacheService.h"
44 #include "nsCacheEntryDescriptor.h"
45 #include "nsCacheEntry.h"
46 #include "nsReadableUtils.h"
47 #include "nsIOutputStream.h"
48 #include "nsCRT.h"
50 NS_IMPL_THREADSAFE_ISUPPORTS2(nsCacheEntryDescriptor,
51 nsICacheEntryDescriptor,
52 nsICacheEntryInfo)
54 nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry,
55 nsCacheAccessMode accessGranted)
56 : mCacheEntry(entry),
57 mAccessGranted(accessGranted)
59 PR_INIT_CLIST(this);
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.
71 if (mCacheEntry)
72 Close();
74 nsCacheService * service = nsCacheService::GlobalInstance();
75 NS_RELEASE(service);
79 NS_IMETHODIMP
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);
91 NS_IMETHODIMP
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;
103 NS_IMETHODIMP
104 nsCacheEntryDescriptor::GetKey(nsACString &result)
106 nsCacheServiceAutoLock lock;
107 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
109 return ClientKeyFromCacheKey(*(mCacheEntry->Key()), result);
113 NS_IMETHODIMP
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();
121 return NS_OK;
125 NS_IMETHODIMP
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();
133 return NS_OK;
137 NS_IMETHODIMP
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();
145 return NS_OK;
149 NS_IMETHODIMP
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();
157 return NS_OK;
161 NS_IMETHODIMP
162 nsCacheEntryDescriptor::SetExpirationTime(PRUint32 expirationTime)
164 nsCacheServiceAutoLock lock;
165 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
167 mCacheEntry->SetExpirationTime(expirationTime);
168 mCacheEntry->MarkEntryDirty();
169 return NS_OK;
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();
180 return NS_OK;
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();
191 return NS_OK;
195 nsresult
196 nsCacheEntryDescriptor::RequestDataSizeChange(PRInt32 deltaSize)
198 nsCacheServiceAutoLock lock;
199 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
201 nsresult rv;
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();
209 return rv;
213 NS_IMETHODIMP
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();
222 nsresult rv;
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();
230 } else {
231 NS_WARNING("failed SetDataSize() on memory cache object!");
234 return rv;
238 NS_IMETHODIMP
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);
258 return NS_OK;
261 NS_IMETHODIMP
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);
281 return NS_OK;
285 NS_IMETHODIMP
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());
294 return NS_OK;
298 NS_IMETHODIMP
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);
309 NS_IMETHODIMP
310 nsCacheEntryDescriptor::GetAccessGranted(nsCacheAccessMode *result)
312 NS_ENSURE_ARG_POINTER(result);
313 *result = mAccessGranted;
314 return NS_OK;
318 NS_IMETHODIMP
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();
326 return NS_OK;
330 NS_IMETHODIMP
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();
352 return NS_OK;
356 NS_IMETHODIMP
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);
367 NS_IMETHODIMP
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);
376 return NS_OK;
380 NS_IMETHODIMP
381 nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo)
383 nsCacheServiceAutoLock lock;
384 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
386 mCacheEntry->SetSecurityInfo(securityInfo);
387 mCacheEntry->MarkEntryDirty();
388 return NS_OK;
392 NS_IMETHODIMP
393 nsCacheEntryDescriptor::Doom()
395 nsCacheServiceAutoLock lock;
396 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
398 return nsCacheService::DoomEntry(mCacheEntry);
402 NS_IMETHODIMP
403 nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status)
405 nsCacheServiceAutoLock lock;
406 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
408 return NS_ERROR_NOT_IMPLEMENTED;
412 NS_IMETHODIMP
413 nsCacheEntryDescriptor::MarkValid()
415 nsCacheServiceAutoLock lock;
416 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
418 nsresult rv = nsCacheService::ValidateEntry(mCacheEntry);
419 return rv;
423 NS_IMETHODIMP
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");
435 return NS_OK;
439 NS_IMETHODIMP
440 nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char **result)
442 NS_ENSURE_ARG_POINTER(key);
443 *result = nsnull;
445 nsCacheServiceAutoLock lock;
446 NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
448 const char *value;
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;
456 return NS_OK;
460 NS_IMETHODIMP
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();
473 return rv;
477 NS_IMETHODIMP
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,
494 nsIInputStream)
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,
512 mStartOffset,
513 getter_AddRefs(mInput));
514 if (NS_FAILED(rv)) return rv;
516 mInitialized = PR_TRUE;
517 return NS_OK;
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
559 *result = PR_FALSE;
560 return NS_OK;
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,
571 nsIOutputStream)
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;
602 return NS_OK;
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,
632 PRUint32 count,
633 PRUint32 * result)
635 nsresult rv = EnsureInit();
636 if (NS_FAILED(rv)) return rv;
638 rv = OnWrite(count);
639 if (NS_FAILED(rv)) return rv;
641 return mOutput->Write(buf, count, result);
644 NS_IMETHODIMP nsCacheEntryDescriptor::
645 nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr,
646 PRUint32 count,
647 PRUint32 * result)
649 NS_NOTREACHED("cache stream not buffered");
650 return NS_ERROR_NOT_IMPLEMENTED;
653 NS_IMETHODIMP nsCacheEntryDescriptor::
654 nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader,
655 void * closure,
656 PRUint32 count,
657 PRUint32 * result)
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
667 *result = PR_FALSE;
668 return NS_OK;