/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsAboutCache.h" #include "nsIIOService.h" #include "nsIServiceManager.h" #include "nsIInputStream.h" #include "nsIStorageStream.h" #include "nsISimpleEnumerator.h" #include "nsXPIDLString.h" #include "nsIURI.h" #include "nsCOMPtr.h" #include "nsNetUtil.h" #include "prtime.h" #include "nsEscape.h" #include "nsICacheService.h" static PRTime SecondsToPRTime(uint32_t t_sec) { PRTime t_usec, usec_per_sec; LL_I2L(t_usec, t_sec); LL_I2L(usec_per_sec, PR_USEC_PER_SEC); LL_MUL(t_usec, t_usec, usec_per_sec); return t_usec; } static void PrintTimeString(char *buf, uint32_t bufsize, uint32_t t_sec) { PRExplodedTime et; PRTime t_usec = SecondsToPRTime(t_sec); PR_ExplodeTime(t_usec, PR_LocalTimeParameters, &et); PR_FormatTime(buf, bufsize, "%Y-%m-%d %H:%M:%S", &et); } NS_IMPL_ISUPPORTS2(nsAboutCache, nsIAboutModule, nsICacheVisitor) NS_IMETHODIMP nsAboutCache::NewChannel(nsIURI *aURI, nsIChannel **result) { NS_ENSURE_ARG_POINTER(aURI); nsresult rv; uint32_t bytesWritten; *result = nullptr; // Get the cache manager service nsCOMPtr cacheService = do_GetService(NS_CACHESERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr storageStream; nsCOMPtr outputStream; // Init: (block size, maximum length) rv = NS_NewStorageStream(256, (uint32_t)-1, getter_AddRefs(storageStream)); if (NS_FAILED(rv)) return rv; rv = storageStream->GetOutputStream(0, getter_AddRefs(outputStream)); if (NS_FAILED(rv)) return rv; mBuffer.AssignLiteral( "\n" "\n" "\n" " Information about the Cache Service\n" " \n" " \n" "\n" "\n" "

Information about the Cache Service

\n"); outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); rv = ParseURI(aURI, mDeviceID); if (NS_FAILED(rv)) return rv; mStream = outputStream; // nsCacheService::VisitEntries calls nsMemoryCacheDevice::Visit, // nsDiskCacheDevice::Visit and nsOfflineCacheDevice::Visit, // each of which call // 1. VisitDevice (for about:cache), // 2. VisitEntry in a loop (for about:cache?device=disk etc.) rv = cacheService->VisitEntries(this); mBuffer.Truncate(); if (rv == NS_ERROR_NOT_AVAILABLE) { mBuffer.AppendLiteral("

The cache is disabled.

\n"); } else if (NS_FAILED(rv)) { return rv; } if (!mDeviceID.IsEmpty()) { mBuffer.AppendLiteral("\n"); } mBuffer.AppendLiteral("\n" "\n"); outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); nsCOMPtr inStr; rv = storageStream->NewInputStream(0, getter_AddRefs(inStr)); if (NS_FAILED(rv)) return rv; nsCOMPtr channel; rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, inStr, NS_LITERAL_CSTRING("text/html"), NS_LITERAL_CSTRING("utf-8")); if (NS_FAILED(rv)) return rv; channel.forget(result); return rv; } NS_IMETHODIMP nsAboutCache::GetURIFlags(nsIURI *aURI, uint32_t *result) { *result = 0; return NS_OK; } NS_IMETHODIMP nsAboutCache::VisitDevice(const char *deviceID, nsICacheDeviceInfo *deviceInfo, bool *visitEntries) { uint32_t bytesWritten, value, entryCount; nsXPIDLCString str; *visitEntries = false; if (mDeviceID.IsEmpty() || mDeviceID.Equals(deviceID)) { // We need mStream for this if (!mStream) return NS_ERROR_FAILURE; // Write out the Cache Name deviceInfo->GetDescription(getter_Copies(str)); mBuffer.AssignLiteral("

"); mBuffer.Append(str); mBuffer.AppendLiteral("

