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/browser/manifest/manifest_manager_host.h"
7 #include "base/stl_util.h"
8 #include "content/common/manifest_manager_messages.h"
9 #include "content/public/browser/render_frame_host.h"
10 #include "content/public/browser/render_process_host.h"
11 #include "content/public/common/manifest.h"
12 #include "content/public/common/result_codes.h"
18 void KillRenderer(RenderFrameHost
* render_frame_host
) {
19 base::ProcessHandle process_handle
=
20 render_frame_host
->GetProcess()->GetHandle();
21 if (process_handle
== base::kNullProcessHandle
)
23 render_frame_host
->GetProcess()->Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE
,
27 } // anonymous namespace
29 ManifestManagerHost::ManifestManagerHost(WebContents
* web_contents
)
30 : WebContentsObserver(web_contents
) {
33 ManifestManagerHost::~ManifestManagerHost() {
34 STLDeleteValues(&pending_callbacks_
);
37 ManifestManagerHost::CallbackMap
* ManifestManagerHost::GetCallbackMapForFrame(
38 RenderFrameHost
* render_frame_host
) {
39 FrameCallbackMap::iterator it
= pending_callbacks_
.find(render_frame_host
);
40 return it
!= pending_callbacks_
.end() ? it
->second
: 0;
43 void ManifestManagerHost::RenderFrameDeleted(
44 RenderFrameHost
* render_frame_host
) {
45 CallbackMap
* callbacks
= GetCallbackMapForFrame(render_frame_host
);
49 // Before deleting the callbacks, make sure they are called with a failure
50 // state. Do this in a block so the iterator is destroyed before |callbacks|.
52 CallbackMap::const_iterator
it(callbacks
);
53 for (; !it
.IsAtEnd(); it
.Advance())
54 it
.GetCurrentValue()->Run(Manifest());
58 pending_callbacks_
.erase(render_frame_host
);
61 void ManifestManagerHost::GetManifest(RenderFrameHost
* render_frame_host
,
62 const GetManifestCallback
& callback
) {
63 CallbackMap
* callbacks
= GetCallbackMapForFrame(render_frame_host
);
65 callbacks
= new CallbackMap();
66 pending_callbacks_
[render_frame_host
] = callbacks
;
69 int request_id
= callbacks
->Add(new GetManifestCallback(callback
));
71 render_frame_host
->Send(new ManifestManagerMsg_RequestManifest(
72 render_frame_host
->GetRoutingID(), request_id
));
75 bool ManifestManagerHost::OnMessageReceived(
76 const IPC::Message
& message
, RenderFrameHost
* render_frame_host
) {
79 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ManifestManagerHost
, message
,
81 IPC_MESSAGE_HANDLER(ManifestManagerHostMsg_RequestManifestResponse
,
82 OnRequestManifestResponse
)
83 IPC_MESSAGE_UNHANDLED(handled
= false)
89 void ManifestManagerHost::OnRequestManifestResponse(
90 RenderFrameHost
* render_frame_host
,
92 const Manifest
& insecure_manifest
) {
93 CallbackMap
* callbacks
= GetCallbackMapForFrame(render_frame_host
);
95 DVLOG(1) << "Unexpected RequestManifestResponse to from renderer. "
97 KillRenderer(render_frame_host
);
101 GetManifestCallback
* callback
= callbacks
->Lookup(request_id
);
103 DVLOG(1) << "Received a request_id (" << request_id
<< ") from renderer "
104 "with no associated callback. Killing renderer.";
105 KillRenderer(render_frame_host
);
109 // When receiving a Manifest, the browser process can't trust that it is
110 // coming from a known and secure source. It must be processed accordingly.
111 Manifest manifest
= insecure_manifest
;
112 manifest
.name
= base::NullableString16(
113 manifest
.name
.string().substr(0, Manifest::kMaxIPCStringLength
),
114 manifest
.name
.is_null());
115 manifest
.short_name
= base::NullableString16(
116 manifest
.short_name
.string().substr(0, Manifest::kMaxIPCStringLength
),
117 manifest
.short_name
.is_null());
118 if (!manifest
.start_url
.is_valid())
119 manifest
.start_url
= GURL();
120 for (auto& icon
: manifest
.icons
) {
121 if (!icon
.src
.is_valid())
123 icon
.type
= base::NullableString16(
124 icon
.type
.string().substr(0, Manifest::kMaxIPCStringLength
),
125 icon
.type
.is_null());
127 manifest
.gcm_sender_id
= base::NullableString16(
128 manifest
.gcm_sender_id
.string().substr(
129 0, Manifest::kMaxIPCStringLength
),
130 manifest
.gcm_sender_id
.is_null());
131 for (auto& related_application
: manifest
.related_applications
) {
132 if (!related_application
.url
.is_valid())
133 related_application
.url
= GURL();
134 related_application
.id
=
135 base::NullableString16(related_application
.id
.string().substr(
136 0, Manifest::kMaxIPCStringLength
),
137 related_application
.id
.is_null());
139 // theme_color is a 32 bit unsigned integer with a 64 bit integer simply
140 // being used to encode an error occuring. Therefore, any value outside the
141 // range of an unsigned 32 bit integer is invalid.
142 if (manifest
.theme_color
< 0 || manifest
.theme_color
> 0xFFFFFFFF)
143 manifest
.theme_color
= Manifest::kInvalidOrMissingThemeColor
;
145 callback
->Run(manifest
);
146 callbacks
->Remove(request_id
);
147 if (callbacks
->IsEmpty()) {
149 pending_callbacks_
.erase(render_frame_host
);
153 } // namespace content