Home | History | Annotate | Download | only in blob
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "storage/browser/blob/view_blob_internals_job.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/compiler_specific.h"
      9 #include "base/format_macros.h"
     10 #include "base/i18n/number_formatting.h"
     11 #include "base/i18n/time_formatting.h"
     12 #include "base/logging.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_util.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "net/base/escape.h"
     19 #include "net/base/net_errors.h"
     20 #include "net/url_request/url_request.h"
     21 #include "storage/browser/blob/blob_storage_context.h"
     22 #include "storage/common/blob/blob_data.h"
     23 
     24 namespace {
     25 
     26 const char kEmptyBlobStorageMessage[] = "No available blob data.";
     27 const char kContentType[] = "Content Type: ";
     28 const char kContentDisposition[] = "Content Disposition: ";
     29 const char kCount[] = "Count: ";
     30 const char kIndex[] = "Index: ";
     31 const char kType[] = "Type: ";
     32 const char kPath[] = "Path: ";
     33 const char kURL[] = "URL: ";
     34 const char kModificationTime[] = "Modification Time: ";
     35 const char kOffset[] = "Offset: ";
     36 const char kLength[] = "Length: ";
     37 const char kUUID[] = "Uuid: ";
     38 const char kRefcount[] = "Refcount: ";
     39 
     40 void StartHTML(std::string* out) {
     41   out->append(
     42       "<!DOCTYPE HTML>"
     43       "<html><title>Blob Storage Internals</title>"
     44       "<meta http-equiv=\"Content-Security-Policy\""
     45       "  content=\"object-src 'none'; script-src 'none'\">\n"
     46       "<style>\n"
     47       "body { font-family: sans-serif; font-size: 0.8em; }\n"
     48       "tt, code, pre { font-family: WebKitHack, monospace; }\n"
     49       "form { display: inline }\n"
     50       ".subsection_body { margin: 10px 0 10px 2em; }\n"
     51       ".subsection_title { font-weight: bold; }\n"
     52       "</style>\n"
     53       "</head><body>\n\n");
     54 }
     55 
     56 void EndHTML(std::string* out) {
     57   out->append("\n</body></html>");
     58 }
     59 
     60 void AddHTMLBoldText(const std::string& text, std::string* out) {
     61   out->append("<b>");
     62   out->append(net::EscapeForHTML(text));
     63   out->append("</b>");
     64 }
     65 
     66 void StartHTMLList(std::string* out) {
     67   out->append("\n<ul>");
     68 }
     69 
     70 void EndHTMLList(std::string* out) {
     71   out->append("</ul>\n");
     72 }
     73 
     74 void AddHTMLListItem(const std::string& element_title,
     75                      const std::string& element_data,
     76                      std::string* out) {
     77   out->append("<li>");
     78   // No need to escape element_title since constant string is passed.
     79   out->append(element_title);
     80   out->append(net::EscapeForHTML(element_data));
     81   out->append("</li>\n");
     82 }
     83 
     84 void AddHorizontalRule(std::string* out) {
     85   out->append("\n<hr>\n");
     86 }
     87 
     88 }  // namespace
     89 
     90 namespace storage {
     91 
     92 ViewBlobInternalsJob::ViewBlobInternalsJob(
     93     net::URLRequest* request,
     94     net::NetworkDelegate* network_delegate,
     95     BlobStorageContext* blob_storage_context)
     96     : net::URLRequestSimpleJob(request, network_delegate),
     97       blob_storage_context_(blob_storage_context),
     98       weak_factory_(this) {
     99 }
    100 
    101 ViewBlobInternalsJob::~ViewBlobInternalsJob() {
    102 }
    103 
    104 void ViewBlobInternalsJob::Start() {
    105   base::MessageLoop::current()->PostTask(
    106       FROM_HERE,
    107       base::Bind(&ViewBlobInternalsJob::StartAsync,
    108                  weak_factory_.GetWeakPtr()));
    109 }
    110 
    111 bool ViewBlobInternalsJob::IsRedirectResponse(GURL* location,
    112                                               int* http_status_code) {
    113   if (request_->url().has_query()) {
    114     // Strip the query parameters.
    115     GURL::Replacements replacements;
    116     replacements.ClearQuery();
    117     *location = request_->url().ReplaceComponents(replacements);
    118     *http_status_code = 307;
    119     return true;
    120   }
    121   return false;
    122 }
    123 
    124 void ViewBlobInternalsJob::Kill() {
    125   net::URLRequestSimpleJob::Kill();
    126   weak_factory_.InvalidateWeakPtrs();
    127 }
    128 
    129 int ViewBlobInternalsJob::GetData(
    130     std::string* mime_type,
    131     std::string* charset,
    132     std::string* data,
    133     const net::CompletionCallback& callback) const {
    134   mime_type->assign("text/html");
    135   charset->assign("UTF-8");
    136 
    137   data->clear();
    138   StartHTML(data);
    139   if (blob_storage_context_->blob_map_.empty())
    140     data->append(kEmptyBlobStorageMessage);
    141   else
    142     GenerateHTML(data);
    143   EndHTML(data);
    144   return net::OK;
    145 }
    146 
    147 void ViewBlobInternalsJob::GenerateHTML(std::string* out) const {
    148   for (BlobStorageContext::BlobMap::const_iterator iter =
    149            blob_storage_context_->blob_map_.begin();
    150        iter != blob_storage_context_->blob_map_.end();
    151        ++iter) {
    152     AddHTMLBoldText(iter->first, out);
    153     GenerateHTMLForBlobData(*(iter->second.data.get()),
    154                             iter->second.refcount,
    155                             out);
    156   }
    157   if (!blob_storage_context_->public_blob_urls_.empty()) {
    158     AddHorizontalRule(out);
    159     for (BlobStorageContext::BlobURLMap::const_iterator iter =
    160              blob_storage_context_->public_blob_urls_.begin();
    161          iter != blob_storage_context_->public_blob_urls_.end();
    162          ++iter) {
    163       AddHTMLBoldText(iter->first.spec(), out);
    164       StartHTMLList(out);
    165       AddHTMLListItem(kUUID, iter->second, out);
    166       EndHTMLList(out);
    167     }
    168   }
    169 }
    170 
    171 void ViewBlobInternalsJob::GenerateHTMLForBlobData(const BlobData& blob_data,
    172                                                    int refcount,
    173                                                    std::string* out) {
    174   StartHTMLList(out);
    175 
    176   AddHTMLListItem(kRefcount, base::IntToString(refcount), out);
    177   if (!blob_data.content_type().empty())
    178     AddHTMLListItem(kContentType, blob_data.content_type(), out);
    179   if (!blob_data.content_disposition().empty())
    180     AddHTMLListItem(kContentDisposition, blob_data.content_disposition(), out);
    181 
    182   bool has_multi_items = blob_data.items().size() > 1;
    183   if (has_multi_items) {
    184     AddHTMLListItem(kCount,
    185         base::UTF16ToUTF8(base::FormatNumber(blob_data.items().size())), out);
    186   }
    187 
    188   for (size_t i = 0; i < blob_data.items().size(); ++i) {
    189     if (has_multi_items) {
    190       AddHTMLListItem(kIndex, base::UTF16ToUTF8(base::FormatNumber(i)), out);
    191       StartHTMLList(out);
    192     }
    193     const BlobData::Item& item = blob_data.items().at(i);
    194 
    195     switch (item.type()) {
    196       case BlobData::Item::TYPE_BYTES:
    197         AddHTMLListItem(kType, "data", out);
    198         break;
    199       case BlobData::Item::TYPE_FILE:
    200         AddHTMLListItem(kType, "file", out);
    201         AddHTMLListItem(kPath,
    202                  net::EscapeForHTML(item.path().AsUTF8Unsafe()),
    203                  out);
    204         if (!item.expected_modification_time().is_null()) {
    205           AddHTMLListItem(kModificationTime, base::UTF16ToUTF8(
    206               TimeFormatFriendlyDateAndTime(item.expected_modification_time())),
    207               out);
    208         }
    209         break;
    210       case BlobData::Item::TYPE_BLOB:
    211         NOTREACHED();   // Should be flattened in the storage context.
    212         break;
    213       case BlobData::Item::TYPE_FILE_FILESYSTEM:
    214         AddHTMLListItem(kType, "filesystem", out);
    215         AddHTMLListItem(kURL, item.filesystem_url().spec(), out);
    216         if (!item.expected_modification_time().is_null()) {
    217           AddHTMLListItem(kModificationTime, base::UTF16ToUTF8(
    218               TimeFormatFriendlyDateAndTime(item.expected_modification_time())),
    219               out);
    220         }
    221         break;
    222       case BlobData::Item::TYPE_UNKNOWN:
    223         NOTREACHED();
    224         break;
    225     }
    226     if (item.offset()) {
    227       AddHTMLListItem(kOffset, base::UTF16ToUTF8(base::FormatNumber(
    228           static_cast<int64>(item.offset()))), out);
    229     }
    230     if (static_cast<int64>(item.length()) != -1) {
    231       AddHTMLListItem(kLength, base::UTF16ToUTF8(base::FormatNumber(
    232           static_cast<int64>(item.length()))), out);
    233     }
    234 
    235     if (has_multi_items)
    236       EndHTMLList(out);
    237   }
    238 
    239   EndHTMLList(out);
    240 }
    241 
    242 }  // namespace storage
    243