netwerk/protocol/about/nsAboutCacheEntry.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsAboutCacheEntry.h"
michael@0 7 #include "nsICacheService.h"
michael@0 8 #include "nsICacheSession.h"
michael@0 9 #include "nsNetUtil.h"
michael@0 10 #include "prprf.h"
michael@0 11 #include "nsEscape.h"
michael@0 12 #include "nsIAsyncInputStream.h"
michael@0 13 #include "nsIAsyncOutputStream.h"
michael@0 14 #include "nsAboutProtocolUtils.h"
michael@0 15 #include <algorithm>
michael@0 16
michael@0 17 #define HEXDUMP_MAX_ROWS 16
michael@0 18
michael@0 19 static void
michael@0 20 HexDump(uint32_t *state, const char *buf, int32_t n, nsCString &result)
michael@0 21 {
michael@0 22 char temp[16];
michael@0 23
michael@0 24 const unsigned char *p;
michael@0 25 while (n) {
michael@0 26 PR_snprintf(temp, sizeof(temp), "%08x: ", *state);
michael@0 27 result.Append(temp);
michael@0 28 *state += HEXDUMP_MAX_ROWS;
michael@0 29
michael@0 30 p = (const unsigned char *) buf;
michael@0 31
michael@0 32 int32_t i, row_max = std::min(HEXDUMP_MAX_ROWS, n);
michael@0 33
michael@0 34 // print hex codes:
michael@0 35 for (i = 0; i < row_max; ++i) {
michael@0 36 PR_snprintf(temp, sizeof(temp), "%02x ", *p++);
michael@0 37 result.Append(temp);
michael@0 38 }
michael@0 39 for (i = row_max; i < HEXDUMP_MAX_ROWS; ++i) {
michael@0 40 result.AppendLiteral(" ");
michael@0 41 }
michael@0 42
michael@0 43 // print ASCII glyphs if possible:
michael@0 44 p = (const unsigned char *) buf;
michael@0 45 for (i = 0; i < row_max; ++i, ++p) {
michael@0 46 switch (*p) {
michael@0 47 case '<':
michael@0 48 result.AppendLiteral("&lt;");
michael@0 49 break;
michael@0 50 case '>':
michael@0 51 result.AppendLiteral("&gt;");
michael@0 52 break;
michael@0 53 case '&':
michael@0 54 result.AppendLiteral("&amp;");
michael@0 55 break;
michael@0 56 default:
michael@0 57 if (*p < 0x7F && *p > 0x1F) {
michael@0 58 result.Append(*p);
michael@0 59 } else {
michael@0 60 result.Append('.');
michael@0 61 }
michael@0 62 }
michael@0 63 }
michael@0 64
michael@0 65 result.Append('\n');
michael@0 66
michael@0 67 buf += row_max;
michael@0 68 n -= row_max;
michael@0 69 }
michael@0 70 }
michael@0 71
michael@0 72 //-----------------------------------------------------------------------------
michael@0 73 // nsAboutCacheEntry::nsISupports
michael@0 74
michael@0 75 NS_IMPL_ISUPPORTS(nsAboutCacheEntry,
michael@0 76 nsIAboutModule,
michael@0 77 nsICacheMetaDataVisitor)
michael@0 78
michael@0 79 //-----------------------------------------------------------------------------
michael@0 80 // nsAboutCacheEntry::nsIAboutModule
michael@0 81
michael@0 82 NS_IMETHODIMP
michael@0 83 nsAboutCacheEntry::NewChannel(nsIURI *uri, nsIChannel **result)
michael@0 84 {
michael@0 85 NS_ENSURE_ARG_POINTER(uri);
michael@0 86 nsresult rv;
michael@0 87
michael@0 88 nsCOMPtr<nsIInputStream> stream;
michael@0 89 rv = GetContentStream(uri, getter_AddRefs(stream));
michael@0 90 if (NS_FAILED(rv)) return rv;
michael@0 91
michael@0 92 return NS_NewInputStreamChannel(result, uri, stream,
michael@0 93 NS_LITERAL_CSTRING("text/html"),
michael@0 94 NS_LITERAL_CSTRING("utf-8"));
michael@0 95 }
michael@0 96
michael@0 97 NS_IMETHODIMP
michael@0 98 nsAboutCacheEntry::GetURIFlags(nsIURI *aURI, uint32_t *result)
michael@0 99 {
michael@0 100 *result = nsIAboutModule::HIDE_FROM_ABOUTABOUT;
michael@0 101 return NS_OK;
michael@0 102 }
michael@0 103
michael@0 104 //-----------------------------------------------------------------------------
michael@0 105 // nsAboutCacheEntry
michael@0 106
michael@0 107 nsresult
michael@0 108 nsAboutCacheEntry::GetContentStream(nsIURI *uri, nsIInputStream **result)
michael@0 109 {
michael@0 110 nsresult rv;
michael@0 111
michael@0 112 // Init: (block size, maximum length)
michael@0 113 nsCOMPtr<nsIAsyncInputStream> inputStream;
michael@0 114 rv = NS_NewPipe2(getter_AddRefs(inputStream),
michael@0 115 getter_AddRefs(mOutputStream),
michael@0 116 true, false,
michael@0 117 256, UINT32_MAX);
michael@0 118 if (NS_FAILED(rv)) return rv;
michael@0 119
michael@0 120 NS_NAMED_LITERAL_CSTRING(
michael@0 121 buffer,
michael@0 122 "<!DOCTYPE html>\n"
michael@0 123 "<html>\n"
michael@0 124 "<head>\n"
michael@0 125 " <title>Cache entry information</title>\n"
michael@0 126 " <link rel=\"stylesheet\" "
michael@0 127 "href=\"chrome://global/skin/about.css\" type=\"text/css\"/>\n"
michael@0 128 " <link rel=\"stylesheet\" "
michael@0 129 "href=\"chrome://global/skin/aboutCacheEntry.css\" type=\"text/css\"/>\n"
michael@0 130 "</head>\n"
michael@0 131 "<body>\n"
michael@0 132 "<h1>Cache entry information</h1>\n");
michael@0 133 uint32_t n;
michael@0 134 rv = mOutputStream->Write(buffer.get(), buffer.Length(), &n);
michael@0 135 if (NS_FAILED(rv)) return rv;
michael@0 136 if (n != buffer.Length()) return NS_ERROR_UNEXPECTED;
michael@0 137
michael@0 138 rv = OpenCacheEntry(uri);
michael@0 139 if (NS_FAILED(rv)) return rv;
michael@0 140
michael@0 141 inputStream.forget(result);
michael@0 142 return NS_OK;
michael@0 143 }
michael@0 144
michael@0 145 nsresult
michael@0 146 nsAboutCacheEntry::OpenCacheEntry(nsIURI *uri)
michael@0 147 {
michael@0 148 nsresult rv;
michael@0 149 nsAutoCString clientID, key;
michael@0 150 bool streamBased = true;
michael@0 151
michael@0 152 rv = ParseURI(uri, clientID, streamBased, key);
michael@0 153 if (NS_FAILED(rv)) return rv;
michael@0 154
michael@0 155 nsCOMPtr<nsICacheService> serv =
michael@0 156 do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
michael@0 157 if (NS_FAILED(rv)) return rv;
michael@0 158
michael@0 159 nsCOMPtr<nsICacheSession> session;
michael@0 160 rv = serv->CreateSession(clientID.get(),
michael@0 161 nsICache::STORE_ANYWHERE,
michael@0 162 streamBased,
michael@0 163 getter_AddRefs(session));
michael@0 164 if (NS_FAILED(rv)) return rv;
michael@0 165
michael@0 166 rv = session->SetDoomEntriesIfExpired(false);
michael@0 167 if (NS_FAILED(rv)) return rv;
michael@0 168
michael@0 169 return session->AsyncOpenCacheEntry(key, nsICache::ACCESS_READ, this, true);
michael@0 170 }
michael@0 171
michael@0 172
michael@0 173 //-----------------------------------------------------------------------------
michael@0 174 // helper methods
michael@0 175 //-----------------------------------------------------------------------------
michael@0 176
michael@0 177 #define APPEND_ROW(label, value) \
michael@0 178 PR_BEGIN_MACRO \
michael@0 179 buffer.AppendLiteral(" <tr>\n" \
michael@0 180 " <th>"); \
michael@0 181 buffer.AppendLiteral(label); \
michael@0 182 buffer.AppendLiteral(":</th>\n" \
michael@0 183 " <td>"); \
michael@0 184 buffer.Append(value); \
michael@0 185 buffer.AppendLiteral("</td>\n" \
michael@0 186 " </tr>\n"); \
michael@0 187 PR_END_MACRO
michael@0 188
michael@0 189 nsresult
michael@0 190 nsAboutCacheEntry::WriteCacheEntryDescription(nsICacheEntryDescriptor *descriptor)
michael@0 191 {
michael@0 192 nsresult rv;
michael@0 193 nsCString buffer;
michael@0 194 uint32_t n;
michael@0 195
michael@0 196 nsAutoCString str;
michael@0 197
michael@0 198 rv = descriptor->GetKey(str);
michael@0 199 if (NS_FAILED(rv)) return rv;
michael@0 200
michael@0 201 buffer.SetCapacity(4096);
michael@0 202 buffer.AssignLiteral("<table>\n"
michael@0 203 " <tr>\n"
michael@0 204 " <th>key:</th>\n"
michael@0 205 " <td id=\"td-key\">");
michael@0 206
michael@0 207 // Test if the key is actually a URI
michael@0 208 nsCOMPtr<nsIURI> uri;
michael@0 209 bool isJS = false;
michael@0 210 bool isData = false;
michael@0 211
michael@0 212 rv = NS_NewURI(getter_AddRefs(uri), str);
michael@0 213 // javascript: and data: URLs should not be linkified
michael@0 214 // since clicking them can cause scripts to run - bug 162584
michael@0 215 if (NS_SUCCEEDED(rv)) {
michael@0 216 uri->SchemeIs("javascript", &isJS);
michael@0 217 uri->SchemeIs("data", &isData);
michael@0 218 }
michael@0 219 char* escapedStr = nsEscapeHTML(str.get());
michael@0 220 if (NS_SUCCEEDED(rv) && !(isJS || isData)) {
michael@0 221 buffer.AppendLiteral("<a href=\"");
michael@0 222 buffer.Append(escapedStr);
michael@0 223 buffer.AppendLiteral("\">");
michael@0 224 buffer.Append(escapedStr);
michael@0 225 buffer.AppendLiteral("</a>");
michael@0 226 uri = 0;
michael@0 227 }
michael@0 228 else
michael@0 229 buffer.Append(escapedStr);
michael@0 230 nsMemory::Free(escapedStr);
michael@0 231 buffer.AppendLiteral("</td>\n"
michael@0 232 " </tr>\n");
michael@0 233
michael@0 234 // temp vars for reporting
michael@0 235 char timeBuf[255];
michael@0 236 uint32_t u = 0;
michael@0 237 int32_t i = 0;
michael@0 238 nsAutoCString s;
michael@0 239
michael@0 240 // Fetch Count
michael@0 241 s.Truncate();
michael@0 242 descriptor->GetFetchCount(&i);
michael@0 243 s.AppendInt(i);
michael@0 244 APPEND_ROW("fetch count", s);
michael@0 245
michael@0 246 // Last Fetched
michael@0 247 descriptor->GetLastFetched(&u);
michael@0 248 if (u) {
michael@0 249 PrintTimeString(timeBuf, sizeof(timeBuf), u);
michael@0 250 APPEND_ROW("last fetched", timeBuf);
michael@0 251 } else {
michael@0 252 APPEND_ROW("last fetched", "No last fetch time");
michael@0 253 }
michael@0 254
michael@0 255 // Last Modified
michael@0 256 descriptor->GetLastModified(&u);
michael@0 257 if (u) {
michael@0 258 PrintTimeString(timeBuf, sizeof(timeBuf), u);
michael@0 259 APPEND_ROW("last modified", timeBuf);
michael@0 260 } else {
michael@0 261 APPEND_ROW("last modified", "No last modified time");
michael@0 262 }
michael@0 263
michael@0 264 // Expiration Time
michael@0 265 descriptor->GetExpirationTime(&u);
michael@0 266 if (u < 0xFFFFFFFF) {
michael@0 267 PrintTimeString(timeBuf, sizeof(timeBuf), u);
michael@0 268 APPEND_ROW("expires", timeBuf);
michael@0 269 } else {
michael@0 270 APPEND_ROW("expires", "No expiration time");
michael@0 271 }
michael@0 272
michael@0 273 // Data Size
michael@0 274 s.Truncate();
michael@0 275 uint32_t dataSize;
michael@0 276 descriptor->GetStorageDataSize(&dataSize);
michael@0 277 s.AppendInt((int32_t)dataSize); // XXX nsICacheEntryInfo interfaces should be fixed.
michael@0 278 APPEND_ROW("Data size", s);
michael@0 279
michael@0 280 // Storage Policy
michael@0 281
michael@0 282 // XXX Stream Based?
michael@0 283
michael@0 284 // XXX Cache Device
michael@0 285 // File on disk
michael@0 286 nsCOMPtr<nsIFile> cacheFile;
michael@0 287 rv = descriptor->GetFile(getter_AddRefs(cacheFile));
michael@0 288 if (NS_SUCCEEDED(rv)) {
michael@0 289 nsAutoString filePath;
michael@0 290 cacheFile->GetPath(filePath);
michael@0 291 APPEND_ROW("file on disk", NS_ConvertUTF16toUTF8(filePath));
michael@0 292 }
michael@0 293 else
michael@0 294 APPEND_ROW("file on disk", "none");
michael@0 295
michael@0 296 // Security Info
michael@0 297 nsCOMPtr<nsISupports> securityInfo;
michael@0 298 descriptor->GetSecurityInfo(getter_AddRefs(securityInfo));
michael@0 299 if (securityInfo) {
michael@0 300 APPEND_ROW("Security", "This is a secure document.");
michael@0 301 } else {
michael@0 302 APPEND_ROW("Security",
michael@0 303 "This document does not have any security info associated with it.");
michael@0 304 }
michael@0 305
michael@0 306 buffer.AppendLiteral("</table>\n"
michael@0 307 "<hr/>\n"
michael@0 308 "<table>\n");
michael@0 309 // Meta Data
michael@0 310 // let's just look for some well known (HTTP) meta data tags, for now.
michael@0 311
michael@0 312 // Client ID
michael@0 313 nsXPIDLCString str2;
michael@0 314 descriptor->GetClientID(getter_Copies(str2));
michael@0 315 if (!str2.IsEmpty()) APPEND_ROW("Client", str2);
michael@0 316
michael@0 317
michael@0 318 mBuffer = &buffer; // make it available for VisitMetaDataElement().
michael@0 319 // nsCacheEntryDescriptor::VisitMetaData calls
michael@0 320 // nsCacheEntry.h VisitMetaDataElements, which returns
michael@0 321 // nsCacheMetaData::VisitElements, which calls
michael@0 322 // nsAboutCacheEntry::VisitMetaDataElement (below) in a loop.
michael@0 323 descriptor->VisitMetaData(this);
michael@0 324 mBuffer = nullptr;
michael@0 325
michael@0 326 buffer.AppendLiteral("</table>\n");
michael@0 327 mOutputStream->Write(buffer.get(), buffer.Length(), &n);
michael@0 328
michael@0 329 buffer.Truncate();
michael@0 330
michael@0 331 // Provide a hexdump of the data
michael@0 332 if (dataSize) { // don't draw an <hr> if the Data Size is 0.
michael@0 333 nsCOMPtr<nsIInputStream> stream;
michael@0 334 descriptor->OpenInputStream(0, getter_AddRefs(stream));
michael@0 335 if (stream) {
michael@0 336 buffer.AssignLiteral("<hr/>\n"
michael@0 337 "<pre>");
michael@0 338 uint32_t hexDumpState = 0;
michael@0 339 char chunk[4096];
michael@0 340 while(NS_SUCCEEDED(stream->Read(chunk, sizeof(chunk), &n)) &&
michael@0 341 n > 0) {
michael@0 342 HexDump(&hexDumpState, chunk, n, buffer);
michael@0 343 mOutputStream->Write(buffer.get(), buffer.Length(), &n);
michael@0 344 buffer.Truncate();
michael@0 345 }
michael@0 346 buffer.AssignLiteral("</pre>\n");
michael@0 347 mOutputStream->Write(buffer.get(), buffer.Length(), &n);
michael@0 348 }
michael@0 349 }
michael@0 350 return NS_OK;
michael@0 351 }
michael@0 352
michael@0 353 nsresult
michael@0 354 nsAboutCacheEntry::WriteCacheEntryUnavailable()
michael@0 355 {
michael@0 356 uint32_t n;
michael@0 357 NS_NAMED_LITERAL_CSTRING(buffer,
michael@0 358 "The cache entry you selected is not available.");
michael@0 359 mOutputStream->Write(buffer.get(), buffer.Length(), &n);
michael@0 360 return NS_OK;
michael@0 361 }
michael@0 362
michael@0 363 nsresult
michael@0 364 nsAboutCacheEntry::ParseURI(nsIURI *uri, nsCString &clientID,
michael@0 365 bool &streamBased, nsCString &key)
michael@0 366 {
michael@0 367 //
michael@0 368 // about:cache-entry?client=[string]&sb=[boolean]&key=[string]
michael@0 369 //
michael@0 370 nsresult rv;
michael@0 371
michael@0 372 nsAutoCString path;
michael@0 373 rv = uri->GetPath(path);
michael@0 374 if (NS_FAILED(rv)) return rv;
michael@0 375
michael@0 376 nsACString::const_iterator i1, i2, i3, end;
michael@0 377 path.BeginReading(i1);
michael@0 378 path.EndReading(end);
michael@0 379
michael@0 380 i2 = end;
michael@0 381 if (!FindInReadable(NS_LITERAL_CSTRING("?client="), i1, i2))
michael@0 382 return NS_ERROR_FAILURE;
michael@0 383 // i2 points to the start of clientID
michael@0 384
michael@0 385 i1 = i2;
michael@0 386 i3 = end;
michael@0 387 if (!FindInReadable(NS_LITERAL_CSTRING("&sb="), i1, i3))
michael@0 388 return NS_ERROR_FAILURE;
michael@0 389 // i1 points to the end of clientID
michael@0 390 // i3 points to the start of isStreamBased
michael@0 391
michael@0 392 clientID.Assign(Substring(i2, i1));
michael@0 393
michael@0 394 i1 = i3;
michael@0 395 i2 = end;
michael@0 396 if (!FindInReadable(NS_LITERAL_CSTRING("&key="), i1, i2))
michael@0 397 return NS_ERROR_FAILURE;
michael@0 398 // i1 points to the end of isStreamBased
michael@0 399 // i2 points to the start of key
michael@0 400
michael@0 401 streamBased = FindCharInReadable('1', i3, i1);
michael@0 402 key.Assign(Substring(i2, end));
michael@0 403
michael@0 404 return NS_OK;
michael@0 405 }
michael@0 406
michael@0 407
michael@0 408 //-----------------------------------------------------------------------------
michael@0 409 // nsICacheMetaDataVisitor implementation
michael@0 410 //-----------------------------------------------------------------------------
michael@0 411
michael@0 412 NS_IMETHODIMP
michael@0 413 nsAboutCacheEntry::VisitMetaDataElement(const char * key,
michael@0 414 const char * value,
michael@0 415 bool * keepGoing)
michael@0 416 {
michael@0 417 mBuffer->AppendLiteral(" <tr>\n"
michael@0 418 " <th>");
michael@0 419 mBuffer->Append(key);
michael@0 420 mBuffer->AppendLiteral(":</th>\n"
michael@0 421 " <td>");
michael@0 422 char* escapedValue = nsEscapeHTML(value);
michael@0 423 mBuffer->Append(escapedValue);
michael@0 424 nsMemory::Free(escapedValue);
michael@0 425 mBuffer->AppendLiteral("</td>\n"
michael@0 426 " </tr>\n");
michael@0 427
michael@0 428 *keepGoing = true;
michael@0 429 return NS_OK;
michael@0 430 }
michael@0 431
michael@0 432 //-----------------------------------------------------------------------------
michael@0 433 // nsICacheListener implementation
michael@0 434 //-----------------------------------------------------------------------------
michael@0 435
michael@0 436 NS_IMETHODIMP
michael@0 437 nsAboutCacheEntry::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
michael@0 438 nsCacheAccessMode access,
michael@0 439 nsresult status)
michael@0 440 {
michael@0 441 nsresult rv;
michael@0 442
michael@0 443 if (entry)
michael@0 444 rv = WriteCacheEntryDescription(entry);
michael@0 445 else
michael@0 446 rv = WriteCacheEntryUnavailable();
michael@0 447 if (NS_FAILED(rv)) return rv;
michael@0 448
michael@0 449 uint32_t n;
michael@0 450 NS_NAMED_LITERAL_CSTRING(buffer, "</body>\n</html>\n");
michael@0 451 mOutputStream->Write(buffer.get(), buffer.Length(), &n);
michael@0 452 mOutputStream->Close();
michael@0 453 mOutputStream = nullptr;
michael@0 454
michael@0 455 return NS_OK;
michael@0 456 }
michael@0 457
michael@0 458 NS_IMETHODIMP
michael@0 459 nsAboutCacheEntry::OnCacheEntryDoomed(nsresult status)
michael@0 460 {
michael@0 461 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 462 }

mercurial