1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/manifest/manifest_manager.h"
#include "base/bind.h"
#include "base/strings/nullable_string16.h"
#include "content/common/manifest_manager_messages.h"
#include "content/public/renderer/render_frame.h"
#include "content/renderer/fetchers/manifest_fetcher.h"
#include "content/renderer/manifest/manifest_parser.h"
#include "content/renderer/manifest/manifest_uma_util.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebConsoleMessage.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
namespace content {
ManifestManager::ManifestManager(RenderFrame* render_frame)
: RenderFrameObserver(render_frame),
may_have_manifest_(false),
manifest_dirty_(true) {
}
ManifestManager::~ManifestManager() {
if (fetcher_)
fetcher_->Cancel();
// Consumers in the browser process will not receive this message but they
// will be aware of the RenderFrame dying and should act on that. Consumers
// in the renderer process should be correctly notified.
ResolveCallbacks(ResolveStateFailure);
}
bool ManifestManager::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ManifestManager, message)
IPC_MESSAGE_HANDLER(ManifestManagerMsg_RequestManifest, OnRequestManifest)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void ManifestManager::OnRequestManifest(int request_id) {
GetManifest(base::Bind(&ManifestManager::OnRequestManifestComplete,
base::Unretained(this), request_id));
}
void ManifestManager::OnRequestManifestComplete(
int request_id, const Manifest& manifest) {
// When sent via IPC, the Manifest must follow certain security rules.
Manifest ipc_manifest = manifest;
ipc_manifest.name = base::NullableString16(
ipc_manifest.name.string().substr(0, Manifest::kMaxIPCStringLength),
ipc_manifest.name.is_null());
ipc_manifest.short_name = base::NullableString16(
ipc_manifest.short_name.string().substr(0,
Manifest::kMaxIPCStringLength),
ipc_manifest.short_name.is_null());
for (size_t i = 0; i < ipc_manifest.icons.size(); ++i) {
ipc_manifest.icons[i].type = base::NullableString16(
ipc_manifest.icons[i].type.string().substr(
0, Manifest::kMaxIPCStringLength),
ipc_manifest.icons[i].type.is_null());
}
ipc_manifest.gcm_sender_id = base::NullableString16(
ipc_manifest.gcm_sender_id.string().substr(
0, Manifest::kMaxIPCStringLength),
ipc_manifest.gcm_sender_id.is_null());
Send(new ManifestManagerHostMsg_RequestManifestResponse(
routing_id(), request_id, ipc_manifest));
}
void ManifestManager::GetManifest(const GetManifestCallback& callback) {
if (!may_have_manifest_) {
callback.Run(Manifest());
return;
}
if (!manifest_dirty_) {
callback.Run(manifest_);
return;
}
pending_callbacks_.push_back(callback);
// Just wait for the running call to be done if there are other callbacks.
if (pending_callbacks_.size() > 1)
return;
FetchManifest();
}
void ManifestManager::DidChangeManifest() {
may_have_manifest_ = true;
manifest_dirty_ = true;
}
void ManifestManager::FetchManifest() {
GURL url(render_frame()->GetWebFrame()->document().manifestURL());
if (url.is_empty()) {
ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_EMPTY_URL);
ResolveCallbacks(ResolveStateFailure);
return;
}
fetcher_.reset(new ManifestFetcher(url));
fetcher_->Start(render_frame()->GetWebFrame(),
base::Bind(&ManifestManager::OnManifestFetchComplete,
base::Unretained(this),
render_frame()->GetWebFrame()->document().url()));
}
void ManifestManager::OnManifestFetchComplete(
const GURL& document_url,
const blink::WebURLResponse& response,
const std::string& data) {
if (response.isNull() && data.empty()) {
ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_UNSPECIFIED_REASON);
ResolveCallbacks(ResolveStateFailure);
return;
}
ManifestUmaUtil::FetchSucceeded();
ManifestParser parser(data, response.url(), document_url);
parser.Parse();
fetcher_.reset();
for (const std::string& msg : parser.errors()) {
blink::WebConsoleMessage message;
message.level = blink::WebConsoleMessage::LevelError;
message.text = blink::WebString::fromUTF8(msg);
render_frame()->GetWebFrame()->addMessageToConsole(message);
}
// Having errors while parsing the manifest doesn't mean the manifest parsing
// failed. Some properties might have been ignored but some others kept.
if (parser.failed()) {
ResolveCallbacks(ResolveStateFailure);
return;
}
manifest_ = parser.manifest();
ResolveCallbacks(ResolveStateSuccess);
}
void ManifestManager::ResolveCallbacks(ResolveState state) {
if (state == ResolveStateFailure)
manifest_ = Manifest();
manifest_dirty_ = state != ResolveStateSuccess;
Manifest manifest = manifest_;
std::list<GetManifestCallback> callbacks = pending_callbacks_;
pending_callbacks_.clear();
for (std::list<GetManifestCallback>::const_iterator it = callbacks.begin();
it != callbacks.end(); ++it) {
it->Run(manifest);
}
}
} // namespace content
|