Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(561)

Side by Side Diff: components/dom_distiller/content/dom_distiller_viewer_source.cc

Issue 151003006: Add support for distilling arbitrary URLs in DOM Distiller Viewer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. added unit tests Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/dom_distiller/content/dom_distiller_viewer_source.h" 5 #include "components/dom_distiller/content/dom_distiller_viewer_source.h"
6 6
7 #include <sstream> 7 #include <sstream>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/memory/ref_counted_memory.h" 11 #include "base/memory/ref_counted_memory.h"
12 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "components/dom_distiller/core/dom_distiller_service.h" 15 #include "components/dom_distiller/core/dom_distiller_service.h"
16 #include "components/dom_distiller/core/proto/distilled_article.pb.h" 16 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
17 #include "components/dom_distiller/core/proto/distilled_page.pb.h" 17 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
18 #include "components/dom_distiller/core/task_tracker.h" 18 #include "components/dom_distiller/core/task_tracker.h"
19 #include "components/dom_distiller/core/url_constants.h"
19 #include "content/public/browser/render_frame_host.h" 20 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/render_view_host.h" 21 #include "content/public/browser/render_view_host.h"
21 #include "grit/component_resources.h" 22 #include "grit/component_resources.h"
22 #include "grit/component_strings.h" 23 #include "grit/component_strings.h"
23 #include "net/base/escape.h" 24 #include "net/base/escape.h"
25 #include "net/base/url_util.h"
24 #include "net/url_request/url_request.h" 26 #include "net/url_request/url_request.h"
25 #include "ui/base/l10n/l10n_util.h" 27 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h" 28 #include "ui/base/resource/resource_bundle.h"
27 #include "url/gurl.h" 29 #include "url/gurl.h"
28 30
31 namespace dom_distiller {
32
29 namespace { 33 namespace {
30 34
31 const char kCssPath[] = "readability.css"; 35 const char kInternalScheme[] = "chrome-distiller-internal";
32 36
33 std::string ReplaceHtmlTemplateValues(std::string title, std::string content) { 37 std::string ReplaceHtmlTemplateValues(std::string title, std::string content) {
34 base::StringPiece html_template = 38 base::StringPiece html_template =
35 ResourceBundle::GetSharedInstance().GetRawDataResource( 39 ResourceBundle::GetSharedInstance().GetRawDataResource(
36 IDR_DOM_DISTILLER_VIEWER_HTML); 40 IDR_DOM_DISTILLER_VIEWER_HTML);
37 std::vector<std::string> substitutions; 41 std::vector<std::string> substitutions;
38 substitutions.push_back(title); // $1 42 substitutions.push_back(title); // $1
39 substitutions.push_back(kCssPath); // $2 43 substitutions.push_back(kCssPath); // $2
40 substitutions.push_back(title); // $3 44 substitutions.push_back(title); // $3
41 substitutions.push_back(content); // $4 45 substitutions.push_back(content); // $4
42 return ReplaceStringPlaceholders(html_template, substitutions, NULL); 46 return ReplaceStringPlaceholders(html_template, substitutions, NULL);
43 } 47 }
44 48
45 } // namespace 49 } // namespace
46 50
47 namespace dom_distiller {
48
49 // Handles receiving data asynchronously for a specific entry, and passing 51 // Handles receiving data asynchronously for a specific entry, and passing
50 // it along to the data callback for the data source. 52 // it along to the data callback for the data source.
51 class RequestViewerHandle : public ViewRequestDelegate { 53 class DomDistillerViewerSource::RequestViewerHandle
54 : public ViewRequestDelegate {
52 public: 55 public:
53 explicit RequestViewerHandle( 56 explicit RequestViewerHandle(
54 const content::URLDataSource::GotDataCallback& callback); 57 const content::URLDataSource::GotDataCallback& callback);
55 virtual ~RequestViewerHandle(); 58 virtual ~RequestViewerHandle();
56 59
57 // ViewRequestDelegate implementation. 60 // ViewRequestDelegate implementation.
58 virtual void OnArticleReady(const DistilledArticleProto* article_proto) 61 virtual void OnArticleReady(const DistilledArticleProto* article_proto)
59 OVERRIDE; 62 OVERRIDE;
60 63
61 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); 64 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle);
62 65
63 private: 66 private:
64 // The handle to the view request towards the DomDistillerService. It 67 // The handle to the view request towards the DomDistillerService. It
65 // needs to be kept around to ensure the distillation request finishes. 68 // needs to be kept around to ensure the distillation request finishes.
66 scoped_ptr<ViewerHandle> viewer_handle_; 69 scoped_ptr<ViewerHandle> viewer_handle_;
67 70
68 // This holds the callback to where the data retrieved is sent back. 71 // This holds the callback to where the data retrieved is sent back.
69 content::URLDataSource::GotDataCallback callback_; 72 content::URLDataSource::GotDataCallback callback_;
70 }; 73 };
71 74
72 RequestViewerHandle::RequestViewerHandle( 75 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
73 const content::URLDataSource::GotDataCallback& callback) 76 const content::URLDataSource::GotDataCallback& callback)
74 : callback_(callback) {} 77 : callback_(callback) {}
75 78
76 RequestViewerHandle::~RequestViewerHandle() {} 79 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {}
77 80
78 void RequestViewerHandle::OnArticleReady( 81 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady(
79 const DistilledArticleProto* article_proto) { 82 const DistilledArticleProto* article_proto) {
80 DCHECK(article_proto); 83 DCHECK(article_proto);
81 std::string title; 84 std::string title;
82 std::string unsafe_article_html; 85 std::string unsafe_article_html;
83 if (article_proto->has_title() && article_proto->pages_size() > 0 && 86 if (article_proto->has_title() && article_proto->pages_size() > 0 &&
84 article_proto->pages(0).has_html()) { 87 article_proto->pages(0).has_html()) {
85 title = net::EscapeForHTML(article_proto->title()); 88 title = net::EscapeForHTML(article_proto->title());
86 // TODO(shashishekhar): Add support for correcting displaying multiple pages 89 // TODO(shashishekhar): Add support for correcting displaying multiple pages
87 // after discussing the right way to display them. 90 // after discussing the right way to display them.
88 std::ostringstream unsafe_output_stream; 91 std::ostringstream unsafe_output_stream;
89 for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) { 92 for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) {
90 unsafe_output_stream << article_proto->pages(page_num).html(); 93 unsafe_output_stream << article_proto->pages(page_num).html();
91 } 94 }
92 unsafe_article_html = unsafe_output_stream.str(); 95 unsafe_article_html = unsafe_output_stream.str();
93 } else { 96 } else {
94 title = l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE); 97 title = l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE);
95 unsafe_article_html = 98 unsafe_article_html =
96 l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT); 99 l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT);
97 } 100 }
98 std::string unsafe_page_html = 101 std::string unsafe_page_html =
99 ReplaceHtmlTemplateValues(title, unsafe_article_html); 102 ReplaceHtmlTemplateValues(title, unsafe_article_html);
100 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 103 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
101 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 104 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
102 } 105 }
103 106
104 void RequestViewerHandle::TakeViewerHandle( 107 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle(
105 scoped_ptr<ViewerHandle> viewer_handle) { 108 scoped_ptr<ViewerHandle> viewer_handle) {
106 viewer_handle_ = viewer_handle.Pass(); 109 viewer_handle_ = viewer_handle.Pass();
107 } 110 }
108 111
109 DomDistillerViewerSource::DomDistillerViewerSource( 112 DomDistillerViewerSource::DomDistillerViewerSource(
110 DomDistillerService* dom_distiller_service, 113 DomDistillerServiceInterface* dom_distiller_service,
111 const std::string& scheme) 114 const std::string& scheme)
112 : scheme_(scheme), dom_distiller_service_(dom_distiller_service) {} 115 : scheme_(scheme), dom_distiller_service_(dom_distiller_service) {}
113 116
114 DomDistillerViewerSource::~DomDistillerViewerSource() {} 117 DomDistillerViewerSource::~DomDistillerViewerSource() {}
115 118
116 std::string DomDistillerViewerSource::GetSource() const { 119 std::string DomDistillerViewerSource::GetSource() const {
117 return scheme_ + "://"; 120 return scheme_ + "://";
118 } 121 }
119 122
120 void DomDistillerViewerSource::StartDataRequest( 123 void DomDistillerViewerSource::StartDataRequest(
(...skipping 12 matching lines...) Expand all
133 if (kCssPath == path) { 136 if (kCssPath == path) {
134 std::string css = ResourceBundle::GetSharedInstance() 137 std::string css = ResourceBundle::GetSharedInstance()
135 .GetRawDataResource(IDR_DISTILLER_CSS) 138 .GetRawDataResource(IDR_DISTILLER_CSS)
136 .as_string(); 139 .as_string();
137 callback.Run(base::RefCountedString::TakeString(&css)); 140 callback.Run(base::RefCountedString::TakeString(&css));
138 return; 141 return;
139 } 142 }
140 143
141 RequestViewerHandle* request_viewer_handle = 144 RequestViewerHandle* request_viewer_handle =
142 new RequestViewerHandle(callback); 145 new RequestViewerHandle(callback);
143 std::string entry_id = StringToUpperASCII(path);
144 scoped_ptr<ViewerHandle> viewer_handle = 146 scoped_ptr<ViewerHandle> viewer_handle =
145 dom_distiller_service_->ViewEntry(request_viewer_handle, entry_id); 147 CreateViewRequest(path, request_viewer_handle);
148
146 if (viewer_handle) { 149 if (viewer_handle) {
147 // The service returned a |ViewerHandle| and guarantees it will call 150 // The service returned a |ViewerHandle| and guarantees it will call
148 // the |RequestViewerHandle|, so passing ownership to it, to ensure the 151 // the |RequestViewerHandle|, so passing ownership to it, to ensure the
149 // request is not cancelled. The |RequestViewerHandle| will delete itself 152 // request is not cancelled. The |RequestViewerHandle| will delete itself
150 // after receiving the callback. 153 // after receiving the callback.
151 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); 154 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
152 } else { 155 } else {
153 // The service did not return a |ViewerHandle|, which means the 156 // The service did not return a |ViewerHandle|, which means the
154 // |RequestViewerHandle| will never be called, so clean up now. 157 // |RequestViewerHandle| will never be called, so clean up now.
155 delete request_viewer_handle; 158 delete request_viewer_handle;
156 159
157 std::string title = l10n_util::GetStringUTF8( 160 std::string title = l10n_util::GetStringUTF8(
158 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE); 161 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE);
159 std::string content = l10n_util::GetStringUTF8( 162 std::string content = l10n_util::GetStringUTF8(
160 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT); 163 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT);
161 std::string html = ReplaceHtmlTemplateValues(title, content); 164 std::string html = ReplaceHtmlTemplateValues(title, content);
162 callback.Run(base::RefCountedString::TakeString(&html)); 165 callback.Run(base::RefCountedString::TakeString(&html));
163 } 166 }
164 }; 167 };
165 168
166 std::string DomDistillerViewerSource::GetMimeType(const std::string& path) 169 std::string DomDistillerViewerSource::GetMimeType(
167 const { 170 const std::string& path) const {
168 if (path == kCssPath) 171 if (path == kCssPath)
169 return "text/css"; 172 return "text/css";
170 return "text/html"; 173 return "text/html";
171 } 174 }
172 175
173 bool DomDistillerViewerSource::ShouldServiceRequest( 176 bool DomDistillerViewerSource::ShouldServiceRequest(
174 const net::URLRequest* request) const { 177 const net::URLRequest* request) const {
175 return request->url().SchemeIs(scheme_.c_str()); 178 return request->url().SchemeIs(scheme_.c_str());
176 } 179 }
177 180
181 // TODO(nyquist): Start tracking requests using this method.
178 void DomDistillerViewerSource::WillServiceRequest( 182 void DomDistillerViewerSource::WillServiceRequest(
179 const net::URLRequest* request, 183 const net::URLRequest* request,
180 std::string* path) const { 184 std::string* path) const {};
181 if (*path != kCssPath) {
182 // Since the full request is not available to StartDataRequest, replace the
183 // path to contain the data needed.
184 *path = request->url().host();
185 }
186 };
187 185
188 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 186 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
189 const { 187 const {
190 return "object-src 'none'; style-src 'self'"; 188 return "object-src 'none'; style-src 'self';";
189 }
190
191 scoped_ptr<ViewerHandle> DomDistillerViewerSource::CreateViewRequest(
192 const std::string& path,
193 ViewRequestDelegate* view_request_delegate) {
194 std::string entry_id = GetValueForKeyInURLPathQuery(path, kEntryIdKey);
195 bool has_entry_id = !entry_id.empty();
196 entry_id = StringToUpperASCII(entry_id);
197
198 std::string requested_url_str = GetValueForKeyInURLPathQuery(path, kUrlKey);
199 GURL requested_url(requested_url_str);
200 bool has_url = !requested_url_str.empty() && requested_url.is_valid();
shashi 2014/02/25 21:48:08 nit is requested_url.is_valid() sufficient here? h
nyquist 2014/02/27 00:07:37 Done.
201
202 if (has_entry_id && has_url) {
203 // It is invalid to specify a query param for both |kEntryIdKey| and
204 // |kUrlKey|.
205 return scoped_ptr<ViewerHandle>();
206 }
207
208 if (has_entry_id) {
209 return dom_distiller_service_->ViewEntry(view_request_delegate, entry_id)
210 .Pass();
211 } else if (has_url) {
212 return dom_distiller_service_->ViewUrl(view_request_delegate, requested_url)
213 .Pass();
214 }
215
216 // It is invalid to not specify a query param for |kEntryIdKey| or |kUrlKey|.
217 return scoped_ptr<ViewerHandle>();
218 }
219
220 std::string DomDistillerViewerSource::GetValueForKeyInURLPathQuery(
221 const std::string& path,
222 const std::string& key) {
223 GURL dummy_url(std::string(kInternalScheme) + "://dummy/" + path);
shashi 2014/02/25 21:48:08 It will be nice to have a comment here, that using
nyquist 2014/02/27 00:07:37 Done. Also moved more of this into the constant, w
224 std::string value;
225 net::GetValueForKeyInQuery(dummy_url, key, &value);
226 return value;
191 } 227 }
192 228
193 } // namespace dom_distiller 229 } // namespace dom_distiller
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698