• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "webkit/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 "webkit/browser/blob/blob_storage_context.h"
22 #include "webkit/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 
StartHTML(std::string * out)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 
EndHTML(std::string * out)56 void EndHTML(std::string* out) {
57   out->append("\n</body></html>");
58 }
59 
AddHTMLBoldText(const std::string & text,std::string * out)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 
StartHTMLList(std::string * out)66 void StartHTMLList(std::string* out) {
67   out->append("\n<ul>");
68 }
69 
EndHTMLList(std::string * out)70 void EndHTMLList(std::string* out) {
71   out->append("</ul>\n");
72 }
73 
AddHTMLListItem(const std::string & element_title,const std::string & element_data,std::string * out)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 
AddHorizontalRule(std::string * out)84 void AddHorizontalRule(std::string* out) {
85   out->append("\n<hr>\n");
86 }
87 
88 }  // namespace
89 
90 namespace webkit_blob {
91 
ViewBlobInternalsJob(net::URLRequest * request,net::NetworkDelegate * network_delegate,BlobStorageContext * blob_storage_context)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 
~ViewBlobInternalsJob()101 ViewBlobInternalsJob::~ViewBlobInternalsJob() {
102 }
103 
Start()104 void ViewBlobInternalsJob::Start() {
105   base::MessageLoop::current()->PostTask(
106       FROM_HERE,
107       base::Bind(&ViewBlobInternalsJob::StartAsync,
108                  weak_factory_.GetWeakPtr()));
109 }
110 
IsRedirectResponse(GURL * location,int * http_status_code)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 
Kill()124 void ViewBlobInternalsJob::Kill() {
125   net::URLRequestSimpleJob::Kill();
126   weak_factory_.InvalidateWeakPtrs();
127 }
128 
GetData(std::string * mime_type,std::string * charset,std::string * data,const net::CompletionCallback & callback) const129 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 
GenerateHTML(std::string * out) const147 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 
GenerateHTMLForBlobData(const BlobData & blob_data,int refcount,std::string * out)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 webkit_blob
243