15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/blob/view_blob_internals_job.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/format_macros.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/number_formatting.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/time_formatting.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
165e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/blob/blob_storage_context.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/blob/blob_data.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kEmptyBlobStorageMessage[] = "No available blob data.";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kContentType[] = "Content Type: ";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kContentDisposition[] = "Content Disposition: ";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCount[] = "Count: ";
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kIndex[] = "Index: ";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kType[] = "Type: ";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPath[] = "Path: ";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kURL[] = "URL: ";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kModificationTime[] = "Modification Time: ";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kOffset[] = "Offset: ";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLength[] = "Length: ";
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const char kUUID[] = "Uuid: ";
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const char kRefcount[] = "Refcount: ";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartHTML(std::string* out) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append(
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "<!DOCTYPE HTML>"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "<html><title>Blob Storage Internals</title>"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "<meta http-equiv=\"Content-Security-Policy\""
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  content=\"object-src 'none'; script-src 'none'\">\n"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "<style>\n"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "body { font-family: sans-serif; font-size: 0.8em; }\n"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "tt, code, pre { font-family: WebKitHack, monospace; }\n"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "form { display: inline }\n"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ".subsection_body { margin: 10px 0 10px 2em; }\n"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ".subsection_title { font-weight: bold; }\n"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "</style>\n"
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      "</head><body>\n\n");
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EndHTML(std::string* out) {
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  out->append("\n</body></html>");
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddHTMLBoldText(const std::string& text, std::string* out) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append("<b>");
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append(net::EscapeForHTML(text));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append("</b>");
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartHTMLList(std::string* out) {
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  out->append("\n<ul>");
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EndHTMLList(std::string* out) {
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  out->append("</ul>\n");
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddHTMLListItem(const std::string& element_title,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::string& element_data,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     std::string* out) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append("<li>");
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No need to escape element_title since constant string is passed.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append(element_title);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->append(net::EscapeForHTML(element_data));
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  out->append("</li>\n");
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void AddHorizontalRule(std::string* out) {
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  out->append("\n<hr>\n");
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)namespace storage {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ViewBlobInternalsJob::ViewBlobInternalsJob(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequest* request,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::NetworkDelegate* network_delegate,
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    BlobStorageContext* blob_storage_context)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : net::URLRequestSimpleJob(request, network_delegate),
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      blob_storage_context_(blob_storage_context),
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ViewBlobInternalsJob::~ViewBlobInternalsJob() {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ViewBlobInternalsJob::Start() {
105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      FROM_HERE,
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::Bind(&ViewBlobInternalsJob::StartAsync,
108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ViewBlobInternalsJob::IsRedirectResponse(GURL* location,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int* http_status_code) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request_->url().has_query()) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Strip the query parameters.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL::Replacements replacements;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    replacements.ClearQuery();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *location = request_->url().ReplaceComponents(replacements);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_status_code = 307;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ViewBlobInternalsJob::Kill() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::URLRequestSimpleJob::Kill();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ViewBlobInternalsJob::GetData(
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* mime_type,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* charset,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* data,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::CompletionCallback& callback) const {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mime_type->assign("text/html");
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  charset->assign("UTF-8");
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data->clear();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartHTML(data);
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (blob_storage_context_->blob_map_.empty())
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->append(kEmptyBlobStorageMessage);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GenerateHTML(data);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EndHTML(data);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return net::OK;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ViewBlobInternalsJob::GenerateHTML(std::string* out) const {
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (BlobStorageContext::BlobMap::const_iterator iter =
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)           blob_storage_context_->blob_map_.begin();
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       iter != blob_storage_context_->blob_map_.end();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddHTMLBoldText(iter->first, out);
15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GenerateHTMLForBlobData(*(iter->second.data.get()),
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            iter->second.refcount,
15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            out);
15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!blob_storage_context_->public_blob_urls_.empty()) {
15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AddHorizontalRule(out);
15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (BlobStorageContext::BlobURLMap::const_iterator iter =
16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             blob_storage_context_->public_blob_urls_.begin();
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)         iter != blob_storage_context_->public_blob_urls_.end();
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)         ++iter) {
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AddHTMLBoldText(iter->first.spec(), out);
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      StartHTMLList(out);
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AddHTMLListItem(kUUID, iter->second, out);
16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      EndHTMLList(out);
16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ViewBlobInternalsJob::GenerateHTMLForBlobData(const BlobData& blob_data,
17258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                                   int refcount,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   std::string* out) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartHTMLList(out);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  AddHTMLListItem(kRefcount, base::IntToString(refcount), out);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!blob_data.content_type().empty())
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddHTMLListItem(kContentType, blob_data.content_type(), out);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!blob_data.content_disposition().empty())
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddHTMLListItem(kContentDisposition, blob_data.content_disposition(), out);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_multi_items = blob_data.items().size() > 1;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_multi_items) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddHTMLListItem(kCount,
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::UTF16ToUTF8(base::FormatNumber(blob_data.items().size())), out);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < blob_data.items().size(); ++i) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (has_multi_items) {
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      AddHTMLListItem(kIndex, base::UTF16ToUTF8(base::FormatNumber(i)), out);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartHTMLList(out);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BlobData::Item& item = blob_data.items().at(i);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (item.type()) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BlobData::Item::TYPE_BYTES:
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AddHTMLListItem(kType, "data", out);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BlobData::Item::TYPE_FILE:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AddHTMLListItem(kType, "file", out);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AddHTMLListItem(kPath,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 net::EscapeForHTML(item.path().AsUTF8Unsafe()),
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 out);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!item.expected_modification_time().is_null()) {
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          AddHTMLListItem(kModificationTime, base::UTF16ToUTF8(
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              TimeFormatFriendlyDateAndTime(item.expected_modification_time())),
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              out);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BlobData::Item::TYPE_BLOB:
21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        NOTREACHED();   // Should be flattened in the storage context.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BlobData::Item::TYPE_FILE_FILESYSTEM:
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AddHTMLListItem(kType, "filesystem", out);
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        AddHTMLListItem(kURL, item.filesystem_url().spec(), out);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!item.expected_modification_time().is_null()) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          AddHTMLListItem(kModificationTime, base::UTF16ToUTF8(
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              TimeFormatFriendlyDateAndTime(item.expected_modification_time())),
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              out);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BlobData::Item::TYPE_UNKNOWN:
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (item.offset()) {
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      AddHTMLListItem(kOffset, base::UTF16ToUTF8(base::FormatNumber(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<int64>(item.offset()))), out);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (static_cast<int64>(item.length()) != -1) {
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      AddHTMLListItem(kLength, base::UTF16ToUTF8(base::FormatNumber(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<int64>(item.length()))), out);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (has_multi_items)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndHTMLList(out);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EndHTMLList(out);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}  // namespace storage
243