18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Copyright 2014 The Chromium Authors. All rights reserved. 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Use of this source code is governed by a BSD-style license that can be 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// found in the LICENSE file. 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#include "content/renderer/manifest/manifest_manager.h" 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/bind.h" 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/strings/nullable_string16.h" 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "content/common/manifest_manager_messages.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "content/public/renderer/render_frame.h" 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "content/renderer/fetchers/manifest_fetcher.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "content/renderer/manifest/manifest_parser.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "third_party/WebKit/public/platform/WebURLResponse.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "third_party/WebKit/public/web/WebDocument.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "third_party/WebKit/public/web/WebLocalFrame.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnamespace content { 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtManifestManager::ManifestManager(RenderFrame* render_frame) 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt : RenderFrameObserver(render_frame), 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt may_have_manifest_(false), 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt manifest_dirty_(true) { 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtManifestManager::~ManifestManager() { 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (fetcher_) 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fetcher_->Cancel(); 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Consumers in the browser process will not receive this message but they 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // will be aware of the RenderFrame dying and should act on that. Consumers 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // in the renderer process should be correctly notified. 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ResolveCallbacks(ResolveStateFailure); 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbool ManifestManager::OnMessageReceived(const IPC::Message& message) { 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bool handled = true; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IPC_BEGIN_MESSAGE_MAP(ManifestManager, message) 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IPC_MESSAGE_HANDLER(ManifestManagerMsg_RequestManifest, OnRequestManifest) 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IPC_MESSAGE_UNHANDLED(handled = false) 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IPC_END_MESSAGE_MAP() 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return handled; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ManifestManager::OnRequestManifest(int request_id) { 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt GetManifest(base::Bind(&ManifestManager::OnRequestManifestComplete, 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::Unretained(this), request_id)); 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ManifestManager::OnRequestManifestComplete( 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int request_id, const Manifest& manifest) { 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // When sent via IPC, the Manifest must follow certain security rules. 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Manifest ipc_manifest = manifest; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.name = base::NullableString16( 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.name.string().substr(0, Manifest::kMaxIPCStringLength), 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.name.is_null()); 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.short_name = base::NullableString16( 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.short_name.string().substr(0, 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Manifest::kMaxIPCStringLength), 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.short_name.is_null()); 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (size_t i = 0; i < ipc_manifest.icons.size(); ++i) { 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.icons[i].type = base::NullableString16( 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.icons[i].type.string().substr( 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 0, Manifest::kMaxIPCStringLength), 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipc_manifest.icons[i].type.is_null()); 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Send(new ManifestManagerHostMsg_RequestManifestResponse( 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt routing_id(), request_id, ipc_manifest)); 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ManifestManager::GetManifest(const GetManifestCallback& callback) { 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!may_have_manifest_) { 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt callback.Run(Manifest()); 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!manifest_dirty_) { 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt callback.Run(manifest_); 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pending_callbacks_.push_back(callback); 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Just wait for the running call to be done if there are other callbacks. 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pending_callbacks_.size() > 1) 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt FetchManifest(); 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ManifestManager::DidChangeManifest() { 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt may_have_manifest_ = true; 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt manifest_dirty_ = true; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ManifestManager::FetchManifest() { 99a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt GURL url(render_frame()->GetWebFrame()->document().manifestURL()); 100a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (url.is_empty()) { 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ResolveCallbacks(ResolveStateFailure); 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fetcher_.reset(new ManifestFetcher(url)); 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // TODO(mlamouri,kenneth): this is not yet taking into account manifest-src 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // CSP rule, see http://crbug.com/409996. 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fetcher_->Start(render_frame()->GetWebFrame(), 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::Bind(&ManifestManager::OnManifestFetchComplete, 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::Unretained(this), 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt render_frame()->GetWebFrame()->document().url())); 114} 115 116void ManifestManager::OnManifestFetchComplete( 117 const GURL& document_url, 118 const blink::WebURLResponse& response, 119 const std::string& data) { 120 if (response.isNull() && data.empty()) { 121 ResolveCallbacks(ResolveStateFailure); 122 return; 123 } 124 125 manifest_ = ManifestParser::Parse(data, response.url(), document_url); 126 127 fetcher_.reset(); 128 ResolveCallbacks(ResolveStateSuccess); 129} 130 131void ManifestManager::ResolveCallbacks(ResolveState state) { 132 if (state == ResolveStateFailure) 133 manifest_ = Manifest(); 134 135 manifest_dirty_ = state != ResolveStateSuccess; 136 137 Manifest manifest = manifest_; 138 std::list<GetManifestCallback> callbacks = pending_callbacks_; 139 140 pending_callbacks_.clear(); 141 142 for (std::list<GetManifestCallback>::const_iterator it = callbacks.begin(); 143 it != callbacks.end(); ++it) { 144 it->Run(manifest); 145 } 146} 147 148} // namespace content 149