Add ICU message format support
[chromium-blink-merge.git] / content / renderer / manifest / manifest_manager.cc
bloba14aa70d84fe76ca5ba73b203cde1dbb4b10cfca
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.
5 #include "content/renderer/manifest/manifest_manager.h"
7 #include "base/bind.h"
8 #include "base/strings/nullable_string16.h"
9 #include "content/common/manifest_manager_messages.h"
10 #include "content/public/renderer/render_frame.h"
11 #include "content/renderer/fetchers/manifest_fetcher.h"
12 #include "content/renderer/manifest/manifest_parser.h"
13 #include "content/renderer/manifest/manifest_uma_util.h"
14 #include "third_party/WebKit/public/platform/WebURLResponse.h"
15 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
16 #include "third_party/WebKit/public/web/WebDocument.h"
17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
19 namespace content {
21 ManifestManager::ManifestManager(RenderFrame* render_frame)
22 : RenderFrameObserver(render_frame),
23 may_have_manifest_(false),
24 manifest_dirty_(true) {
27 ManifestManager::~ManifestManager() {
28 if (fetcher_)
29 fetcher_->Cancel();
31 // Consumers in the browser process will not receive this message but they
32 // will be aware of the RenderFrame dying and should act on that. Consumers
33 // in the renderer process should be correctly notified.
34 ResolveCallbacks(ResolveStateFailure);
37 bool ManifestManager::OnMessageReceived(const IPC::Message& message) {
38 bool handled = true;
40 IPC_BEGIN_MESSAGE_MAP(ManifestManager, message)
41 IPC_MESSAGE_HANDLER(ManifestManagerMsg_RequestManifest, OnRequestManifest)
42 IPC_MESSAGE_UNHANDLED(handled = false)
43 IPC_END_MESSAGE_MAP()
45 return handled;
48 void ManifestManager::OnRequestManifest(int request_id) {
49 GetManifest(base::Bind(&ManifestManager::OnRequestManifestComplete,
50 base::Unretained(this), request_id));
53 void ManifestManager::OnRequestManifestComplete(
54 int request_id, const Manifest& manifest) {
55 // When sent via IPC, the Manifest must follow certain security rules.
56 Manifest ipc_manifest = manifest;
57 ipc_manifest.name = base::NullableString16(
58 ipc_manifest.name.string().substr(0, Manifest::kMaxIPCStringLength),
59 ipc_manifest.name.is_null());
60 ipc_manifest.short_name = base::NullableString16(
61 ipc_manifest.short_name.string().substr(0,
62 Manifest::kMaxIPCStringLength),
63 ipc_manifest.short_name.is_null());
64 for (auto& icon : ipc_manifest.icons) {
65 icon.type = base::NullableString16(
66 icon.type.string().substr(0, Manifest::kMaxIPCStringLength),
67 icon.type.is_null());
69 ipc_manifest.gcm_sender_id = base::NullableString16(
70 ipc_manifest.gcm_sender_id.string().substr(
71 0, Manifest::kMaxIPCStringLength),
72 ipc_manifest.gcm_sender_id.is_null());
73 for (auto& related_application : ipc_manifest.related_applications) {
74 related_application.id =
75 base::NullableString16(related_application.id.string().substr(
76 0, Manifest::kMaxIPCStringLength),
77 related_application.id.is_null());
80 Send(new ManifestManagerHostMsg_RequestManifestResponse(
81 routing_id(), request_id, ipc_manifest));
84 void ManifestManager::GetManifest(const GetManifestCallback& callback) {
85 if (!may_have_manifest_) {
86 callback.Run(Manifest());
87 return;
90 if (!manifest_dirty_) {
91 callback.Run(manifest_);
92 return;
95 pending_callbacks_.push_back(callback);
97 // Just wait for the running call to be done if there are other callbacks.
98 if (pending_callbacks_.size() > 1)
99 return;
101 FetchManifest();
104 void ManifestManager::DidChangeManifest() {
105 may_have_manifest_ = true;
106 manifest_dirty_ = true;
109 void ManifestManager::DidCommitProvisionalLoad(
110 bool is_new_navigation,
111 bool is_same_page_navigation) {
112 if (is_same_page_navigation)
113 return;
115 may_have_manifest_ = false;
116 manifest_dirty_ = true;
119 void ManifestManager::FetchManifest() {
120 GURL url(render_frame()->GetWebFrame()->document().manifestURL());
122 if (url.is_empty()) {
123 ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_EMPTY_URL);
124 ResolveCallbacks(ResolveStateFailure);
125 return;
128 fetcher_.reset(new ManifestFetcher(url));
129 fetcher_->Start(
130 render_frame()->GetWebFrame(),
131 render_frame()->GetWebFrame()->document().manifestUseCredentials(),
132 base::Bind(&ManifestManager::OnManifestFetchComplete,
133 base::Unretained(this),
134 render_frame()->GetWebFrame()->document().url()));
137 void ManifestManager::OnManifestFetchComplete(
138 const GURL& document_url,
139 const blink::WebURLResponse& response,
140 const std::string& data) {
141 if (response.isNull() && data.empty()) {
142 ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_UNSPECIFIED_REASON);
143 ResolveCallbacks(ResolveStateFailure);
144 return;
147 ManifestUmaUtil::FetchSucceeded();
149 ManifestParser parser(data, response.url(), document_url);
150 parser.Parse();
152 fetcher_.reset();
154 for (const std::string& msg : parser.errors()) {
155 blink::WebConsoleMessage message;
156 message.level = blink::WebConsoleMessage::LevelError;
157 message.text = blink::WebString::fromUTF8(msg);
158 render_frame()->GetWebFrame()->addMessageToConsole(message);
161 // Having errors while parsing the manifest doesn't mean the manifest parsing
162 // failed. Some properties might have been ignored but some others kept.
163 if (parser.failed()) {
164 ResolveCallbacks(ResolveStateFailure);
165 return;
168 manifest_ = parser.manifest();
169 ResolveCallbacks(ResolveStateSuccess);
172 void ManifestManager::ResolveCallbacks(ResolveState state) {
173 if (state == ResolveStateFailure)
174 manifest_ = Manifest();
176 manifest_dirty_ = state != ResolveStateSuccess;
178 Manifest manifest = manifest_;
179 std::list<GetManifestCallback> callbacks = pending_callbacks_;
181 pending_callbacks_.clear();
183 for (std::list<GetManifestCallback>::const_iterator it = callbacks.begin();
184 it != callbacks.end(); ++it) {
185 it->Run(manifest);
189 } // namespace content