1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/about/nsAboutCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,340 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsAboutCache.h" 1.10 +#include "nsIInputStream.h" 1.11 +#include "nsIStorageStream.h" 1.12 +#include "nsIURI.h" 1.13 +#include "nsCOMPtr.h" 1.14 +#include "nsNetUtil.h" 1.15 +#include "nsEscape.h" 1.16 +#include "nsAboutProtocolUtils.h" 1.17 + 1.18 +#include "nsICacheService.h" 1.19 + 1.20 +NS_IMPL_ISUPPORTS(nsAboutCache, nsIAboutModule, nsICacheVisitor) 1.21 + 1.22 +NS_IMETHODIMP 1.23 +nsAboutCache::NewChannel(nsIURI *aURI, nsIChannel **result) 1.24 +{ 1.25 + NS_ENSURE_ARG_POINTER(aURI); 1.26 + nsresult rv; 1.27 + uint32_t bytesWritten; 1.28 + 1.29 + *result = nullptr; 1.30 + // Get the cache manager service 1.31 + nsCOMPtr<nsICacheService> cacheService = 1.32 + do_GetService(NS_CACHESERVICE_CONTRACTID, &rv); 1.33 + if (NS_FAILED(rv)) return rv; 1.34 + 1.35 + nsCOMPtr<nsIStorageStream> storageStream; 1.36 + nsCOMPtr<nsIOutputStream> outputStream; 1.37 + 1.38 + // Init: (block size, maximum length) 1.39 + rv = NS_NewStorageStream(256, (uint32_t)-1, getter_AddRefs(storageStream)); 1.40 + if (NS_FAILED(rv)) return rv; 1.41 + 1.42 + rv = storageStream->GetOutputStream(0, getter_AddRefs(outputStream)); 1.43 + if (NS_FAILED(rv)) return rv; 1.44 + 1.45 + mBuffer.AssignLiteral( 1.46 + "<!DOCTYPE html>\n" 1.47 + "<html>\n" 1.48 + "<head>\n" 1.49 + " <title>Information about the Cache Service</title>\n" 1.50 + " <link rel=\"stylesheet\" " 1.51 + "href=\"chrome://global/skin/about.css\" type=\"text/css\"/>\n" 1.52 + " <link rel=\"stylesheet\" " 1.53 + "href=\"chrome://global/skin/aboutCache.css\" type=\"text/css\"/>\n" 1.54 + "</head>\n" 1.55 + "<body class=\"aboutPageWideContainer\">\n" 1.56 + "<h1>Information about the Cache Service</h1>\n"); 1.57 + 1.58 + outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); 1.59 + 1.60 + rv = ParseURI(aURI, mDeviceID); 1.61 + if (NS_FAILED(rv)) return rv; 1.62 + 1.63 + mStream = outputStream; 1.64 + 1.65 + // nsCacheService::VisitEntries calls nsMemoryCacheDevice::Visit, 1.66 + // nsDiskCacheDevice::Visit and nsOfflineCacheDevice::Visit, 1.67 + // each of which call 1.68 + // 1. VisitDevice (for about:cache), 1.69 + // 2. VisitEntry in a loop (for about:cache?device=disk etc.) 1.70 + rv = cacheService->VisitEntries(this); 1.71 + mBuffer.Truncate(); 1.72 + if (rv == NS_ERROR_NOT_AVAILABLE) { 1.73 + mBuffer.AppendLiteral("<h2>The cache is disabled.</h2>\n"); 1.74 + } 1.75 + else if (NS_FAILED(rv)) { 1.76 + return rv; 1.77 + } 1.78 + 1.79 + if (!mDeviceID.IsEmpty()) { 1.80 + mBuffer.AppendLiteral("</table>\n"); 1.81 + } 1.82 + mBuffer.AppendLiteral("</body>\n" 1.83 + "</html>\n"); 1.84 + outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); 1.85 + 1.86 + nsCOMPtr<nsIInputStream> inStr; 1.87 + 1.88 + rv = storageStream->NewInputStream(0, getter_AddRefs(inStr)); 1.89 + if (NS_FAILED(rv)) return rv; 1.90 + 1.91 + nsCOMPtr<nsIChannel> channel; 1.92 + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, inStr, 1.93 + NS_LITERAL_CSTRING("text/html"), 1.94 + NS_LITERAL_CSTRING("utf-8")); 1.95 + if (NS_FAILED(rv)) return rv; 1.96 + 1.97 + channel.forget(result); 1.98 + return rv; 1.99 +} 1.100 + 1.101 +NS_IMETHODIMP 1.102 +nsAboutCache::GetURIFlags(nsIURI *aURI, uint32_t *result) 1.103 +{ 1.104 + *result = 0; 1.105 + return NS_OK; 1.106 +} 1.107 + 1.108 +NS_IMETHODIMP 1.109 +nsAboutCache::VisitDevice(const char *deviceID, 1.110 + nsICacheDeviceInfo *deviceInfo, 1.111 + bool *visitEntries) 1.112 +{ 1.113 + uint32_t bytesWritten, value, entryCount; 1.114 + nsXPIDLCString str; 1.115 + 1.116 + *visitEntries = false; 1.117 + 1.118 + if (mDeviceID.IsEmpty() || mDeviceID.Equals(deviceID)) { 1.119 + 1.120 + // We need mStream for this 1.121 + if (!mStream) 1.122 + return NS_ERROR_FAILURE; 1.123 + 1.124 + // Write out the Cache Name 1.125 + deviceInfo->GetDescription(getter_Copies(str)); 1.126 + 1.127 + mBuffer.AssignLiteral("<h2>"); 1.128 + mBuffer.Append(str); 1.129 + mBuffer.AppendLiteral("</h2>\n" 1.130 + "<table id=\""); 1.131 + mBuffer.Append(deviceID); 1.132 + mBuffer.AppendLiteral("\">\n"); 1.133 + 1.134 + // Write out cache info 1.135 + // Number of entries 1.136 + mBuffer.AppendLiteral(" <tr>\n" 1.137 + " <th>Number of entries:</th>\n" 1.138 + " <td>"); 1.139 + entryCount = 0; 1.140 + deviceInfo->GetEntryCount(&entryCount); 1.141 + mBuffer.AppendInt(entryCount); 1.142 + mBuffer.AppendLiteral("</td>\n" 1.143 + " </tr>\n"); 1.144 + 1.145 + // Maximum storage size 1.146 + mBuffer.AppendLiteral(" <tr>\n" 1.147 + " <th>Maximum storage size:</th>\n" 1.148 + " <td>"); 1.149 + value = 0; 1.150 + deviceInfo->GetMaximumSize(&value); 1.151 + mBuffer.AppendInt(value/1024); 1.152 + mBuffer.AppendLiteral(" KiB</td>\n" 1.153 + " </tr>\n"); 1.154 + 1.155 + // Storage in use 1.156 + mBuffer.AppendLiteral(" <tr>\n" 1.157 + " <th>Storage in use:</th>\n" 1.158 + " <td>"); 1.159 + value = 0; 1.160 + deviceInfo->GetTotalSize(&value); 1.161 + mBuffer.AppendInt(value/1024); 1.162 + mBuffer.AppendLiteral(" KiB</td>\n" 1.163 + " </tr>\n"); 1.164 + 1.165 + deviceInfo->GetUsageReport(getter_Copies(str)); 1.166 + mBuffer.Append(str); 1.167 + 1.168 + if (mDeviceID.IsEmpty()) { // The about:cache case 1.169 + if (entryCount != 0) { // Add the "List Cache Entries" link 1.170 + mBuffer.AppendLiteral(" <tr>\n" 1.171 + " <th><a href=\"about:cache?device="); 1.172 + mBuffer.Append(deviceID); 1.173 + mBuffer.AppendLiteral("\">List Cache Entries</a></th>\n" 1.174 + " </tr>\n"); 1.175 + } 1.176 + mBuffer.AppendLiteral("</table>\n"); 1.177 + } else { // The about:cache?device=disk etc. case 1.178 + mBuffer.AppendLiteral("</table>\n"); 1.179 + if (entryCount != 0) { 1.180 + *visitEntries = true; 1.181 + mBuffer.AppendLiteral("<hr/>\n" 1.182 + "<table id=\"entries\">\n" 1.183 + " <colgroup>\n" 1.184 + " <col id=\"col-key\">\n" 1.185 + " <col id=\"col-dataSize\">\n" 1.186 + " <col id=\"col-fetchCount\">\n" 1.187 + " <col id=\"col-lastModified\">\n" 1.188 + " <col id=\"col-expires\">\n" 1.189 + " </colgroup>\n" 1.190 + " <thead>\n" 1.191 + " <tr>\n" 1.192 + " <th>Key</th>\n" 1.193 + " <th>Data size</th>\n" 1.194 + " <th>Fetch count</th>\n" 1.195 + " <th>Last modified</th>\n" 1.196 + " <th>Expires</th>\n" 1.197 + " </tr>\n" 1.198 + " </thead>\n"); 1.199 + } 1.200 + } 1.201 + 1.202 + mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); 1.203 + } 1.204 + 1.205 + return NS_OK; 1.206 +} 1.207 + 1.208 +NS_IMETHODIMP 1.209 +nsAboutCache::VisitEntry(const char *deviceID, 1.210 + nsICacheEntryInfo *entryInfo, 1.211 + bool *visitNext) 1.212 +{ 1.213 + // We need mStream for this 1.214 + if (!mStream) 1.215 + return NS_ERROR_FAILURE; 1.216 + 1.217 + nsresult rv; 1.218 + uint32_t bytesWritten; 1.219 + nsAutoCString key; 1.220 + nsXPIDLCString clientID; 1.221 + bool streamBased; 1.222 + 1.223 + rv = entryInfo->GetKey(key); 1.224 + if (NS_FAILED(rv)) return rv; 1.225 + 1.226 + rv = entryInfo->GetClientID(getter_Copies(clientID)); 1.227 + if (NS_FAILED(rv)) return rv; 1.228 + 1.229 + rv = entryInfo->IsStreamBased(&streamBased); 1.230 + if (NS_FAILED(rv)) return rv; 1.231 + 1.232 + // Generate a about:cache-entry URL for this entry... 1.233 + nsAutoCString url; 1.234 + url.AssignLiteral("about:cache-entry?client="); 1.235 + url += clientID; 1.236 + url.AppendLiteral("&sb="); 1.237 + url += streamBased ? '1' : '0'; 1.238 + url.AppendLiteral("&key="); 1.239 + char* escapedKey = nsEscapeHTML(key.get()); 1.240 + url += escapedKey; // key 1.241 + 1.242 + // Entry start... 1.243 + mBuffer.AssignLiteral(" <tr>\n"); 1.244 + 1.245 + // URI 1.246 + mBuffer.AppendLiteral(" <td><a href=\""); 1.247 + mBuffer.Append(url); 1.248 + mBuffer.AppendLiteral("\">"); 1.249 + mBuffer.Append(escapedKey); 1.250 + nsMemory::Free(escapedKey); 1.251 + mBuffer.AppendLiteral("</a></td>\n"); 1.252 + 1.253 + // Content length 1.254 + uint32_t length = 0; 1.255 + entryInfo->GetDataSize(&length); 1.256 + mBuffer.AppendLiteral(" <td>"); 1.257 + mBuffer.AppendInt(length); 1.258 + mBuffer.AppendLiteral(" bytes</td>\n"); 1.259 + 1.260 + // Number of accesses 1.261 + int32_t fetchCount = 0; 1.262 + entryInfo->GetFetchCount(&fetchCount); 1.263 + mBuffer.AppendLiteral(" <td>"); 1.264 + mBuffer.AppendInt(fetchCount); 1.265 + mBuffer.AppendLiteral("</td>\n"); 1.266 + 1.267 + // vars for reporting time 1.268 + char buf[255]; 1.269 + uint32_t t; 1.270 + 1.271 + // Last modified time 1.272 + mBuffer.AppendLiteral(" <td>"); 1.273 + entryInfo->GetLastModified(&t); 1.274 + if (t) { 1.275 + PrintTimeString(buf, sizeof(buf), t); 1.276 + mBuffer.Append(buf); 1.277 + } else 1.278 + mBuffer.AppendLiteral("No last modified time"); 1.279 + mBuffer.AppendLiteral("</td>\n"); 1.280 + 1.281 + // Expires time 1.282 + mBuffer.AppendLiteral(" <td>"); 1.283 + entryInfo->GetExpirationTime(&t); 1.284 + if (t < 0xFFFFFFFF) { 1.285 + PrintTimeString(buf, sizeof(buf), t); 1.286 + mBuffer.Append(buf); 1.287 + } else { 1.288 + mBuffer.AppendLiteral("No expiration time"); 1.289 + } 1.290 + mBuffer.AppendLiteral("</td>\n"); 1.291 + 1.292 + // Entry is done... 1.293 + mBuffer.AppendLiteral(" </tr>\n"); 1.294 + 1.295 + mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten); 1.296 + 1.297 + *visitNext = true; 1.298 + return NS_OK; 1.299 +} 1.300 + 1.301 + 1.302 +nsresult 1.303 +nsAboutCache::ParseURI(nsIURI * uri, nsCString &deviceID) 1.304 +{ 1.305 + // 1.306 + // about:cache[?device=string] 1.307 + // 1.308 + nsresult rv; 1.309 + 1.310 + deviceID.Truncate(); 1.311 + 1.312 + nsAutoCString path; 1.313 + rv = uri->GetPath(path); 1.314 + if (NS_FAILED(rv)) return rv; 1.315 + 1.316 + nsACString::const_iterator start, valueStart, end; 1.317 + path.BeginReading(start); 1.318 + path.EndReading(end); 1.319 + 1.320 + valueStart = end; 1.321 + if (!FindInReadable(NS_LITERAL_CSTRING("?device="), start, valueStart)) 1.322 + return NS_OK; 1.323 + 1.324 + deviceID.Assign(Substring(valueStart, end)); 1.325 + return NS_OK; 1.326 +} 1.327 + 1.328 + 1.329 +nsresult 1.330 +nsAboutCache::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.331 +{ 1.332 + nsAboutCache* about = new nsAboutCache(); 1.333 + if (about == nullptr) 1.334 + return NS_ERROR_OUT_OF_MEMORY; 1.335 + NS_ADDREF(about); 1.336 + nsresult rv = about->QueryInterface(aIID, aResult); 1.337 + NS_RELEASE(about); 1.338 + return rv; 1.339 +} 1.340 + 1.341 + 1.342 + 1.343 +////////////////////////////////////////////////////////////////////////////////