1 // Copyright 2015 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 "components/html_viewer/html_document_application_delegate.h"
8 #include "components/html_viewer/global_state.h"
9 #include "components/html_viewer/html_document.h"
10 #include "mojo/application/public/cpp/application_connection.h"
11 #include "mojo/application/public/cpp/application_delegate.h"
12 #include "mojo/application/public/cpp/connect.h"
14 namespace html_viewer
{
16 // ServiceConnectorQueue records all incoming service requests and processes
17 // them once PushRequestsTo() is called. This is useful if you need to delay
18 // processing incoming service requests.
19 class HTMLDocumentApplicationDelegate::ServiceConnectorQueue
20 : public mojo::ServiceConnector
{
22 ServiceConnectorQueue() {}
23 ~ServiceConnectorQueue() override
{}
25 void PushRequestsTo(mojo::ApplicationConnection
* connection
) {
26 ScopedVector
<Request
> requests
;
27 requests_
.swap(requests
);
28 for (Request
* request
: requests
) {
29 connection
->GetLocalServiceProvider()->ConnectToService(
30 request
->interface_name
, request
->handle
.Pass());
36 std::string interface_name
;
37 mojo::ScopedMessagePipeHandle handle
;
40 // mojo::ServiceConnector:
41 void ConnectToService(mojo::ApplicationConnection
* application_connection
,
42 const std::string
& interface_name
,
43 mojo::ScopedMessagePipeHandle handle
) override
{
44 scoped_ptr
<Request
> request(new Request
);
45 request
->interface_name
= interface_name
;
46 request
->handle
= handle
.Pass();
47 requests_
.push_back(request
.Pass());
50 ScopedVector
<Request
> requests_
;
52 DISALLOW_COPY_AND_ASSIGN(ServiceConnectorQueue
);
55 HTMLDocumentApplicationDelegate::HTMLDocumentApplicationDelegate(
56 mojo::InterfaceRequest
<mojo::Application
> request
,
57 mojo::URLResponsePtr response
,
58 GlobalState
* global_state
,
59 scoped_ptr
<mojo::AppRefCount
> parent_app_refcount
)
62 base::Bind(&HTMLDocumentApplicationDelegate::OnTerminate
,
63 base::Unretained(this))),
64 parent_app_refcount_(parent_app_refcount
.Pass()),
66 initial_response_(response
.Pass()),
67 global_state_(global_state
),
69 weak_factory_(this) {}
71 HTMLDocumentApplicationDelegate::~HTMLDocumentApplicationDelegate() {
72 // Deleting the documents is going to trigger a callback to
73 // OnHTMLDocumentDeleted() and remove from |documents_|. Copy the set so we
74 // don't have to worry about the set being modified out from under us.
75 std::set
<HTMLDocument
*> documents2(documents2_
);
76 for (HTMLDocument
* doc
: documents2
)
78 DCHECK(documents2_
.empty());
81 // Callback from the quit closure. We key off this rather than
82 // ApplicationDelegate::Quit() as we don't want to shut down the messageloop
83 // when we quit (the messageloop is shared among multiple
84 // HTMLDocumentApplicationDelegates).
85 void HTMLDocumentApplicationDelegate::OnTerminate() {
89 // ApplicationDelegate;
90 void HTMLDocumentApplicationDelegate::Initialize(mojo::ApplicationImpl
* app
) {
91 mojo::URLRequestPtr
request(mojo::URLRequest::New());
92 request
->url
= mojo::String::From("mojo:network_service");
93 scoped_ptr
<mojo::ApplicationConnection
> connection
=
94 app_
.ConnectToApplication(request
.Pass());
95 connection
->ConnectToService(&url_loader_factory_
);
98 bool HTMLDocumentApplicationDelegate::ConfigureIncomingConnection(
99 mojo::ApplicationConnection
* connection
) {
100 if (initial_response_
) {
101 OnResponseReceived(nullptr, mojo::URLLoaderPtr(), connection
, nullptr,
102 initial_response_
.Pass());
103 } else if (url_
== "about:blank") {
104 // This is a little unfortunate. At the browser side, when starting a new
105 // app for "about:blank", the application manager uses
106 // mojo::runner::AboutFetcher to construct a response for "about:blank".
107 // However, when an app for "about:blank" already exists, it is reused and
108 // we end up here. We cannot fetch the URL using mojo::URLLoader because it
109 // is not an actual Web resource.
110 // TODO(yzshen): find out a better approach.
111 mojo::URLResponsePtr
response(mojo::URLResponse::New());
112 response
->url
= url_
;
113 response
->status_code
= 200;
114 response
->mime_type
= "text/html";
115 OnResponseReceived(nullptr, mojo::URLLoaderPtr(), connection
, nullptr,
118 // HTMLDocument provides services, but is created asynchronously. Queue up
119 // requests until the HTMLDocument is created.
120 scoped_ptr
<ServiceConnectorQueue
> service_connector_queue(
121 new ServiceConnectorQueue
);
122 connection
->SetServiceConnector(service_connector_queue
.get());
124 mojo::URLLoaderPtr loader
;
125 url_loader_factory_
->CreateURLLoader(GetProxy(&loader
));
126 mojo::URLRequestPtr
request(mojo::URLRequest::New());
128 request
->auto_follow_redirects
= true;
130 // |loader| will be passed to the OnResponseReceived method through a
131 // callback. Because order of evaluation is undefined, a reference to the
132 // raw pointer is needed.
133 mojo::URLLoader
* raw_loader
= loader
.get();
134 // The app needs to stay alive while waiting for the response to be
136 scoped_ptr
<mojo::AppRefCount
> app_retainer(
137 app_
.app_lifetime_helper()->CreateAppRefCount());
140 base::Bind(&HTMLDocumentApplicationDelegate::OnResponseReceived
,
141 weak_factory_
.GetWeakPtr(), base::Passed(&app_retainer
),
142 base::Passed(&loader
), connection
,
143 base::Passed(&service_connector_queue
)));
148 void HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted2(
149 HTMLDocument
* document
) {
150 DCHECK(documents2_
.count(document
) > 0);
151 documents2_
.erase(document
);
154 void HTMLDocumentApplicationDelegate::OnResponseReceived(
155 scoped_ptr
<mojo::AppRefCount
> app_refcount
,
156 mojo::URLLoaderPtr loader
,
157 mojo::ApplicationConnection
* connection
,
158 scoped_ptr
<ServiceConnectorQueue
> connector_queue
,
159 mojo::URLResponsePtr response
) {
160 // HTMLDocument is destroyed when the hosting view is destroyed, or
161 // explicitly from our destructor.
162 HTMLDocument
* document
= new HTMLDocument(
163 &app_
, connection
, response
.Pass(), global_state_
,
164 base::Bind(&HTMLDocumentApplicationDelegate::OnHTMLDocumentDeleted2
,
165 base::Unretained(this)),
167 documents2_
.insert(document
);
169 if (connector_queue
) {
170 connector_queue
->PushRequestsTo(connection
);
171 connection
->SetServiceConnector(nullptr);
175 HTMLFrame
* HTMLDocumentApplicationDelegate::CreateHTMLFrame(
176 HTMLFrame::CreateParams
* params
) {
177 return new HTMLFrame(params
);
180 HTMLWidgetRootLocal
* HTMLDocumentApplicationDelegate::CreateHTMLWidgetRootLocal(
181 HTMLWidgetRootLocal::CreateParams
* params
) {
182 return new HTMLWidgetRootLocal(params
);
185 } // namespace html_viewer