Chromium Code Reviews| 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" | |
| 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 Loading... | |
| 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 |
| OLD | NEW |