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 "base/base_paths.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/path_service.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "mojo/application/public/cpp/application_impl.h"
14 #include "mojo/application/public/cpp/application_test_base.h"
15 #include "mojo/common/data_pipe_utils.h"
16 #include "mojo/public/cpp/system/macros.h"
17 #include "mojo/runner/kPingable.h"
18 #include "mojo/runner/test/pingable.mojom.h"
19 #include "mojo/services/http_server/public/cpp/http_server_util.h"
20 #include "mojo/services/http_server/public/interfaces/http_server.mojom.h"
21 #include "mojo/services/http_server/public/interfaces/http_server_factory.mojom.h"
22 #include "mojo/services/network/public/interfaces/net_address.mojom.h"
27 std::string
GetURL(uint16_t port
, const std::string
& path
) {
28 return base::StringPrintf("http://127.0.0.1:%u/%s",
29 static_cast<unsigned>(port
), path
.c_str());
32 class GetHandler
: public http_server::HttpHandler
{
34 GetHandler(InterfaceRequest
<http_server::HttpHandler
> request
, uint16_t port
)
35 : binding_(this, request
.Pass()), port_(port
) {
37 ~GetHandler() override
{}
40 // http_server::HttpHandler:
42 http_server::HttpRequestPtr request
,
43 const Callback
<void(http_server::HttpResponsePtr
)>& callback
) override
{
44 http_server::HttpResponsePtr response
;
45 if (base::StartsWith(request
->relative_url
, "/app",
46 base::CompareCase::SENSITIVE
)) {
47 response
= http_server::CreateHttpResponse(
48 200, std::string(kPingable
.data
, kPingable
.size
));
49 response
->content_type
= "application/octet-stream";
50 } else if (request
->relative_url
== "/redirect") {
51 response
= http_server::HttpResponse::New();
52 response
->status_code
= 302;
53 response
->custom_headers
.insert("Location", GetURL(port_
, "app"));
58 callback
.Run(response
.Pass());
61 Binding
<http_server::HttpHandler
> binding_
;
64 MOJO_DISALLOW_COPY_AND_ASSIGN(GetHandler
);
67 typedef test::ApplicationTestBase ShellAppTest
;
69 class ShellHTTPAppTest
: public test::ApplicationTestBase
{
71 ShellHTTPAppTest() : ApplicationTestBase() {}
72 ~ShellHTTPAppTest() override
{}
75 // ApplicationTestBase:
76 void SetUp() override
{
77 ApplicationTestBase::SetUp();
79 application_impl()->ConnectToService("mojo:http_server",
80 &http_server_factory_
);
82 NetAddressPtr
local_address(NetAddress::New());
83 local_address
->family
= NET_ADDRESS_FAMILY_IPV4
;
84 local_address
->ipv4
= NetAddressIPv4::New();
85 local_address
->ipv4
->addr
.resize(4);
86 local_address
->ipv4
->addr
[0] = 127;
87 local_address
->ipv4
->addr
[1] = 0;
88 local_address
->ipv4
->addr
[2] = 0;
89 local_address
->ipv4
->addr
[3] = 1;
90 local_address
->ipv4
->port
= 0;
91 http_server_factory_
->CreateHttpServer(GetProxy(&http_server_
),
92 local_address
.Pass());
94 http_server_
->GetPort([this](uint16_t p
) { port_
= p
; });
95 EXPECT_TRUE(http_server_
.WaitForIncomingResponse());
97 InterfacePtr
<http_server::HttpHandler
> http_handler
;
98 handler_
.reset(new GetHandler(GetProxy(&http_handler
).Pass(), port_
));
99 http_server_
->SetHandler(".*", http_handler
.Pass(),
100 [](bool result
) { EXPECT_TRUE(result
); });
101 EXPECT_TRUE(http_server_
.WaitForIncomingResponse());
104 std::string
GetURL(const std::string
& path
) {
105 return ::mojo::GetURL(port_
, path
);
108 http_server::HttpServerFactoryPtr http_server_factory_
;
109 http_server::HttpServerPtr http_server_
;
110 scoped_ptr
<GetHandler
> handler_
;
114 MOJO_DISALLOW_COPY_AND_ASSIGN(ShellHTTPAppTest
);
117 // Test that we can load apps over http.
118 TEST_F(ShellHTTPAppTest
, Http
) {
119 InterfacePtr
<Pingable
> pingable
;
120 application_impl()->ConnectToService(GetURL("app"), &pingable
);
121 pingable
->Ping("hello",
122 [this](const String
& app_url
, const String
& connection_url
,
123 const String
& message
) {
124 EXPECT_EQ(GetURL("app"), app_url
);
125 EXPECT_EQ(GetURL("app"), connection_url
);
126 EXPECT_EQ("hello", message
);
127 base::MessageLoop::current()->Quit();
129 base::RunLoop().Run();
132 // Test that redirects work.
133 // TODO(aa): Test that apps receive the correct URL parameters.
134 TEST_F(ShellHTTPAppTest
, Redirect
) {
135 InterfacePtr
<Pingable
> pingable
;
136 application_impl()->ConnectToService(GetURL("redirect"), &pingable
);
137 pingable
->Ping("hello",
138 [this](const String
& app_url
, const String
& connection_url
,
139 const String
& message
) {
140 EXPECT_EQ(GetURL("app"), app_url
);
141 EXPECT_EQ(GetURL("app"), connection_url
);
142 EXPECT_EQ("hello", message
);
143 base::MessageLoop::current()->Quit();
145 base::RunLoop().Run();
148 // Test that querystring is not considered when resolving http applications.
149 // TODO(aa|qsr): Fix this test on Linux ASAN http://crbug.com/463662
150 #if defined(ADDRESS_SANITIZER)
151 #define MAYBE_QueryHandling DISABLED_QueryHandling
153 #define MAYBE_QueryHandling QueryHandling
154 #endif // ADDRESS_SANITIZER
155 TEST_F(ShellHTTPAppTest
, MAYBE_QueryHandling
) {
156 InterfacePtr
<Pingable
> pingable1
;
157 InterfacePtr
<Pingable
> pingable2
;
158 application_impl()->ConnectToService(GetURL("app?foo"), &pingable1
);
159 application_impl()->ConnectToService(GetURL("app?bar"), &pingable2
);
161 int num_responses
= 0;
162 auto callback
= [this, &num_responses
](const String
& app_url
,
163 const String
& connection_url
,
164 const String
& message
) {
165 EXPECT_EQ(GetURL("app"), app_url
);
166 EXPECT_EQ("hello", message
);
168 if (num_responses
== 1) {
169 EXPECT_EQ(GetURL("app?foo"), connection_url
);
170 } else if (num_responses
== 2) {
171 EXPECT_EQ(GetURL("app?bar"), connection_url
);
172 base::MessageLoop::current()->Quit();
177 pingable1
->Ping("hello", callback
);
178 pingable2
->Ping("hello", callback
);
179 base::RunLoop().Run();
182 // mojo: URLs can have querystrings too
183 TEST_F(ShellAppTest
, MojoURLQueryHandling
) {
184 InterfacePtr
<Pingable
> pingable
;
185 application_impl()->ConnectToService("mojo:pingable_app?foo", &pingable
);
186 auto callback
= [this](const String
& app_url
, const String
& connection_url
,
187 const String
& message
) {
188 EXPECT_TRUE(base::EndsWith(app_url
, "/pingable_app.mojo",
189 base::CompareCase::SENSITIVE
));
190 EXPECT_EQ(app_url
.To
<std::string
>() + "?foo", connection_url
);
191 EXPECT_EQ("hello", message
);
192 base::MessageLoop::current()->Quit();
194 pingable
->Ping("hello", callback
);
195 base::RunLoop().Run();