OLD | NEW |
| (Empty) |
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/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.h" | |
14 #include "base/string_util.h" | |
15 #include "base/stringprintf.h" | |
16 #include "base/utf_string_conversions.h" | |
17 #include "net/base/escape.h" | |
18 #include "net/base/net_errors.h" | |
19 #include "net/url_request/url_request.h" | |
20 #include "webkit/blob/blob_data.h" | |
21 #include "webkit/blob/blob_storage_controller.h" | |
22 | |
23 namespace { | |
24 | |
25 const char kEmptyBlobStorageMessage[] = "No available blob data."; | |
26 const char kRemove[] = "Remove"; | |
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 | |
38 void StartHTML(std::string* out) { | |
39 out->append( | |
40 "<!DOCTYPE HTML>" | |
41 "<html><title>Blob Storage Internals</title>" | |
42 "<meta http-equiv=\"Content-Security-Policy\"" | |
43 " content=\"object-src 'none'; script-src 'none'\">\n" | |
44 "<style>\n" | |
45 "body { font-family: sans-serif; font-size: 0.8em; }\n" | |
46 "tt, code, pre { font-family: WebKitHack, monospace; }\n" | |
47 "form { display: inline }\n" | |
48 ".subsection_body { margin: 10px 0 10px 2em; }\n" | |
49 ".subsection_title { font-weight: bold; }\n" | |
50 "</style>\n" | |
51 "</head><body>\n"); | |
52 } | |
53 | |
54 void EndHTML(std::string* out) { | |
55 out->append("</body></html>"); | |
56 } | |
57 | |
58 void AddHTMLBoldText(const std::string& text, std::string* out) { | |
59 out->append("<b>"); | |
60 out->append(net::EscapeForHTML(text)); | |
61 out->append("</b>"); | |
62 } | |
63 | |
64 void StartHTMLList(std::string* out) { | |
65 out->append("<ul>"); | |
66 } | |
67 | |
68 void EndHTMLList(std::string* out) { | |
69 out->append("</ul>"); | |
70 } | |
71 | |
72 void AddHTMLListItem(const std::string& element_title, | |
73 const std::string& element_data, | |
74 std::string* out) { | |
75 out->append("<li>"); | |
76 // No need to escape element_title since constant string is passed. | |
77 out->append(element_title); | |
78 out->append(net::EscapeForHTML(element_data)); | |
79 out->append("</li>"); | |
80 } | |
81 | |
82 void AddHTMLButton(const std::string& title, | |
83 const std::string& command, | |
84 std::string* out) { | |
85 // No need to escape title since constant string is passed. | |
86 std::string escaped_command = net::EscapeForHTML(command.c_str()); | |
87 base::StringAppendF(out, | |
88 "<form action=\"\" method=\"GET\">\n" | |
89 "<input type=\"hidden\" name=\"remove\" value=\"%s\">\n" | |
90 "<input type=\"submit\" value=\"%s\">\n" | |
91 "</form><br/>\n", | |
92 escaped_command.c_str(), | |
93 title.c_str()); | |
94 } | |
95 | |
96 } // namespace | |
97 | |
98 namespace webkit_blob { | |
99 | |
100 ViewBlobInternalsJob::ViewBlobInternalsJob( | |
101 net::URLRequest* request, | |
102 net::NetworkDelegate* network_delegate, | |
103 BlobStorageController* blob_storage_controller) | |
104 : net::URLRequestSimpleJob(request, network_delegate), | |
105 blob_storage_controller_(blob_storage_controller), | |
106 weak_factory_(this) { | |
107 } | |
108 | |
109 ViewBlobInternalsJob::~ViewBlobInternalsJob() { | |
110 } | |
111 | |
112 void ViewBlobInternalsJob::Start() { | |
113 base::MessageLoop::current()->PostTask( | |
114 FROM_HERE, | |
115 base::Bind(&ViewBlobInternalsJob::DoWorkAsync, | |
116 weak_factory_.GetWeakPtr())); | |
117 } | |
118 | |
119 bool ViewBlobInternalsJob::IsRedirectResponse(GURL* location, | |
120 int* http_status_code) { | |
121 if (request_->url().has_query()) { | |
122 // Strip the query parameters. | |
123 GURL::Replacements replacements; | |
124 replacements.ClearQuery(); | |
125 *location = request_->url().ReplaceComponents(replacements); | |
126 *http_status_code = 307; | |
127 return true; | |
128 } | |
129 return false; | |
130 } | |
131 | |
132 void ViewBlobInternalsJob::Kill() { | |
133 net::URLRequestSimpleJob::Kill(); | |
134 weak_factory_.InvalidateWeakPtrs(); | |
135 } | |
136 | |
137 void ViewBlobInternalsJob::DoWorkAsync() { | |
138 if (request_->url().has_query() && | |
139 StartsWithASCII(request_->url().query(), "remove=", true)) { | |
140 std::string blob_url = request_->url().query().substr(strlen("remove=")); | |
141 blob_url = net::UnescapeURLComponent(blob_url, | |
142 net::UnescapeRule::NORMAL | net::UnescapeRule::URL_SPECIAL_CHARS); | |
143 blob_storage_controller_->RemoveBlob(GURL(blob_url)); | |
144 } | |
145 | |
146 StartAsync(); | |
147 } | |
148 | |
149 int ViewBlobInternalsJob::GetData( | |
150 std::string* mime_type, | |
151 std::string* charset, | |
152 std::string* data, | |
153 const net::CompletionCallback& callback) const { | |
154 mime_type->assign("text/html"); | |
155 charset->assign("UTF-8"); | |
156 | |
157 data->clear(); | |
158 StartHTML(data); | |
159 if (blob_storage_controller_->blob_map_.empty()) | |
160 data->append(kEmptyBlobStorageMessage); | |
161 else | |
162 GenerateHTML(data); | |
163 EndHTML(data); | |
164 return net::OK; | |
165 } | |
166 | |
167 void ViewBlobInternalsJob::GenerateHTML(std::string* out) const { | |
168 for (BlobStorageController::BlobMap::const_iterator iter = | |
169 blob_storage_controller_->blob_map_.begin(); | |
170 iter != blob_storage_controller_->blob_map_.end(); | |
171 ++iter) { | |
172 AddHTMLBoldText(iter->first, out); | |
173 AddHTMLButton(kRemove, iter->first, out); | |
174 GenerateHTMLForBlobData(*iter->second, out); | |
175 } | |
176 } | |
177 | |
178 void ViewBlobInternalsJob::GenerateHTMLForBlobData(const BlobData& blob_data, | |
179 std::string* out) { | |
180 StartHTMLList(out); | |
181 | |
182 if (!blob_data.content_type().empty()) | |
183 AddHTMLListItem(kContentType, blob_data.content_type(), out); | |
184 if (!blob_data.content_disposition().empty()) | |
185 AddHTMLListItem(kContentDisposition, blob_data.content_disposition(), out); | |
186 | |
187 bool has_multi_items = blob_data.items().size() > 1; | |
188 if (has_multi_items) { | |
189 AddHTMLListItem(kCount, | |
190 UTF16ToUTF8(base::FormatNumber(blob_data.items().size())), out); | |
191 } | |
192 | |
193 for (size_t i = 0; i < blob_data.items().size(); ++i) { | |
194 if (has_multi_items) { | |
195 AddHTMLListItem(kIndex, UTF16ToUTF8(base::FormatNumber(i)), out); | |
196 StartHTMLList(out); | |
197 } | |
198 const BlobData::Item& item = blob_data.items().at(i); | |
199 | |
200 switch (item.type()) { | |
201 case BlobData::Item::TYPE_BYTES: | |
202 AddHTMLListItem(kType, "data", out); | |
203 break; | |
204 case BlobData::Item::TYPE_FILE: | |
205 AddHTMLListItem(kType, "file", out); | |
206 AddHTMLListItem(kPath, | |
207 net::EscapeForHTML(item.path().AsUTF8Unsafe()), | |
208 out); | |
209 if (!item.expected_modification_time().is_null()) { | |
210 AddHTMLListItem(kModificationTime, UTF16ToUTF8( | |
211 TimeFormatFriendlyDateAndTime(item.expected_modification_time())), | |
212 out); | |
213 } | |
214 break; | |
215 case BlobData::Item::TYPE_BLOB: | |
216 AddHTMLListItem(kType, "blob", out); | |
217 AddHTMLListItem(kURL, item.url().spec(), out); | |
218 break; | |
219 case BlobData::Item::TYPE_FILE_FILESYSTEM: | |
220 AddHTMLListItem(kType, "filesystem", out); | |
221 AddHTMLListItem(kURL, item.url().spec(), out); | |
222 if (!item.expected_modification_time().is_null()) { | |
223 AddHTMLListItem(kModificationTime, UTF16ToUTF8( | |
224 TimeFormatFriendlyDateAndTime(item.expected_modification_time())), | |
225 out); | |
226 } | |
227 break; | |
228 case BlobData::Item::TYPE_UNKNOWN: | |
229 NOTREACHED(); | |
230 break; | |
231 } | |
232 if (item.offset()) { | |
233 AddHTMLListItem(kOffset, UTF16ToUTF8(base::FormatNumber( | |
234 static_cast<int64>(item.offset()))), out); | |
235 } | |
236 if (static_cast<int64>(item.length()) != -1) { | |
237 AddHTMLListItem(kLength, UTF16ToUTF8(base::FormatNumber( | |
238 static_cast<int64>(item.length()))), out); | |
239 } | |
240 | |
241 if (has_multi_items) | |
242 EndHTMLList(out); | |
243 } | |
244 | |
245 EndHTMLList(out); | |
246 } | |
247 | |
248 } // namespace webkit_blob | |
OLD | NEW |