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"
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/WebDocument.h"
16 #include "third_party/WebKit/public/web/WebLocalFrame.h"
20 ManifestManager::ManifestManager(RenderFrame
* render_frame
)
21 : RenderFrameObserver(render_frame
),
22 may_have_manifest_(false),
23 manifest_dirty_(true) {
26 ManifestManager::~ManifestManager() {
30 // Consumers in the browser process will not receive this message but they
31 // will be aware of the RenderFrame dying and should act on that. Consumers
32 // in the renderer process should be correctly notified.
33 ResolveCallbacks(ResolveStateFailure
);
36 bool ManifestManager::OnMessageReceived(const IPC::Message
& message
) {
39 IPC_BEGIN_MESSAGE_MAP(ManifestManager
, message
)
40 IPC_MESSAGE_HANDLER(ManifestManagerMsg_RequestManifest
, OnRequestManifest
)
41 IPC_MESSAGE_UNHANDLED(handled
= false)
47 void ManifestManager::OnRequestManifest(int request_id
) {
48 GetManifest(base::Bind(&ManifestManager::OnRequestManifestComplete
,
49 base::Unretained(this), request_id
));
52 void ManifestManager::OnRequestManifestComplete(
53 int request_id
, const Manifest
& manifest
) {
54 // When sent via IPC, the Manifest must follow certain security rules.
55 Manifest ipc_manifest
= manifest
;
56 ipc_manifest
.name
= base::NullableString16(
57 ipc_manifest
.name
.string().substr(0, Manifest::kMaxIPCStringLength
),
58 ipc_manifest
.name
.is_null());
59 ipc_manifest
.short_name
= base::NullableString16(
60 ipc_manifest
.short_name
.string().substr(0,
61 Manifest::kMaxIPCStringLength
),
62 ipc_manifest
.short_name
.is_null());
63 for (size_t i
= 0; i
< ipc_manifest
.icons
.size(); ++i
) {
64 ipc_manifest
.icons
[i
].type
= base::NullableString16(
65 ipc_manifest
.icons
[i
].type
.string().substr(
66 0, Manifest::kMaxIPCStringLength
),
67 ipc_manifest
.icons
[i
].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());
74 Send(new ManifestManagerHostMsg_RequestManifestResponse(
75 routing_id(), request_id
, ipc_manifest
));
78 void ManifestManager::GetManifest(const GetManifestCallback
& callback
) {
79 if (!may_have_manifest_
) {
80 callback
.Run(Manifest());
84 if (!manifest_dirty_
) {
85 callback
.Run(manifest_
);
89 pending_callbacks_
.push_back(callback
);
91 // Just wait for the running call to be done if there are other callbacks.
92 if (pending_callbacks_
.size() > 1)
98 void ManifestManager::DidChangeManifest() {
99 may_have_manifest_
= true;
100 manifest_dirty_
= true;
103 void ManifestManager::FetchManifest() {
104 GURL
url(render_frame()->GetWebFrame()->document().manifestURL());
106 if (url
.is_empty()) {
107 ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_EMPTY_URL
);
108 ResolveCallbacks(ResolveStateFailure
);
112 fetcher_
.reset(new ManifestFetcher(url
));
114 // TODO(mlamouri,kenneth): this is not yet taking into account manifest-src
115 // CSP rule, see http://crbug.com/409996.
116 fetcher_
->Start(render_frame()->GetWebFrame(),
117 base::Bind(&ManifestManager::OnManifestFetchComplete
,
118 base::Unretained(this),
119 render_frame()->GetWebFrame()->document().url()));
122 void ManifestManager::OnManifestFetchComplete(
123 const GURL
& document_url
,
124 const blink::WebURLResponse
& response
,
125 const std::string
& data
) {
126 if (response
.isNull() && data
.empty()) {
127 ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_UNSPECIFIED_REASON
);
128 ResolveCallbacks(ResolveStateFailure
);
132 ManifestUmaUtil::FetchSucceeded();
133 manifest_
= ManifestParser::Parse(data
, response
.url(), document_url
);
136 ResolveCallbacks(ResolveStateSuccess
);
139 void ManifestManager::ResolveCallbacks(ResolveState state
) {
140 if (state
== ResolveStateFailure
)
141 manifest_
= Manifest();
143 manifest_dirty_
= state
!= ResolveStateSuccess
;
145 Manifest manifest
= manifest_
;
146 std::list
<GetManifestCallback
> callbacks
= pending_callbacks_
;
148 pending_callbacks_
.clear();
150 for (std::list
<GetManifestCallback
>::const_iterator it
= callbacks
.begin();
151 it
!= callbacks
.end(); ++it
) {
156 } // namespace content