Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / components / dom_distiller / content / dom_distiller_viewer_source.cc
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
3 // found in the LICENSE file.
4
5 #include "components/dom_distiller/content/dom_distiller_viewer_source.h"
6
7 #include <sstream>
8 #include <string>
9 #include <vector>
10
11 #include "base/memory/ref_counted_memory.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_util.h"
15 #include "components/dom_distiller/core/dom_distiller_service.h"
16 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
17 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
18 #include "components/dom_distiller/core/task_tracker.h"
19 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "grit/component_resources.h"
22 #include "grit/component_strings.h"
23 #include "net/base/escape.h"
24 #include "net/url_request/url_request.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "url/gurl.h"
28
29 namespace {
30
31 const char kCssPath[] = "readability.css";
32
33 std::string ReplaceHtmlTemplateValues(std::string title, std::string content) {
34   base::StringPiece html_template =
35       ResourceBundle::GetSharedInstance().GetRawDataResource(
36           IDR_DOM_DISTILLER_VIEWER_HTML);
37   std::vector<std::string> substitutions;
38   substitutions.push_back(title);     // $1
39   substitutions.push_back(kCssPath);  // $2
40   substitutions.push_back(title);     // $3
41   substitutions.push_back(content);   // $4
42   return ReplaceStringPlaceholders(html_template, substitutions, NULL);
43 }
44
45 }  // namespace
46
47 namespace dom_distiller {
48
49 // Handles receiving data asynchronously for a specific entry, and passing
50 // it along to the data callback for the data source.
51 class RequestViewerHandle : public ViewRequestDelegate {
52  public:
53   explicit RequestViewerHandle(
54       const content::URLDataSource::GotDataCallback& callback);
55   virtual ~RequestViewerHandle();
56
57   // ViewRequestDelegate implementation.
58   virtual void OnArticleReady(const DistilledArticleProto* article_proto)
59       OVERRIDE;
60
61   void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle);
62
63  private:
64   // The handle to the view request towards the DomDistillerService. It
65   // needs to be kept around to ensure the distillation request finishes.
66   scoped_ptr<ViewerHandle> viewer_handle_;
67
68   // This holds the callback to where the data retrieved is sent back.
69   content::URLDataSource::GotDataCallback callback_;
70 };
71
72 RequestViewerHandle::RequestViewerHandle(
73     const content::URLDataSource::GotDataCallback& callback)
74     : callback_(callback) {}
75
76 RequestViewerHandle::~RequestViewerHandle() {}
77
78 void RequestViewerHandle::OnArticleReady(
79     const DistilledArticleProto* article_proto) {
80   DCHECK(article_proto);
81   std::string title;
82   std::string unsafe_article_html;
83   if (article_proto->has_title() && article_proto->pages_size() > 0 &&
84       article_proto->pages(0).has_html()) {
85     title = net::EscapeForHTML(article_proto->title());
86     // TODO(shashishekhar): Add support for correcting displaying multiple pages
87     // after discussing the right way to display them.
88     std::ostringstream unsafe_output_stream;
89     for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) {
90       unsafe_output_stream << article_proto->pages(page_num).html();
91     }
92     unsafe_article_html = unsafe_output_stream.str();
93   } else {
94     title = l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE);
95     unsafe_article_html =
96         l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT);
97   }
98   std::string unsafe_page_html =
99       ReplaceHtmlTemplateValues(title, unsafe_article_html);
100   callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
101   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
102 }
103
104 void RequestViewerHandle::TakeViewerHandle(
105     scoped_ptr<ViewerHandle> viewer_handle) {
106   viewer_handle_ = viewer_handle.Pass();
107 }
108
109 DomDistillerViewerSource::DomDistillerViewerSource(
110     DomDistillerService* dom_distiller_service,
111     const std::string& scheme)
112     : scheme_(scheme), dom_distiller_service_(dom_distiller_service) {}
113
114 DomDistillerViewerSource::~DomDistillerViewerSource() {}
115
116 std::string DomDistillerViewerSource::GetSource() const {
117   return scheme_ + "://";
118 }
119
120 void DomDistillerViewerSource::StartDataRequest(
121     const std::string& path,
122     int render_process_id,
123     int render_frame_id,
124     const content::URLDataSource::GotDataCallback& callback) {
125   content::RenderFrameHost* render_frame_host =
126       content::RenderFrameHost::FromID(render_process_id, render_frame_id);
127   DCHECK(render_frame_host);
128   content::RenderViewHost* render_view_host =
129       render_frame_host->GetRenderViewHost();
130   DCHECK(render_view_host);
131   CHECK_EQ(0, render_view_host->GetEnabledBindings());
132
133   if (kCssPath == path) {
134     std::string css = ResourceBundle::GetSharedInstance()
135                           .GetRawDataResource(IDR_DISTILLER_CSS)
136                           .as_string();
137     callback.Run(base::RefCountedString::TakeString(&css));
138     return;
139   }
140
141   RequestViewerHandle* request_viewer_handle =
142       new RequestViewerHandle(callback);
143   std::string entry_id = StringToUpperASCII(path);
144   scoped_ptr<ViewerHandle> viewer_handle =
145       dom_distiller_service_->ViewEntry(request_viewer_handle, entry_id);
146   if (viewer_handle) {
147     // The service returned a |ViewerHandle| and guarantees it will call
148     // the |RequestViewerHandle|, so passing ownership to it, to ensure the
149     // request is not cancelled. The |RequestViewerHandle| will delete itself
150     // after receiving the callback.
151     request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
152   } else {
153     // The service did not return a |ViewerHandle|, which means the
154     // |RequestViewerHandle| will never be called, so clean up now.
155     delete request_viewer_handle;
156
157     std::string title = l10n_util::GetStringUTF8(
158         IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE);
159     std::string content = l10n_util::GetStringUTF8(
160         IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT);
161     std::string html = ReplaceHtmlTemplateValues(title, content);
162     callback.Run(base::RefCountedString::TakeString(&html));
163   }
164 };
165
166 std::string DomDistillerViewerSource::GetMimeType(const std::string& path)
167     const {
168   if (path == kCssPath)
169     return "text/css";
170   return "text/html";
171 }
172
173 bool DomDistillerViewerSource::ShouldServiceRequest(
174     const net::URLRequest* request) const {
175   return request->url().SchemeIs(scheme_.c_str());
176 }
177
178 void DomDistillerViewerSource::WillServiceRequest(
179     const net::URLRequest* request,
180     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
188 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
189     const {
190   return "object-src 'none'; style-src 'self'";
191 }
192
193 }  // namespace dom_distiller