1 // Copyright (c) 2012 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/web_intents_host.h"
8 #include "base/bind_helpers.h"
9 #include "base/utf_string_conversions.h"
10 #include "content/common/intents_messages.h"
11 #include "content/public/renderer/v8_value_converter.h"
12 #include "content/renderer/render_view_impl.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBlob.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDeliveredIntentClient.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIntent.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIntentRequest.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFileSystem.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerializedScriptValue.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
26 #include "webkit/fileapi/file_system_util.h"
27 #include "webkit/glue/cpp_bound_class.h"
29 using WebKit::WebBindings
;
30 using WebKit::WebBlob
;
31 using WebKit::WebCString
;
32 using WebKit::WebDeliveredIntentClient
;
33 using WebKit::WebFrame
;
34 using WebKit::WebIntent
;
35 using WebKit::WebIntentRequest
;
36 using WebKit::WebString
;
37 using WebKit::WebSerializedScriptValue
;
38 using WebKit::WebVector
;
44 // Reads reply value, either from the data field, or the data_file field.
45 WebSerializedScriptValue
GetReplyValue(
46 const webkit_glue::WebIntentReply
& reply
) {
47 if (reply
.data_file_size
> -1) {
48 // TODO(smckay): seralize the blob value in the web intent script
49 // context. We simply don't know how to do this at this time.
50 // The following code kills the renderer when we call toV8Value.
51 // v8::HandleScope scope;
52 // v8::Local<v8::Context> ctx = ....which context?
53 // v8::Context::Scope cscope(ctx);
54 // WebKit::WebBlob blob = WebBlob::createFromFile(
55 // WebString::fromUTF8(reply.data_file.AsUTF8Unsafe()),
56 // reply.data_file_size);
57 // v8::Handle<v8::Value> value = blob.toV8Value();
58 // return WebSerializedScriptValue::serialize(value);
59 return WebSerializedScriptValue::fromString(
60 ASCIIToUTF16(reply
.data_file
.AsUTF8Unsafe()));
62 return WebSerializedScriptValue::fromString(reply
.data
);
68 class DeliveredIntentClientImpl
: public WebDeliveredIntentClient
{
70 explicit DeliveredIntentClientImpl(WebIntentsHost
* host
) : host_(host
) {}
71 virtual ~DeliveredIntentClientImpl() {}
73 virtual void postResult(const WebSerializedScriptValue
& data
) const {
74 host_
->OnResult(data
.toString());
77 virtual void postFailure(const WebSerializedScriptValue
& data
) const {
78 host_
->OnFailure(data
.toString());
81 virtual void destroy() OVERRIDE
{
85 WebIntentsHost
* host_
;
88 WebIntentsHost::WebIntentsHost(RenderViewImpl
* render_view
)
89 : RenderViewObserver(render_view
),
93 WebIntentsHost::~WebIntentsHost() {
96 int WebIntentsHost::RegisterWebIntent(
97 const WebIntentRequest
& request
) {
98 int id
= id_counter_
++;
99 intent_requests_
[id
] = request
;
103 bool WebIntentsHost::OnMessageReceived(const IPC::Message
& message
) {
105 IPC_BEGIN_MESSAGE_MAP(WebIntentsHost
, message
)
106 IPC_MESSAGE_HANDLER(IntentsMsg_SetWebIntentData
, OnSetIntent
)
107 IPC_MESSAGE_HANDLER(IntentsMsg_WebIntentReply
, OnWebIntentReply
);
108 IPC_MESSAGE_UNHANDLED(handled
= false)
109 IPC_END_MESSAGE_MAP()
113 void WebIntentsHost::OnSetIntent(const webkit_glue::WebIntentData
& intent
) {
114 intent_
.reset(new webkit_glue::WebIntentData(intent
));
117 void WebIntentsHost::OnWebIntentReply(
118 const webkit_glue::WebIntentReply
& reply
,
120 std::map
<int, WebIntentRequest
>::iterator request
=
121 intent_requests_
.find(intent_id
);
122 if (request
== intent_requests_
.end())
124 WebIntentRequest intent_request
= request
->second
;
125 intent_requests_
.erase(request
);
127 if (reply
.type
== webkit_glue::WEB_INTENT_REPLY_SUCCESS
) {
128 intent_request
.postResult(GetReplyValue(reply
));
130 intent_request
.postFailure(
131 WebSerializedScriptValue::fromString(reply
.data
));
135 void WebIntentsHost::OnResult(const WebKit::WebString
& data
) {
136 const webkit_glue::WebIntentReply
reply(
137 webkit_glue::WEB_INTENT_REPLY_SUCCESS
, data
);
138 Send(new IntentsHostMsg_WebIntentReply(routing_id(), reply
));
141 void WebIntentsHost::OnFailure(const WebKit::WebString
& data
) {
142 const webkit_glue::WebIntentReply
reply(
143 webkit_glue::WEB_INTENT_REPLY_FAILURE
, data
);
144 Send(new IntentsHostMsg_WebIntentReply(routing_id(), reply
));
147 // We set the intent payload into all top-level frame window objects. This
148 // should persist the data through redirects, and not deliver it to any
150 void WebIntentsHost::DidCreateScriptContext(WebKit::WebFrame
* frame
,
151 v8::Handle
<v8::Context
> ctx
,
154 if (intent_
.get() == NULL
|| frame
->top() != frame
)
157 if (ctx
!= frame
->mainWorldScriptContext())
160 if (!delivered_intent_client_
.get()) {
161 delivered_intent_client_
.reset(new DeliveredIntentClientImpl(this));
164 WebIntent web_intent
= CreateWebIntent(frame
, *intent_
);
166 if (!web_intent
.action().isEmpty())
167 frame
->deliverIntent(web_intent
, NULL
, delivered_intent_client_
.get());
170 WebIntent
WebIntentsHost::CreateWebIntent(
171 WebFrame
* frame
, const webkit_glue::WebIntentData
& intent_data
) {
172 // Must be called with v8 scope held.
173 DCHECK(v8::Context::InContext());
175 // TODO(gbillock): Remove this block when we get rid of |extras|.
176 WebVector
<WebString
> extras_keys(intent_data
.extra_data
.size());
177 WebVector
<WebString
> extras_values(intent_data
.extra_data
.size());
178 std::map
<string16
, string16
>::const_iterator iter
=
179 intent_data
.extra_data
.begin();
180 for (size_t i
= 0; iter
!= intent_data
.extra_data
.end(); ++i
, ++iter
) {
181 extras_keys
[i
] = iter
->first
;
182 extras_values
[i
] = iter
->second
;
185 switch (intent_data
.data_type
) {
186 case webkit_glue::WebIntentData::SERIALIZED
: {
187 return WebIntent::create(intent_data
.action
, intent_data
.type
,
189 extras_keys
, extras_values
);
192 case webkit_glue::WebIntentData::UNSERIALIZED
: {
193 v8::Local
<v8::String
> dataV8
= v8::String::New(
194 reinterpret_cast<const uint16_t*>(
195 intent_data
.unserialized_data
.data()),
196 static_cast<int>(intent_data
.unserialized_data
.length()));
197 WebSerializedScriptValue serialized_data
=
198 WebSerializedScriptValue::serialize(dataV8
);
200 return WebIntent::create(intent_data
.action
, intent_data
.type
,
201 serialized_data
.toString(),
202 extras_keys
, extras_values
);
205 case webkit_glue::WebIntentData::BLOB
: {
206 web_blob_
= WebBlob::createFromFile(
207 WebString::fromUTF8(intent_data
.blob_file
.AsUTF8Unsafe()),
208 intent_data
.blob_length
);
209 WebSerializedScriptValue serialized_data
=
210 WebSerializedScriptValue::serialize(web_blob_
.toV8Value());
211 return WebIntent::create(intent_data
.action
, intent_data
.type
,
212 serialized_data
.toString(),
213 extras_keys
, extras_values
);
216 case webkit_glue::WebIntentData::FILESYSTEM
: {
217 const GURL origin
= GURL(frame
->document().securityOrigin().toString());
218 const GURL root_url
=
219 fileapi::GetFileSystemRootURI(origin
,
220 fileapi::kFileSystemTypeIsolated
);
221 const std::string url
= base::StringPrintf(
223 root_url
.spec().c_str(),
224 intent_data
.filesystem_id
.c_str(),
225 intent_data
.root_name
.c_str());
226 // TODO(kmadhusu): This is a temporary hack to create a serializable file
227 // system. Once we have a better way to create a serializable file system,
229 v8::Handle
<v8::Value
> filesystem_V8
= frame
->createSerializableFileSystem(
230 WebKit::WebFileSystem::TypeIsolated
,
231 WebKit::WebString::fromUTF8(intent_data
.root_name
),
232 WebKit::WebString::fromUTF8(url
));
233 WebSerializedScriptValue serialized_data
=
234 WebSerializedScriptValue::serialize(filesystem_V8
);
235 return WebIntent::create(intent_data
.action
, intent_data
.type
,
236 serialized_data
.toString(),
237 extras_keys
, extras_values
);
240 case webkit_glue::WebIntentData::MIME_TYPE
: {
241 scoped_ptr
<V8ValueConverter
> converter(
242 V8ValueConverter::create());
243 v8::Handle
<v8::Value
> valV8
= converter
->ToV8Value(
244 &intent_data
.mime_data
, v8::Context::GetCurrent());
246 WebSerializedScriptValue serialized_data
=
247 WebSerializedScriptValue::serialize(valV8
);
248 return WebIntent::create(intent_data
.action
, intent_data
.type
,
249 serialized_data
.toString(),
250 WebVector
<WebString
>(), WebVector
<WebString
>());
258 } // namespace content