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