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

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 all comments 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"
20 #include "components/dom_distiller/core/url_utils.h"
19 #include "content/public/browser/render_frame_host.h" 21 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/render_view_host.h" 22 #include "content/public/browser/render_view_host.h"
21 #include "grit/component_resources.h" 23 #include "grit/component_resources.h"
22 #include "grit/component_strings.h" 24 #include "grit/component_strings.h"
23 #include "net/base/escape.h" 25 #include "net/base/escape.h"
26 #include "net/base/url_util.h"
shashi 2014/02/27 04:29:08 nit: is this import needed?
nyquist 2014/02/27 19:50:19 Done.
24 #include "net/url_request/url_request.h" 27 #include "net/url_request/url_request.h"
25 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h" 29 #include "ui/base/resource/resource_bundle.h"
27 #include "url/gurl.h" 30 #include "url/gurl.h"
28 31
32 namespace dom_distiller {
33
29 namespace { 34 namespace {
30 35
31 const char kCssPath[] = "readability.css";
32
33 std::string ReplaceHtmlTemplateValues(std::string title, std::string content) { 36 std::string ReplaceHtmlTemplateValues(std::string title, std::string content) {
34 base::StringPiece html_template = 37 base::StringPiece html_template =
35 ResourceBundle::GetSharedInstance().GetRawDataResource( 38 ResourceBundle::GetSharedInstance().GetRawDataResource(
36 IDR_DOM_DISTILLER_VIEWER_HTML); 39 IDR_DOM_DISTILLER_VIEWER_HTML);
37 std::vector<std::string> substitutions; 40 std::vector<std::string> substitutions;
38 substitutions.push_back(title); // $1 41 substitutions.push_back(title); // $1
39 substitutions.push_back(kCssPath); // $2 42 substitutions.push_back(kCssPath); // $2
40 substitutions.push_back(title); // $3 43 substitutions.push_back(title); // $3
41 substitutions.push_back(content); // $4 44 substitutions.push_back(content); // $4
42 return ReplaceStringPlaceholders(html_template, substitutions, NULL); 45 return ReplaceStringPlaceholders(html_template, substitutions, NULL);
43 } 46 }
44 47
45 } // namespace 48 } // namespace
46 49
47 namespace dom_distiller {
48
49 // Handles receiving data asynchronously for a specific entry, and passing 50 // Handles receiving data asynchronously for a specific entry, and passing
50 // it along to the data callback for the data source. 51 // it along to the data callback for the data source.
51 class RequestViewerHandle : public ViewRequestDelegate { 52 class DomDistillerViewerSource::RequestViewerHandle
53 : public ViewRequestDelegate {
52 public: 54 public:
53 explicit RequestViewerHandle( 55 explicit RequestViewerHandle(
54 const content::URLDataSource::GotDataCallback& callback); 56 const content::URLDataSource::GotDataCallback& callback);
55 virtual ~RequestViewerHandle(); 57 virtual ~RequestViewerHandle();
56 58
57 // ViewRequestDelegate implementation. 59 // ViewRequestDelegate implementation.
58 virtual void OnArticleReady(const DistilledArticleProto* article_proto) 60 virtual void OnArticleReady(const DistilledArticleProto* article_proto)
59 OVERRIDE; 61 OVERRIDE;
60 62
61 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); 63 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle);
62 64
63 private: 65 private:
64 // The handle to the view request towards the DomDistillerService. It 66 // The handle to the view request towards the DomDistillerService. It
65 // needs to be kept around to ensure the distillation request finishes. 67 // needs to be kept around to ensure the distillation request finishes.
66 scoped_ptr<ViewerHandle> viewer_handle_; 68 scoped_ptr<ViewerHandle> viewer_handle_;
67 69
68 // This holds the callback to where the data retrieved is sent back. 70 // This holds the callback to where the data retrieved is sent back.
69 content::URLDataSource::GotDataCallback callback_; 71 content::URLDataSource::GotDataCallback callback_;
70 }; 72 };
71 73
72 RequestViewerHandle::RequestViewerHandle( 74 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
73 const content::URLDataSource::GotDataCallback& callback) 75 const content::URLDataSource::GotDataCallback& callback)
74 : callback_(callback) {} 76 : callback_(callback) {}
75 77
76 RequestViewerHandle::~RequestViewerHandle() {} 78 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {}
77 79
78 void RequestViewerHandle::OnArticleReady( 80 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady(
79 const DistilledArticleProto* article_proto) { 81 const DistilledArticleProto* article_proto) {
80 DCHECK(article_proto); 82 DCHECK(article_proto);
81 std::string title; 83 std::string title;
82 std::string unsafe_article_html; 84 std::string unsafe_article_html;
83 if (article_proto->has_title() && article_proto->pages_size() > 0 && 85 if (article_proto->has_title() && article_proto->pages_size() > 0 &&
84 article_proto->pages(0).has_html()) { 86 article_proto->pages(0).has_html()) {
85 title = net::EscapeForHTML(article_proto->title()); 87 title = net::EscapeForHTML(article_proto->title());
86 // TODO(shashishekhar): Add support for correcting displaying multiple pages 88 // TODO(shashishekhar): Add support for correcting displaying multiple pages
87 // after discussing the right way to display them. 89 // after discussing the right way to display them.
88 std::ostringstream unsafe_output_stream; 90 std::ostringstream unsafe_output_stream;
89 for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) { 91 for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) {
90 unsafe_output_stream << article_proto->pages(page_num).html(); 92 unsafe_output_stream << article_proto->pages(page_num).html();
91 } 93 }
92 unsafe_article_html = unsafe_output_stream.str(); 94 unsafe_article_html = unsafe_output_stream.str();
93 } else { 95 } else {
94 title = l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE); 96 title = l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE);
95 unsafe_article_html = 97 unsafe_article_html =
96 l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT); 98 l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT);
97 } 99 }
98 std::string unsafe_page_html = 100 std::string unsafe_page_html =
99 ReplaceHtmlTemplateValues(title, unsafe_article_html); 101 ReplaceHtmlTemplateValues(title, unsafe_article_html);
100 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 102 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
101 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 103 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
102 } 104 }
103 105
104 void RequestViewerHandle::TakeViewerHandle( 106 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle(
105 scoped_ptr<ViewerHandle> viewer_handle) { 107 scoped_ptr<ViewerHandle> viewer_handle) {
106 viewer_handle_ = viewer_handle.Pass(); 108 viewer_handle_ = viewer_handle.Pass();
107 } 109 }
108 110
109 DomDistillerViewerSource::DomDistillerViewerSource( 111 DomDistillerViewerSource::DomDistillerViewerSource(
110 DomDistillerService* dom_distiller_service, 112 DomDistillerServiceInterface* dom_distiller_service,
111 const std::string& scheme) 113 const std::string& scheme)
112 : scheme_(scheme), dom_distiller_service_(dom_distiller_service) {} 114 : scheme_(scheme), dom_distiller_service_(dom_distiller_service) {}
113 115
114 DomDistillerViewerSource::~DomDistillerViewerSource() {} 116 DomDistillerViewerSource::~DomDistillerViewerSource() {}
115 117
116 std::string DomDistillerViewerSource::GetSource() const { 118 std::string DomDistillerViewerSource::GetSource() const {
117 return scheme_ + "://"; 119 return scheme_ + "://";
118 } 120 }
119 121
120 void DomDistillerViewerSource::StartDataRequest( 122 void DomDistillerViewerSource::StartDataRequest(
(...skipping 12 matching lines...) Expand all
133 if (kCssPath == path) { 135 if (kCssPath == path) {
134 std::string css = ResourceBundle::GetSharedInstance() 136 std::string css = ResourceBundle::GetSharedInstance()
135 .GetRawDataResource(IDR_DISTILLER_CSS) 137 .GetRawDataResource(IDR_DISTILLER_CSS)
136 .as_string(); 138 .as_string();
137 callback.Run(base::RefCountedString::TakeString(&css)); 139 callback.Run(base::RefCountedString::TakeString(&css));
138 return; 140 return;
139 } 141 }
140 142
141 RequestViewerHandle* request_viewer_handle = 143 RequestViewerHandle* request_viewer_handle =
142 new RequestViewerHandle(callback); 144 new RequestViewerHandle(callback);
143 std::string entry_id = StringToUpperASCII(path);
144 scoped_ptr<ViewerHandle> viewer_handle = 145 scoped_ptr<ViewerHandle> viewer_handle =
145 dom_distiller_service_->ViewEntry(request_viewer_handle, entry_id); 146 CreateViewRequest(path, request_viewer_handle);
147
146 if (viewer_handle) { 148 if (viewer_handle) {
147 // The service returned a |ViewerHandle| and guarantees it will call 149 // The service returned a |ViewerHandle| and guarantees it will call
148 // the |RequestViewerHandle|, so passing ownership to it, to ensure the 150 // the |RequestViewerHandle|, so passing ownership to it, to ensure the
149 // request is not cancelled. The |RequestViewerHandle| will delete itself 151 // request is not cancelled. The |RequestViewerHandle| will delete itself
150 // after receiving the callback. 152 // after receiving the callback.
151 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); 153 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
152 } else { 154 } else {
153 // The service did not return a |ViewerHandle|, which means the 155 // The service did not return a |ViewerHandle|, which means the
154 // |RequestViewerHandle| will never be called, so clean up now. 156 // |RequestViewerHandle| will never be called, so clean up now.
155 delete request_viewer_handle; 157 delete request_viewer_handle;
156 158
157 std::string title = l10n_util::GetStringUTF8( 159 std::string title = l10n_util::GetStringUTF8(
158 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE); 160 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE);
159 std::string content = l10n_util::GetStringUTF8( 161 std::string content = l10n_util::GetStringUTF8(
160 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT); 162 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT);
161 std::string html = ReplaceHtmlTemplateValues(title, content); 163 std::string html = ReplaceHtmlTemplateValues(title, content);
162 callback.Run(base::RefCountedString::TakeString(&html)); 164 callback.Run(base::RefCountedString::TakeString(&html));
163 } 165 }
164 }; 166 };
165 167
166 std::string DomDistillerViewerSource::GetMimeType(const std::string& path) 168 std::string DomDistillerViewerSource::GetMimeType(
167 const { 169 const std::string& path) const {
168 if (path == kCssPath) 170 if (path == kCssPath)
169 return "text/css"; 171 return "text/css";
170 return "text/html"; 172 return "text/html";
171 } 173 }
172 174
173 bool DomDistillerViewerSource::ShouldServiceRequest( 175 bool DomDistillerViewerSource::ShouldServiceRequest(
174 const net::URLRequest* request) const { 176 const net::URLRequest* request) const {
175 return request->url().SchemeIs(scheme_.c_str()); 177 return request->url().SchemeIs(scheme_.c_str());
176 } 178 }
177 179
180 // TODO(nyquist): Start tracking requests using this method.
178 void DomDistillerViewerSource::WillServiceRequest( 181 void DomDistillerViewerSource::WillServiceRequest(
179 const net::URLRequest* request, 182 const net::URLRequest* request,
180 std::string* path) const { 183 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 184
188 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 185 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
189 const { 186 const {
190 return "object-src 'none'; style-src 'self'"; 187 return "object-src 'none'; style-src 'self';";
188 }
189
190 scoped_ptr<ViewerHandle> DomDistillerViewerSource::CreateViewRequest(
191 const std::string& path,
192 ViewRequestDelegate* view_request_delegate) {
193 std::string entry_id =
194 url_utils::GetValueForKeyInURLPathQuery(path, kEntryIdKey);
195 bool has_valid_entry_id = !entry_id.empty();
196 entry_id = StringToUpperASCII(entry_id);
197
198 std::string requested_url_str =
199 url_utils::GetValueForKeyInURLPathQuery(path, kUrlKey);
200 GURL requested_url(requested_url_str);
201 bool has_valid_url = url_utils::IsDistillableUrl(requested_url);
202
203 if (has_valid_entry_id && has_valid_url) {
204 // It is invalid to specify a query param for both |kEntryIdKey| and
205 // |kUrlKey|.
206 return scoped_ptr<ViewerHandle>();
207 }
208
209 if (has_valid_entry_id) {
210 return dom_distiller_service_->ViewEntry(view_request_delegate, entry_id)
211 .Pass();
212 } else if (has_valid_url) {
213 return dom_distiller_service_->ViewUrl(view_request_delegate, requested_url)
214 .Pass();
215 }
216
217 // It is invalid to not specify a query param for |kEntryIdKey| or |kUrlKey|.
218 return scoped_ptr<ViewerHandle>();
191 } 219 }
192 220
193 } // namespace dom_distiller 221 } // namespace dom_distiller
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698