\n" "\n"); // Write out cache info // Number of entries mBuffer.AppendLiteral(" \n" " \n" " \n" " \n"); // Maximum storage size mBuffer.AppendLiteral(" \n" " \n" " \n" " \n"); // Storage in use mBuffer.AppendLiteral(" \n" " \n" " \n" " \n"); deviceInfo->GetUsageReport(getter_Copies(str)); mBuffer.Append(str); if (mDeviceID.IsEmpty()) { // The about:cache case if (entryCount != 0) { // Add the "List Cache Entries" link mBuffer.AppendLiteral(" \n" " \n" " \n"); } mBuffer.AppendLiteral("
Number of entries:"); entryCount = 0; deviceInfo->GetEntryCount(&entryCount); mBuffer.AppendInt(entryCount); mBuffer.AppendLiteral("
Maximum storage size:"); value = 0; deviceInfo->GetMaximumSize(&value); mBuffer.AppendInt(value/1024); mBuffer.AppendLiteral(" KiB
Storage in use:"); value = 0; deviceInfo->GetTotalSize(&value); mBuffer.AppendInt(value/1024); mBuffer.AppendLiteral(" KiB
List Cache Entries
\n"); } else { // The about:cache?device=disk etc. case mBuffer.AppendLiteral("\n"); if (entryCount != 0) { *visitEntries = true; mBuffer.AppendLiteral("
\n" "\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n"); } } mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); } return NS_OK; } NS_IMETHODIMP nsAboutCache::VisitEntry(const char *deviceID, nsICacheEntryInfo *entryInfo, bool *visitNext) { // We need mStream for this if (!mStream) return NS_ERROR_FAILURE; nsresult rv; uint32_t bytesWritten; nsAutoCString key; nsXPIDLCString clientID; bool streamBased; rv = entryInfo->GetKey(key); if (NS_FAILED(rv)) return rv; rv = entryInfo->GetClientID(getter_Copies(clientID)); if (NS_FAILED(rv)) return rv; rv = entryInfo->IsStreamBased(&streamBased); if (NS_FAILED(rv)) return rv; // Generate a about:cache-entry URL for this entry... nsAutoCString url; url.AssignLiteral("about:cache-entry?client="); url += clientID; url.AppendLiteral("&sb="); url += streamBased ? '1' : '0'; url.AppendLiteral("&key="); char* escapedKey = nsEscapeHTML(key.get()); url += escapedKey; // key // Entry start... mBuffer.AssignLiteral(" \n"); // URI mBuffer.AppendLiteral(" \n"); // Content length uint32_t length = 0; entryInfo->GetDataSize(&length); mBuffer.AppendLiteral(" \n"); // Number of accesses int32_t fetchCount = 0; entryInfo->GetFetchCount(&fetchCount); mBuffer.AppendLiteral(" \n"); // vars for reporting time char buf[255]; uint32_t t; // Last modified time mBuffer.AppendLiteral(" \n"); // Expires time mBuffer.AppendLiteral(" \n"); // Entry is done... mBuffer.AppendLiteral(" \n"); mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); *visitNext = true; return NS_OK; } nsresult nsAboutCache::ParseURI(nsIURI * uri, nsCString &deviceID) { // // about:cache[?device=string] // nsresult rv; deviceID.Truncate(); nsAutoCString path; rv = uri->GetPath(path); if (NS_FAILED(rv)) return rv; nsACString::const_iterator start, valueStart, end; path.BeginReading(start); path.EndReading(end); valueStart = end; if (!FindInReadable(NS_LITERAL_CSTRING("?device="), start, valueStart)) return NS_OK; deviceID.Assign(Substring(valueStart, end)); return NS_OK; } nsresult nsAboutCache::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) { nsAboutCache* about = new nsAboutCache(); if (about == nullptr) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(about); nsresult rv = about->QueryInterface(aIID, aResult); NS_RELEASE(about); return rv; } ////////////////////////////////////////////////////////////////////////////////
KeyData sizeFetch countLast modifiedExpires
"); mBuffer.Append(escapedKey); nsMemory::Free(escapedKey); mBuffer.AppendLiteral(""); mBuffer.AppendInt(length); mBuffer.AppendLiteral(" bytes"); mBuffer.AppendInt(fetchCount); mBuffer.AppendLiteral(""); entryInfo->GetLastModified(&t); if (t) { PrintTimeString(buf, sizeof(buf), t); mBuffer.Append(buf); } else mBuffer.AppendLiteral("No last modified time"); mBuffer.AppendLiteral(""); entryInfo->GetExpirationTime(&t); if (t < 0xFFFFFFFF) { PrintTimeString(buf, sizeof(buf), t); mBuffer.Append(buf); } else { mBuffer.AppendLiteral("No expiration time"); } mBuffer.AppendLiteral("