netwerk/protocol/about/nsAboutCacheEntry.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial