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 "content/browser/manifest/manifest_manager_host.h" 6 7#include "content/common/manifest_manager_messages.h" 8#include "content/public/browser/render_frame_host.h" 9#include "content/public/browser/render_process_host.h" 10#include "content/public/common/manifest.h" 11#include "content/public/common/result_codes.h" 12 13namespace content { 14 15namespace { 16 17void KillRenderer(RenderFrameHost* render_frame_host) { 18 base::ProcessHandle process_handle = 19 render_frame_host->GetProcess()->GetHandle(); 20 if (process_handle == base::kNullProcessHandle) 21 return; 22 base::KillProcess(process_handle, RESULT_CODE_KILLED_BAD_MESSAGE, false); 23} 24 25} // anonymous namespace 26 27ManifestManagerHost::ManifestManagerHost(WebContents* web_contents) 28 : WebContentsObserver(web_contents) { 29} 30 31ManifestManagerHost::~ManifestManagerHost() { 32} 33 34ManifestManagerHost::CallbackMap* ManifestManagerHost::GetCallbackMapForFrame( 35 RenderFrameHost* render_frame_host) { 36 FrameCallbackMap::iterator it = pending_callbacks_.find(render_frame_host); 37 return it != pending_callbacks_.end() ? it->second : 0; 38} 39 40void ManifestManagerHost::RenderFrameDeleted( 41 RenderFrameHost* render_frame_host) { 42 CallbackMap* callbacks = GetCallbackMapForFrame(render_frame_host); 43 if (!callbacks) 44 return; 45 46 // Before deleting the callbacks, make sure they are called with a failure 47 // state. 48 CallbackMap::const_iterator it(callbacks); 49 for (; !it.IsAtEnd(); it.Advance()) 50 it.GetCurrentValue()->Run(Manifest()); 51 52 pending_callbacks_.erase(render_frame_host); 53} 54 55void ManifestManagerHost::GetManifest(RenderFrameHost* render_frame_host, 56 const GetManifestCallback& callback) { 57 CallbackMap* callbacks = GetCallbackMapForFrame(render_frame_host); 58 if (!callbacks) { 59 callbacks = new CallbackMap(); 60 pending_callbacks_[render_frame_host] = callbacks; 61 } 62 63 int request_id = callbacks->Add(new GetManifestCallback(callback)); 64 65 render_frame_host->Send(new ManifestManagerMsg_RequestManifest( 66 render_frame_host->GetRoutingID(), request_id)); 67} 68 69bool ManifestManagerHost::OnMessageReceived( 70 const IPC::Message& message, RenderFrameHost* render_frame_host) { 71 bool handled = true; 72 73 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ManifestManagerHost, message, 74 render_frame_host) 75 IPC_MESSAGE_HANDLER(ManifestManagerHostMsg_RequestManifestResponse, 76 OnRequestManifestResponse) 77 IPC_MESSAGE_UNHANDLED(handled = false) 78 IPC_END_MESSAGE_MAP() 79 80 return handled; 81} 82 83void ManifestManagerHost::OnRequestManifestResponse( 84 RenderFrameHost* render_frame_host, 85 int request_id, 86 const Manifest& insecure_manifest) { 87 CallbackMap* callbacks = GetCallbackMapForFrame(render_frame_host); 88 if (!callbacks) { 89 DVLOG(1) << "Unexpected RequestManifestResponse to from renderer. " 90 "Killing renderer."; 91 KillRenderer(render_frame_host); 92 return; 93 } 94 95 GetManifestCallback* callback = callbacks->Lookup(request_id); 96 if (!callback) { 97 DVLOG(1) << "Received a request_id (" << request_id << ") from renderer " 98 "with no associated callback. Killing renderer."; 99 KillRenderer(render_frame_host); 100 return; 101 } 102 103 // When receiving a Manifest, the browser process can't trust that it is 104 // coming from a known and secure source. It must be processed accordingly. 105 Manifest manifest = insecure_manifest; 106 manifest.name = base::NullableString16( 107 manifest.name.string().substr(0, Manifest::kMaxIPCStringLength), 108 manifest.name.is_null()); 109 manifest.short_name = base::NullableString16( 110 manifest.short_name.string().substr(0, Manifest::kMaxIPCStringLength), 111 manifest.short_name.is_null()); 112 if (!manifest.start_url.is_valid()) 113 manifest.start_url = GURL(); 114 for (size_t i = 0; i < manifest.icons.size(); ++i) { 115 if (!manifest.icons[i].src.is_valid()) 116 manifest.icons[i].src = GURL(); 117 manifest.icons[i].type = base::NullableString16( 118 manifest.icons[i].type.string().substr(0, 119 Manifest::kMaxIPCStringLength), 120 manifest.icons[i].type.is_null()); 121 } 122 123 callback->Run(manifest); 124 callbacks->Remove(request_id); 125 if (callbacks->IsEmpty()) { 126 delete callbacks; 127 pending_callbacks_.erase(render_frame_host); 128 } 129} 130 131} // namespace content 132