third_party/re2: Remove remove-static-initializers.patch.
[chromium-blink-merge.git] / content / renderer / manifest / manifest_manager.cc
blob52667ba373b8492d7885fe8f1cfc1716ec499f81
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(render_frame()->GetWebFrame(),
130 base::Bind(&ManifestManager::OnManifestFetchComplete,
131 base::Unretained(this),
132 render_frame()->GetWebFrame()->document().url()));
135 void ManifestManager::OnManifestFetchComplete(
136 const GURL& document_url,
137 const blink::WebURLResponse& response,
138 const std::string& data) {
139 if (response.isNull() && data.empty()) {
140 ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_UNSPECIFIED_REASON);
141 ResolveCallbacks(ResolveStateFailure);
142 return;
145 ManifestUmaUtil::FetchSucceeded();
147 ManifestParser parser(data, response.url(), document_url);
148 parser.Parse();
150 fetcher_.reset();
152 for (const std::string& msg : parser.errors()) {
153 blink::WebConsoleMessage message;
154 message.level = blink::WebConsoleMessage::LevelError;
155 message.text = blink::WebString::fromUTF8(msg);
156 render_frame()->GetWebFrame()->addMessageToConsole(message);
159 // Having errors while parsing the manifest doesn't mean the manifest parsing
160 // failed. Some properties might have been ignored but some others kept.
161 if (parser.failed()) {
162 ResolveCallbacks(ResolveStateFailure);
163 return;
166 manifest_ = parser.manifest();
167 ResolveCallbacks(ResolveStateSuccess);
170 void ManifestManager::ResolveCallbacks(ResolveState state) {
171 if (state == ResolveStateFailure)
172 manifest_ = Manifest();
174 manifest_dirty_ = state != ResolveStateSuccess;
176 Manifest manifest = manifest_;
177 std::list<GetManifestCallback> callbacks = pending_callbacks_;
179 pending_callbacks_.clear();
181 for (std::list<GetManifestCallback>::const_iterator it = callbacks.begin();
182 it != callbacks.end(); ++it) {
183 it->Run(manifest);
187 } // namespace content